Skip to content

Commit

Permalink
Merge pull request #42 from dralley/master
Browse files Browse the repository at this point in the history
Iterating over Ini yields "Section" type instead of "SectionIter"  (2.0 - breaking change)
  • Loading branch information
FreeCX authored Nov 16, 2021
2 parents 2fea8cd + 8a8f179 commit 09d0e32
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 50 deletions.
128 changes: 89 additions & 39 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ini, Error> {
let mut result = Ini::new();
for (index, line) in string.lines().enumerate() {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -473,7 +474,7 @@ impl Ini {
.and_then(|x| x.split(sep).map(|s| s.trim().parse()).collect::<Result<Vec<T>, _>>().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
///
Expand All @@ -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: &section, 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
/// ```
Expand All @@ -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),
/// }
/// }
Expand All @@ -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");
/// }
/// }
Expand All @@ -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
Expand All @@ -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::Item> {
self.iter.next().map(|(name, section)| (name, SectionIter { document: &section, 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::Item> {
self.iter.next().map(|(name, section)| (name, SectionIterMut { iter: section.iter_mut() }))
self.iter.next()
}
}

type Section = OrderedHashMap<String, String>;
#[derive(Debug)]
pub struct Section {
inner: OrderedHashMap<String, String>
}

/// 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::Item> {
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::Item> {
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
Expand All @@ -636,28 +655,35 @@ impl<'a> SectionIter<'a> {
/// assert_eq!(value, Some(2));
/// }
/// ```
pub fn get<T>(&'a self, key: &str) -> Option<T>
pub fn get<'a, T>(&'a self, key: &str) -> Option<T>
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<String> {
self.inner.remove(key)
}

fn next(&mut self) -> Option<Self::Item> {
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::*;
Expand Down Expand Up @@ -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(())
}
}
11 changes: 0 additions & 11 deletions src/ordered_hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,6 @@ where
}
}

impl<K, V> IntoIterator for OrderedHashMap<K, V>
where
K: Eq + Hash,
{
type Item = (K, V);
type IntoIter = IntoIter<K, V>;

fn into_iter(self) -> Self::IntoIter {
IntoIter { base: self.base, keys_iterator: self.keys.into_iter() }
}
}

impl<K, V> FromIterator<(K, V)> for OrderedHashMap<K, V>
where
Expand Down

0 comments on commit 09d0e32

Please sign in to comment.