diff --git a/src/file/format/ini.rs b/src/file/format/ini.rs index 9295e60e..f7a25a5c 100644 --- a/src/file/format/ini.rs +++ b/src/file/format/ini.rs @@ -3,35 +3,46 @@ use std::error::Error; use ini::Ini; use crate::map::Map; -use crate::value::{Value, ValueKind}; +use crate::value::{Table, Value, ValueKind}; pub fn parse( uri: Option<&String>, text: &str, ) -> Result, Box> { - let mut map: Map = Map::new(); - let i = Ini::load_from_str(text)?; - for (sec, prop) in i.iter() { - match sec { - Some(sec) => { - let mut sec_map: Map = Map::new(); - for (k, v) in prop.iter() { - sec_map.insert( - k.to_owned(), - Value::new(uri, ValueKind::String(v.to_owned())), - ); - } - map.insert(sec.to_owned(), Value::new(uri, ValueKind::Table(sec_map))); - } - None => { - for (k, v) in prop.iter() { - map.insert( - k.to_owned(), - Value::new(uri, ValueKind::String(v.to_owned())), - ); - } - } - } + let value = from_ini(uri, Ini::load_from_str(text)?); + + match value.kind { + ValueKind::Table(map) => Ok(map), + + _ => Ok(Map::new()), } - Ok(map) +} + +fn from_ini( + uri: Option<&String>, + data: Ini, +) -> Value { + let mut map = Map::::new(); + + let mut sections: Map, Table> = data.into_iter().map(|(section, props)| { + let key = section; + let value = props.iter().map(|(k, v)| { + let key = k.to_owned(); + let value = Value::new(uri, ValueKind::String(v.to_owned())); + (key, value) + }).collect(); + (key, value) + }).collect(); + + // Hoist (optional) sectionless properties to the top-level, alongside sections: + map.extend(sections.remove(&None).unwrap_or_default()); + + // Wrap each section Table into Value for merging into `map`: + map.extend(sections.into_iter().map(|(k,v)| { + let key = k.unwrap_or_default().to_owned(); + let value = Value::new(uri, ValueKind::Table(v)); + (key , value) + })); + + Value::new(uri, ValueKind::Table(map)) }