edres_core 0.8.0

Internals for the edres crate.
Documentation
//! This module provides utilities for parsing TOML files
//! to generic `Value`s.

use toml::{self, Value as TomlValue};

use crate::{
    error::Error,
    options::ParseOptions,
    parsing,
    value::{Struct, Value},
};

/// Parse TOML source, producing a generic `Value`.
pub fn parse_source(source: &str, options: &ParseOptions) -> Result<Value, Error> {
    let raw_value: TomlValue = toml::from_str(source)?;
    parse_value(raw_value, options)
}

/// Parse a TOML value, producing a generic `Value`.
pub fn parse_value(raw_value: TomlValue, options: &ParseOptions) -> Result<Value, Error> {
    let mut result = parse_value_non_unified(raw_value, options)?;
    parsing::unify_value(&mut result)?;
    Ok(result)
}

/// Parse a TOML value, producing a generic `Value`.
///
/// This bypasses the unification step, which currently does
/// nothing anyway.
pub fn parse_value_non_unified(
    raw_value: TomlValue,
    options: &ParseOptions,
) -> Result<Value, Error> {
    Ok(match raw_value {
        TomlValue::Boolean(value) => Value::Bool(value),
        TomlValue::Integer(value) => {
            parsing::preferred_int(value as i128, options.default_int_size)
        }
        TomlValue::Float(value) => parsing::preferred_float(value, options.default_float_size),
        TomlValue::String(value) => Value::String(value),
        TomlValue::Datetime(value) => Value::String(value.to_string()),
        TomlValue::Array(values) => parsing::array_or_vec(
            values
                .into_iter()
                .map(|value| parse_value_non_unified(value, options))
                .collect::<Result<Vec<_>, _>>()?,
            options.max_array_size,
        ),
        TomlValue::Table(values) => Value::Struct(Struct(
            values
                .into_iter()
                .map(|(key, value)| {
                    parse_value_non_unified(value, options).map(|value| (key, value))
                })
                .collect::<Result<_, Error>>()?,
        )),
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    use pretty_assertions::assert_eq;

    #[test]
    fn value_conversion() {
        let toml_source = r#"
            [root_table]
            bool_field = true
            int_field = 1000
            float_field = 2.5
            string_field = "hello"
            datetime_field = 2022-12-22T22:22:22Z
            array_field = [1, 2, 3]
        "#;

        let expected = Value::Struct(Struct(
            [(
                "root_table".into(),
                Value::Struct(Struct(
                    [
                        ("bool_field".into(), Value::Bool(true)),
                        ("int_field".into(), Value::I64(1000)),
                        ("float_field".into(), Value::F64(2.5)),
                        ("string_field".into(), Value::String("hello".into())),
                        (
                            "datetime_field".into(),
                            Value::String("2022-12-22T22:22:22Z".into()),
                        ),
                        (
                            "array_field".into(),
                            Value::Vec(vec![Value::I64(1), Value::I64(2), Value::I64(3)]),
                        ),
                    ]
                    .into_iter()
                    .collect(),
                )),
            )]
            .into_iter()
            .collect(),
        ));

        let value: TomlValue = toml::from_str(toml_source).unwrap();
        let value = parse_value_non_unified(value, &Default::default()).unwrap();

        assert_eq!(value, expected);
    }
}