diff options
Diffstat (limited to 'src/file/format/json5.rs')
-rw-r--r-- | src/file/format/json5.rs | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/file/format/json5.rs b/src/file/format/json5.rs new file mode 100644 index 0000000..33a3135 --- /dev/null +++ b/src/file/format/json5.rs @@ -0,0 +1,66 @@ +use std::collections::HashMap; +use std::error::Error; + +use crate::error::{ConfigError, Unexpected}; +use crate::value::{Value, ValueKind}; + +#[derive(serde::Deserialize, Debug)] +#[serde(untagged)] +pub enum Val { + Null, + Boolean(bool), + Integer(i64), + Float(f64), + String(String), + Array(Vec<Val>), + Object(HashMap<String, Val>), +} + +pub fn parse( + uri: Option<&String>, + text: &str, +) -> Result<HashMap<String, Value>, Box<dyn Error + Send + Sync>> { + match json5_rs::from_str::<Val>(&text)? { + Val::String(ref value) => Err(Unexpected::Str(value.clone())), + Val::Integer(value) => Err(Unexpected::Integer(value)), + Val::Float(value) => Err(Unexpected::Float(value)), + Val::Boolean(value) => Err(Unexpected::Bool(value)), + Val::Array(_) => Err(Unexpected::Seq), + Val::Null => Err(Unexpected::Unit), + Val::Object(o) => match from_json5_value(uri, Val::Object(o)).kind { + ValueKind::Table(map) => Ok(map), + _ => Ok(HashMap::new()), + }, + } + .map_err(|err| ConfigError::invalid_root(uri, err)) + .map_err(|err| Box::new(err) as Box<dyn Error + Send + Sync>) +} + +fn from_json5_value(uri: Option<&String>, value: Val) -> Value { + let vk = match value { + Val::Null => ValueKind::Nil, + Val::String(v) => ValueKind::String(v), + Val::Integer(v) => ValueKind::Integer(v), + Val::Float(v) => ValueKind::Float(v), + Val::Boolean(v) => ValueKind::Boolean(v), + Val::Object(table) => { + let m = table + .into_iter() + .map(|(k, v)| (k, from_json5_value(uri, v))) + .collect(); + + ValueKind::Table(m) + } + + Val::Array(array) => { + let l = array + .into_iter() + .map(|v| from_json5_value(uri, v)) + .collect(); + + ValueKind::Array(l) + } + }; + + Value::new(uri, vk) +} |