    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66

    use std::error::Error;

    use crate::error::{ConfigError, Unexpected};
    use crate::map::Map;
    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<Self>),
        Object(Map<String, Self>),
    }

    pub fn parse(
        uri: Option<&String>,
        text: &str,
    ) -> Result<Map<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::I64(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(Map::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::I64(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)
    }