diff --git a/libimagentryfilter/src/builtin/header/version/eq.rs b/libimagentryfilter/src/builtin/header/version/eq.rs index ac805a68..1ca38f8b 100644 --- a/libimagentryfilter/src/builtin/header/version/eq.rs +++ b/libimagentryfilter/src/builtin/header/version/eq.rs @@ -21,6 +21,7 @@ use semver::Version; use toml::Value; use libimagstore::store::Entry; +use libimagstore::toml_ext::TomlValueExt; use filters::filter::Filter; diff --git a/libimagentryfilter/src/builtin/header/version/gt.rs b/libimagentryfilter/src/builtin/header/version/gt.rs index daded755..8e3873fb 100644 --- a/libimagentryfilter/src/builtin/header/version/gt.rs +++ b/libimagentryfilter/src/builtin/header/version/gt.rs @@ -21,6 +21,7 @@ use semver::Version; use toml::Value; use libimagstore::store::Entry; +use libimagstore::toml_ext::TomlValueExt; use filters::filter::Filter; diff --git a/libimagentryfilter/src/builtin/header/version/lt.rs b/libimagentryfilter/src/builtin/header/version/lt.rs index 02c35cd3..c475b436 100644 --- a/libimagentryfilter/src/builtin/header/version/lt.rs +++ b/libimagentryfilter/src/builtin/header/version/lt.rs @@ -21,6 +21,7 @@ use semver::Version; use toml::Value; use libimagstore::store::Entry; +use libimagstore::toml_ext::TomlValueExt; use filters::filter::Filter; diff --git a/libimagentrylink/src/external.rs b/libimagentrylink/src/external.rs index 4959428b..0d6aab08 100644 --- a/libimagentrylink/src/external.rs +++ b/libimagentrylink/src/external.rs @@ -38,6 +38,7 @@ use libimagstore::store::FileLockEntry; use libimagstore::store::Store; use libimagstore::storeid::StoreId; use libimagstore::storeid::IntoStoreId; +use libimagstore::toml_ext::TomlValueExt; use libimagutil::debug_result::*; use error::LinkError as LE; diff --git a/libimagentrylink/src/internal.rs b/libimagentrylink/src/internal.rs index 48f5d819..6a8e5b5c 100644 --- a/libimagentrylink/src/internal.rs +++ b/libimagentrylink/src/internal.rs @@ -21,6 +21,7 @@ use libimagstore::storeid::StoreId; use libimagstore::store::Entry; use libimagstore::store::EntryHeader; use libimagstore::store::Result as StoreResult; +use libimagstore::toml_ext::TomlValueExt; use libimagerror::into::IntoError; use error::LinkErrorKind as LEK; diff --git a/libimagnotes/src/note.rs b/libimagnotes/src/note.rs index 2397948c..2edf1d60 100644 --- a/libimagnotes/src/note.rs +++ b/libimagnotes/src/note.rs @@ -30,6 +30,7 @@ use libimagstore::storeid::StoreId; use libimagstore::storeid::StoreIdIterator; use libimagstore::store::FileLockEntry; use libimagstore::store::Store; +use libimagstore::toml_ext::TomlValueExt; use libimagentrytag::tag::{Tag, TagSlice}; use libimagentrytag::tagable::Tagable; use libimagentrytag::result::Result as TagResult; diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 0b39285a..1b307ba7 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -33,6 +33,7 @@ use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; use libimagstore::storeid::IntoStoreId; use libimagstore::store::Store; +use libimagstore::toml_ext::TomlValueExt; use libimagerror::into::IntoError; use toml::Value; diff --git a/libimagstore/src/lib.rs b/libimagstore/src/lib.rs index a696f7cc..a420b5f1 100644 --- a/libimagstore/src/lib.rs +++ b/libimagstore/src/lib.rs @@ -52,5 +52,5 @@ pub mod hook; pub mod store; mod configuration; mod file_abstraction; -mod toml_ext; +pub mod toml_ext; diff --git a/libimagstore/src/store.rs b/libimagstore/src/store.rs index de9988d9..f217ba59 100644 --- a/libimagstore/src/store.rs +++ b/libimagstore/src/store.rs @@ -23,7 +23,6 @@ use std::path::PathBuf; use std::result::Result as RResult; use std::sync::Arc; use std::sync::RwLock; -use std::collections::BTreeMap; use std::io::Read; use std::convert::From; use std::convert::Into; @@ -34,13 +33,12 @@ use std::fmt::Formatter; use std::fmt::Debug; use std::fmt::Error as FMTError; -use toml::{Table, Value}; +use toml::Value; use regex::Regex; use glob::glob; use walkdir::WalkDir; use walkdir::Iter as WalkDirIter; -use error::{ParserErrorKind, ParserError}; use error::{StoreError as SE, StoreErrorKind as SEK}; use error::MapErrInto; use storeid::{IntoStoreId, StoreId, StoreIdIterator}; @@ -960,176 +958,6 @@ impl<'a> Drop for FileLockEntry<'a> { /// `EntryContent` type pub type EntryContent = String; -/// `EntryHeader` -/// -/// This is basically a wrapper around `toml::Table` which provides convenience to the user of the -/// library. -#[derive(Debug, Clone, PartialEq)] -pub struct EntryHeader(Value); - -pub type EntryResult = RResult; - -/** - * Wrapper type around file header (TOML) object - */ -impl EntryHeader { - - pub fn new() -> EntryHeader { - EntryHeader(build_default_header()) - } - - pub fn header(&self) -> &Value { - &self.0 - } - - fn from_table(t: Table) -> EntryHeader { - EntryHeader(Value::Table(t)) - } - - pub fn parse(s: &str) -> EntryResult { - use toml::Parser; - - let mut parser = Parser::new(s); - parser.parse() - .ok_or(ParserErrorKind::TOMLParserErrors.into()) - .and_then(verify_header_consistency) - .map(EntryHeader::from_table) - } - - pub fn verify(&self) -> Result<()> { - match self.0 { - Value::Table(ref t) => verify_header(&t), - _ => Err(SE::new(SEK::HeaderTypeFailure, None)), - } - } - - #[inline] - pub fn insert_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result { - self.0.insert_with_sep(spec, sep, v) - } - - #[inline] - pub fn set_with_sep(&mut self, spec: &str, sep: char, v: Value) -> Result> { - self.0.set_with_sep(spec, sep, v) - } - - #[inline] - pub fn read_with_sep(&self, spec: &str, splitchr: char) -> Result> { - self.0.read_with_sep(spec, splitchr) - } - - #[inline] - pub fn delete_with_sep(&mut self, spec: &str, splitchr: char) -> Result> { - self.0.delete_with_sep(spec, splitchr) - } - - #[inline] - pub fn insert(&mut self, spec: &str, v: Value) -> Result { - self.0.insert(spec, v) - } - - #[inline] - pub fn set(&mut self, spec: &str, v: Value) -> Result> { - self.0.set(spec, v) - } - - #[inline] - pub fn read(&self, spec: &str) -> Result> { - self.0.read(spec) - } - - #[inline] - pub fn delete(&mut self, spec: &str) -> Result> { - self.0.delete(spec) - } - -} - -impl Into for EntryHeader { - - fn into(self) -> Table { - match self.0 { - Value::Table(t) => t, - _ => panic!("EntryHeader is not a table!"), - } - } - -} - -impl From
for EntryHeader { - - fn from(t: Table) -> EntryHeader { - EntryHeader(Value::Table(t)) - } - -} - -fn build_default_header() -> Value { // BTreeMap - let mut m = BTreeMap::new(); - - m.insert(String::from("imag"), { - let mut imag_map = BTreeMap::::new(); - - imag_map.insert(String::from("version"), Value::String(String::from(version!()))); - imag_map.insert(String::from("links"), Value::Array(vec![])); - - Value::Table(imag_map) - }); - - Value::Table(m) -} -fn verify_header(t: &Table) -> Result<()> { - if !has_main_section(t) { - Err(SE::from(ParserErrorKind::MissingMainSection.into_error())) - } else if !has_imag_version_in_main_section(t) { - Err(SE::from(ParserErrorKind::MissingVersionInfo.into_error())) - } else if !has_only_tables(t) { - debug!("Could not verify that it only has tables in its base table"); - Err(SE::from(ParserErrorKind::NonTableInBaseTable.into_error())) - } else { - Ok(()) - } -} - -fn verify_header_consistency(t: Table) -> EntryResult
{ - verify_header(&t) - .map_err(Box::new) - .map_err(|e| ParserErrorKind::HeaderInconsistency.into_error_with_cause(e)) - .map(|_| t) -} - -fn has_only_tables(t: &Table) -> bool { - debug!("Verifying that table has only tables"); - t.iter().all(|(_, x)| if let Value::Table(_) = *x { true } else { false }) -} - -fn has_main_section(t: &Table) -> bool { - t.contains_key("imag") && - match t.get("imag") { - Some(&Value::Table(_)) => true, - Some(_) => false, - None => false, - } -} - -fn has_imag_version_in_main_section(t: &Table) -> bool { - use semver::Version; - - match *t.get("imag").unwrap() { - Value::Table(ref sec) => { - sec.get("version") - .and_then(|v| { - match *v { - Value::String(ref s) => Some(Version::parse(&s[..]).is_ok()), - _ => Some(false), - } - }) - .unwrap_or(false) - } - _ => false, - } -} - /** * An Entry of the store * @@ -1138,7 +966,7 @@ fn has_imag_version_in_main_section(t: &Table) -> bool { #[derive(Debug, Clone)] pub struct Entry { location: StoreId, - header: EntryHeader, + header: Value, content: EntryContent, } @@ -1147,11 +975,15 @@ impl Entry { pub fn new(loc: StoreId) -> Entry { Entry { location: loc, - header: EntryHeader::new(), + header: Entry::default_header(), content: EntryContent::new() } } + pub fn default_header() -> Value { // BTreeMap + Value::default_header() + } + pub fn from_reader(loc: S, file: &mut Read) -> Result { let text = { let mut s = String::new(); @@ -1187,14 +1019,14 @@ impl Entry { debug!("Header and content found. Yay! Building Entry object now"); Ok(Entry { location: try!(loc.into_storeid()), - header: try!(EntryHeader::parse(header.as_str())), + header: try!(Value::parse(header.as_str())), content: String::from(content), }) } pub fn to_str(&self) -> String { format!("---\n{header}---\n{content}", - header = ::toml::encode_str(&self.header.0), + header = ::toml::encode_str(&self.header), content = self.content) } @@ -1202,11 +1034,11 @@ impl Entry { &self.location } - pub fn get_header(&self) -> &EntryHeader { + pub fn get_header(&self) -> &Value { &self.header } - pub fn get_header_mut(&mut self) -> &mut EntryHeader { + pub fn get_header_mut(&mut self) -> &mut Value { &mut self.header } @@ -1378,7 +1210,7 @@ mod test { #[test] fn test_verification_good() { - use super::verify_header_consistency; + use toml_ext::verify_header_consistency; let mut header = BTreeMap::new(); let sub = { @@ -1395,7 +1227,7 @@ mod test { #[test] fn test_verification_invalid_versionstring() { - use super::verify_header_consistency; + use toml_ext::verify_header_consistency; let mut header = BTreeMap::new(); let sub = { @@ -1413,7 +1245,7 @@ mod test { #[test] fn test_verification_current_version() { - use super::verify_header_consistency; + use toml_ext::verify_header_consistency; let mut header = BTreeMap::new(); let sub = { diff --git a/libimagstore/src/toml_ext.rs b/libimagstore/src/toml_ext.rs index c0bd79b2..23be2a59 100644 --- a/libimagstore/src/toml_ext.rs +++ b/libimagstore/src/toml_ext.rs @@ -17,10 +17,15 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -use toml::Value; +use std::result::Result as RResult; +use std::collections::BTreeMap; + +use toml::{Table, Value}; use store::Result; +use error::StoreError as SE; use error::StoreErrorKind as SEK; +use error::{ParserErrorKind, ParserError}; use libimagerror::into::IntoError; pub trait TomlValueExt { @@ -353,10 +358,109 @@ impl Extract for Value { } } +pub type EntryResult = RResult; + +/// Extension trait for top-level toml::Value::Table, will only yield correct results on the +/// top-level Value::Table, but not on intermediate tables. +pub trait Header { + fn verify(&self) -> Result<()>; + fn parse(s: &str) -> EntryResult; + fn default_header() -> Value; +} + +impl Header for Value { + + fn verify(&self) -> Result<()> { + match *self { + Value::Table(ref t) => verify_header(&t), + _ => Err(SE::new(SEK::HeaderTypeFailure, None)), + } + } + + fn parse(s: &str) -> EntryResult { + use toml::Parser; + + let mut parser = Parser::new(s); + parser.parse() + .ok_or(ParserErrorKind::TOMLParserErrors.into()) + .and_then(verify_header_consistency) + .map(Value::Table) + } + + fn default_header() -> Value { + let mut m = BTreeMap::new(); + + m.insert(String::from("imag"), { + let mut imag_map = BTreeMap::::new(); + + imag_map.insert(String::from("version"), Value::String(String::from(version!()))); + imag_map.insert(String::from("links"), Value::Array(vec![])); + + Value::Table(imag_map) + }); + + Value::Table(m) + } + +} + +pub fn verify_header_consistency(t: Table) -> EntryResult
{ + verify_header(&t) + .map_err(Box::new) + .map_err(|e| ParserErrorKind::HeaderInconsistency.into_error_with_cause(e)) + .map(|_| t) +} + +fn verify_header(t: &Table) -> Result<()> { + if !has_main_section(t) { + Err(SE::from(ParserErrorKind::MissingMainSection.into_error())) + } else if !has_imag_version_in_main_section(t) { + Err(SE::from(ParserErrorKind::MissingVersionInfo.into_error())) + } else if !has_only_tables(t) { + debug!("Could not verify that it only has tables in its base table"); + Err(SE::from(ParserErrorKind::NonTableInBaseTable.into_error())) + } else { + Ok(()) + } +} + +fn has_only_tables(t: &Table) -> bool { + debug!("Verifying that table has only tables"); + t.iter().all(|(_, x)| if let Value::Table(_) = *x { true } else { false }) +} + +fn has_main_section(t: &Table) -> bool { + t.contains_key("imag") && + match t.get("imag") { + Some(&Value::Table(_)) => true, + Some(_) => false, + None => false, + } +} + +fn has_imag_version_in_main_section(t: &Table) -> bool { + use semver::Version; + + match *t.get("imag").unwrap() { + Value::Table(ref sec) => { + sec.get("version") + .and_then(|v| { + match *v { + Value::String(ref s) => Some(Version::parse(&s[..]).is_ok()), + _ => Some(false), + } + }) + .unwrap_or(false) + } + _ => false, + } +} + + #[cfg(test)] mod test { extern crate env_logger; - use store::EntryHeader; + use super::TomlValueExt; use super::{tokenize, walk_header}; use super::Token; @@ -619,11 +723,7 @@ mod test { #[test] fn test_header_read() { - let v = create_header(); - let h = match v { - Value::Table(t) => EntryHeader::from(t), - _ => panic!("create_header() doesn't return a table!"), - }; + let h = create_header(); assert!(if let Ok(Some(Value::Table(_))) = h.read("a") { true } else { false }); assert!(if let Ok(Some(Value::Array(_))) = h.read("a.array") { true } else { false }); @@ -656,11 +756,7 @@ mod test { #[test] fn test_header_set_override() { let _ = env_logger::init(); - let v = create_header(); - let mut h = match v { - Value::Table(t) => EntryHeader::from(t), - _ => panic!("create_header() doesn't return a table!"), - }; + let mut h = create_header(); println!("Testing index 0"); assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(0)); @@ -686,11 +782,7 @@ mod test { #[test] fn test_header_set_new() { let _ = env_logger::init(); - let v = create_header(); - let mut h = match v { - Value::Table(t) => EntryHeader::from(t), - _ => panic!("create_header() doesn't return a table!"), - }; + let mut h = create_header(); assert!(h.read("a.foo").is_ok()); assert!(h.read("a.foo").unwrap().is_none()); @@ -727,11 +819,7 @@ mod test { #[test] fn test_header_insert_override() { let _ = env_logger::init(); - let v = create_header(); - let mut h = match v { - Value::Table(t) => EntryHeader::from(t), - _ => panic!("create_header() doesn't return a table!"), - }; + let mut h = create_header(); println!("Testing index 0"); assert_eq!(h.read("a.array.0").unwrap().unwrap(), Value::Integer(0)); @@ -756,11 +844,7 @@ mod test { #[test] fn test_header_insert_new() { let _ = env_logger::init(); - let v = create_header(); - let mut h = match v { - Value::Table(t) => EntryHeader::from(t), - _ => panic!("create_header() doesn't return a table!"), - }; + let mut h = create_header(); assert!(h.read("a.foo").is_ok()); assert!(h.read("a.foo").unwrap().is_none()); @@ -796,11 +880,7 @@ mod test { #[test] fn test_header_delete() { let _ = env_logger::init(); - let v = create_header(); - let mut h = match v { - Value::Table(t) => EntryHeader::from(t), - _ => panic!("create_header() doesn't return a table!"), - }; + let mut h = create_header(); assert!(if let Ok(Some(Value::Table(_))) = h.read("a") { true } else { false }); assert!(if let Ok(Some(Value::Array(_))) = h.read("a.array") { true } else { false }); @@ -815,3 +895,4 @@ mod test { } } +