diff --git a/Cargo.lock b/Cargo.lock index 0ea6483a..bc8ed48b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,8 @@ dependencies = [ "log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "rustty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "term_grid 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -173,6 +175,23 @@ dependencies = [ "term 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 58109d21..02766913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,9 @@ config = "0.1.2" chrono = "0.2.16" +serde = "0.6.1" +serde_json = "0.6.0" + clap = { version = "1.4.5", features = ["yaml"] } rustty = "0.1.9" term = "0.2.12" diff --git a/src/main.rs b/src/main.rs index 70e0ce03..fd57f95e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ #[macro_use] extern crate clap; #[macro_use] extern crate log; +#[macro_use] extern crate serde; +#[macro_use] extern crate serde_json; extern crate config; extern crate regex; diff --git a/src/storage/file.rs b/src/storage/file.rs index 0270f5ea..008b2d9c 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -175,10 +175,10 @@ pub struct File { id : String } -impl File { +impl<'a, D: FileData> File { fn new(prs: &Parser, path: &String) -> Result, ParserError> - where HP: FileHeaderParser, + where HP: FileHeaderParser<'a>, DP: FileDataParser, { File::::read_file(path).and_then(|p| prs.read(p)) diff --git a/src/storage/json/mod.rs b/src/storage/json/mod.rs new file mode 100644 index 00000000..67c567fa --- /dev/null +++ b/src/storage/json/mod.rs @@ -0,0 +1 @@ +pub mod parser; diff --git a/src/storage/json/parser.rs b/src/storage/json/parser.rs new file mode 100644 index 00000000..a033cdf3 --- /dev/null +++ b/src/storage/json/parser.rs @@ -0,0 +1,103 @@ +use serde_json::{Value, from_str}; +use serde_json::error::Result as R; +use serde_json::Serializer; +use serde::ser::Serialize; +use serde::ser::Serializer as Ser; + +use std::collections::HashMap; +use std::io::stdout; + +use super::super::parser::{FileHeaderParser, ParserError}; +use super::super::file::{FileHeaderSpec, FileHeaderData}; + + +struct JsonHeaderParser<'a> { + spec: &'a FileHeaderSpec, +} + +impl<'a> FileHeaderParser<'a> for JsonHeaderParser<'a> { + + fn new(spec: &'a FileHeaderSpec) -> JsonHeaderParser<'a> { + JsonHeaderParser { + spec: spec + } + } + + fn read(&self, string: Option) + -> Result + { + if (string.is_some()) { + let s = string.unwrap(); + debug!("Deserializing: {}", s); + let fromstr : R = from_str(&s[..]); + if let Ok(content) = fromstr { + Ok(visit_json(&content)) + } else { + Err(ParserError::short("Unknown JSON parser error", s.clone(), 0)) + } + } else { + Ok(FileHeaderData::Null) + } + } + + fn write(&self, data: &FileHeaderData) -> Result { + let mut ser = Serializer::pretty(stdout()); + data.serialize(&mut ser); + Ok(String::from("")) + } + +} + +// TODO: This function must be able to return a parser error +fn visit_json(v: &Value) -> FileHeaderData { + match v { + &Value::Null => FileHeaderData::Null, + &Value::Bool(b) => FileHeaderData::Bool(b), + &Value::I64(i) => FileHeaderData::Integer(i), + &Value::U64(u) => FileHeaderData::UInteger(u), + &Value::F64(f) => FileHeaderData::Float(f), + &Value::String(ref s) => FileHeaderData::Text(s.clone()), + &Value::Array(ref vec) => { + FileHeaderData::Array { + values: Box::new(vec.clone().into_iter().map(|i| visit_json(v)).collect()) + } + }, + &Value::Object(ref btree) => { + FileHeaderData::Map{ + keys: btree.clone().iter().map(|(k, v)| + FileHeaderData::Key { + name: k.clone(), + value: Box::new(visit_json(v)), + } + ).collect() + } + } + } +} + +impl Serialize for FileHeaderData { + + fn serialize(&self, ser: &mut S) -> Result<(), S::Error> + where S: Ser + { + match self { + &FileHeaderData::Null => { + let o : Option = None; + o.serialize(ser) + }, + &FileHeaderData::Bool(ref b) => b.serialize(ser), + &FileHeaderData::Integer(ref i) => i.serialize(ser), + &FileHeaderData::UInteger(ref u) => u.serialize(ser), + &FileHeaderData::Float(ref f) => f.serialize(ser), + &FileHeaderData::Text(ref s) => (&s[..]).serialize(ser), + &FileHeaderData::Array{values: ref vs} => vs.serialize(ser), + &FileHeaderData::Map{keys: ref ks} => ks.serialize(ser), + &FileHeaderData::Key{name: ref n, value: ref v} => { + let mut hm = HashMap::new(); + hm.insert(n, v); + hm.serialize(ser) + } + } + } + +} diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 5a17befe..252f6001 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -7,3 +7,5 @@ pub use runtime::Runtime; pub mod file; pub mod parser; +pub mod json; + diff --git a/src/storage/parser.rs b/src/storage/parser.rs index ae6198a3..8013ef97 100644 --- a/src/storage/parser.rs +++ b/src/storage/parser.rs @@ -13,7 +13,7 @@ pub struct ParserError { } impl ParserError { - fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError { + pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError { ParserError { summary: String::from(sum), parsertext: text, @@ -22,7 +22,7 @@ impl ParserError { } } - fn short(sum: &'static str, text: String, idx: i32) -> ParserError { + pub fn short(sum: &'static str, text: String, idx: i32) -> ParserError { ParserError { summary: String::from(sum), parsertext: text, @@ -74,8 +74,8 @@ impl Display for ParserError { } -pub trait FileHeaderParser : Sized { - fn new(spec: &FileHeaderSpec) -> Self; +pub trait FileHeaderParser<'a> : Sized { + fn new(spec: &'a FileHeaderSpec) -> Self; fn read(&self, string: Option) -> Result; fn write(&self, data: &FileHeaderData) -> Result; } @@ -94,8 +94,8 @@ pub struct Parser datap : DP, } -impl Parser where - HP: FileHeaderParser, +impl<'a, HP, DP> Parser where + HP: FileHeaderParser<'a>, { fn new(headerp: HP, datap: DP) -> Parser {