diff --git a/src/lib.rs b/src/lib.rs index 0ec0dd9..46ed1d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,7 +68,7 @@ impl Ini { Ini { document: OrderedHashMap::new(), last_section_name: String::new(), empty_section: Section::new() } } - /// Private construct method which creaate [Ini] struct from input string + /// Private construct method which create [Ini] struct from input string fn parse(string: &str) -> Result { let mut result = Ini::new(); for (index, line) in string.lines().enumerate() { @@ -251,6 +251,7 @@ impl Ini { self.document .entry(self.last_section_name.clone()) .or_insert_with(Section::new) + .inner .insert(name.into(), value.to_string()); self } @@ -405,7 +406,7 @@ impl Ini { /// Private method which get value by `key` from `section` fn get_raw(&self, section: &str, key: &str) -> Option<&String> { - self.document.get(section).and_then(|s| s.get(key)) + self.document.get(section).and_then(|s| s.get_raw(key)) } /// Get scalar value of key in section. @@ -473,7 +474,7 @@ impl Ini { .and_then(|x| x.split(sep).map(|s| s.trim().parse()).collect::, _>>().ok()) } - /// An iterator visiting all key-value pairs in order of appearance in section. + /// An iterator visiting all key-value pairs of a section in order of appearance. /// /// If section with given name doesn't exist in document, method returns empty iterator /// @@ -492,13 +493,11 @@ impl Ini { /// assert_eq!(conf.section_iter("absent").count(), 0); /// ``` pub fn section_iter(&self, section: &str) -> SectionIter { - let section = self.document.get(section).unwrap_or(&self.empty_section); - SectionIter { document: §ion, iter: section.iter() } + self.document.get(section).unwrap_or(&self.empty_section).iter() } - /// Iterate over all sections in order of appearance, yielding pairs of - /// section name and iterator over the section elements. The iterator - /// element type is `(&'a String, SectionIter<'a>)`. + /// Iterate over all sections in order of appearance, yielding pairs of section name + /// and section instance, which can be iterated over or queried similarly to Ini instances. /// /// # Example /// ``` @@ -509,10 +508,10 @@ impl Ini { /// .section("bar") /// .item("one", "1"); /// - /// for (name, section_iter) in conf.iter() { + /// for (name, section) in conf.iter() { /// match name.as_str() { - /// "foo" => assert_eq!(section_iter.count(), 2), - /// "bar" => assert_eq!(section_iter.count(), 1), + /// "foo" => assert_eq!(section.iter().count(), 2), + /// "bar" => assert_eq!(section.iter().count(), 1), /// _ => assert!(false), /// } /// } @@ -533,14 +532,14 @@ impl Ini { /// .section("bar") /// .item("one", "1"); /// - /// for (name, section_iter) in conf.iter_mut() { - /// for (key, val) in section_iter { + /// for (name, section) in conf.iter_mut() { + /// for (key, val) in section.iter_mut() { /// *val = String::from("replaced"); /// } /// } /// - /// for (name, section_iter) in conf.iter() { - /// for (key, val) in section_iter { + /// for (name, section) in conf.iter() { + /// for (key, val) in section.iter() { /// assert_eq!(val.as_str(), "replaced"); /// } /// } @@ -556,7 +555,7 @@ impl fmt::Display for Ini { // insert section block items.push(format!("[{}]", name)); // add items - for (key, value) in section { + for (key, value) in section.iter() { items.push(format!("{} = {}", key, value)); } // and blank line between sections @@ -572,54 +571,74 @@ impl Default for Ini { } } -/// An iterator over the sections of an ini documet +/// An iterator over the sections of an ini document pub struct IniIter<'a> { #[doc(hidden)] iter: ordered_hashmap::Iter<'a, String, Section>, } impl<'a> Iterator for IniIter<'a> { - type Item = (&'a String, SectionIter<'a>); + type Item = (&'a String, &'a Section); #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(name, section)| (name, SectionIter { document: §ion, iter: section.iter() })) + self.iter.next() } } -/// A mutable iterator over the sections of an ini documet +/// A mutable iterator over the sections of an ini document pub struct IniIterMut<'a> { #[doc(hidden)] iter: ordered_hashmap::IterMut<'a, String, Section>, } impl<'a> Iterator for IniIterMut<'a> { - type Item = (&'a String, SectionIterMut<'a>); + type Item = (&'a String, &'a mut Section); #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(name, section)| (name, SectionIterMut { iter: section.iter_mut() })) + self.iter.next() } } -type Section = OrderedHashMap; +#[derive(Debug)] +pub struct Section { + inner: OrderedHashMap +} -/// An iterator over the entries of a section pub struct SectionIter<'a> { #[doc(hidden)] - document: &'a Section, iter: ordered_hashmap::Iter<'a, String, String>, } impl<'a> Iterator for SectionIter<'a> { type Item = (&'a String, &'a String); + #[inline] fn next(&mut self) -> Option { self.iter.next() } } -impl<'a> SectionIter<'a> { +pub struct SectionIterMut<'a> { + #[doc(hidden)] + iter: ordered_hashmap::IterMut<'a, String, String>, +} + +impl<'a> Iterator for SectionIterMut<'a> { + type Item = (&'a String, &'a mut String); + + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl Section { + pub fn new() -> Self { + Section { inner: OrderedHashMap::new() } + } + /// Get scalar value of key /// /// - output type `T` must implement [FromStr] trait for auto conversion @@ -636,28 +655,35 @@ impl<'a> SectionIter<'a> { /// assert_eq!(value, Some(2)); /// } /// ``` - pub fn get(&'a self, key: &str) -> Option + pub fn get<'a, T>(&'a self, key: &str) -> Option where - T: FromStr, + T: FromStr { - self.document.get(key).and_then(|x| x.parse().ok()) + self.inner.get(key).and_then(|x| x.parse().ok()) } -} -/// A mutable iterator over the entries of a section -pub struct SectionIterMut<'a> { - #[doc(hidden)] - iter: ordered_hashmap::IterMut<'a, String, String>, -} + pub fn get_raw<'a>(&'a self, key: &str) -> Option<&String> { + self.inner.get(key) + } -impl<'a> Iterator for SectionIterMut<'a> { - type Item = (&'a String, &'a mut String); + pub fn remove(&mut self, key: &str) -> Option { + self.inner.remove(key) + } - fn next(&mut self) -> Option { - self.iter.next() + pub fn insert(&mut self, key: String, value: String) { + self.inner.insert(key, value); + } + + pub fn iter(&self) -> SectionIter { + SectionIter { iter: self.inner.iter() } + } + + pub fn iter_mut(&mut self) -> SectionIterMut { + SectionIterMut { iter: self.inner.iter_mut() } } } + #[cfg(test)] mod library_test { use super::*; @@ -748,4 +774,28 @@ mod library_test { assert_eq!(["c", "b", "a"], keys[..]); Ok(()) } + + #[test] + fn random_access_section() -> Result<(), Error> { + let ini = Ini::from_string("[a]\nc = 1\nb = 2\na = 3\n\n[b]\na = 1\nb = 2\nc = 3\n\n[c]\na=0\nd=4")?; + for (name, section) in ini.iter() { + match name.as_str() { + "a" => { + assert_eq!(section.get_raw("a"), Some(&"3".to_owned())); + assert_eq!(section.get_raw("d"), None); + }, + "b" => { + assert_eq!(section.get_raw("a"), Some(&"1".to_owned())); + assert_eq!(section.get_raw("d"), None); + }, + "c" => { + assert_eq!(section.get_raw("a"), Some(&"0".to_owned())); + assert_eq!(section.get_raw("b"), None); + assert_eq!(section.get_raw("d"), Some(&"4".to_owned())); + }, + _ => unreachable!() + } + } + Ok(()) + } } diff --git a/src/ordered_hashmap.rs b/src/ordered_hashmap.rs index 6123e61..4b22549 100644 --- a/src/ordered_hashmap.rs +++ b/src/ordered_hashmap.rs @@ -250,17 +250,6 @@ where } } -impl IntoIterator for OrderedHashMap -where - K: Eq + Hash, -{ - type Item = (K, V); - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { base: self.base, keys_iterator: self.keys.into_iter() } - } -} impl FromIterator<(K, V)> for OrderedHashMap where