ronf 0.4.2

Configuration system with saving
Documentation
use crate::value::{Map, Value};

pub(crate) fn deserialize(content: String) -> Result<Map<String, Value>, String> {
    let table = content.parse::<toml::Table>().map_err(|e| e.to_string())?;
    let mut map = Map::new();
    for (key, value) in table {
        map.insert(key, from_toml_value(&value));
    }
    Ok(map)
}

fn from_toml_value(value: &toml::Value) -> Value {
    match value {
        toml::Value::String(s) => Value::String(s.clone()),
        toml::Value::Integer(i) => Value::Int(*i),
        toml::Value::Float(f) => Value::Float(*f),
        toml::Value::Boolean(b) => Value::Bool(*b),
        toml::Value::Datetime(dt) => Value::String(dt.to_string()),
        toml::Value::Array(arr) => {
            let mut values = Vec::new();
            for item in arr {
                values.push(from_toml_value(item));
            }
            Value::Array(values)
        }
        toml::Value::Table(table) => {
            let mut map = Map::new();
            for (key, value) in table {
                map.insert(key.clone(), from_toml_value(value));
            }
            Value::Table(map)
        }
    }
}

pub(crate) fn serialize(value: Map<String, Value>) -> String {
    let mut table = toml::Table::new();
    for (key, value) in value {
        table.insert(key, to_toml_value(value));
    }
    toml::to_string(&table).unwrap()
}

fn to_toml_value(value: Value) -> toml::Value {
    match value {
        Value::String(s) => toml::Value::String(s),
        Value::Int(i) => toml::Value::Integer(i),
        Value::Float(f) => toml::Value::Float(f),
        Value::Bool(b) => toml::Value::Boolean(b),
        Value::Array(arr) => {
            let mut values = Vec::new();
            for item in arr {
                values.push(to_toml_value(item));
            }
            toml::Value::Array(values)
        }
        Value::Table(table) => {
            let mut toml_table = toml::Table::new();
            for (key, value) in table {
                toml_table.insert(key, to_toml_value(value));
            }
            toml::Value::Table(toml_table)
        }
        _ => panic!("Unsupported value type for TOML serialization"),
    }
}

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

    #[test]
    fn test_invalid() {
        let toml_content = r#"[section"#;
        let result = deserialize(toml_content.to_string());
        assert!(result.is_err());
    }

    #[test]
    fn test_deserialize() {
        let toml_content = r#"
            key = "value"
            int_key = 42
            float_key = 3.1
            bool_key = true
            array_key = [1, 2, 3]
            table_key = { nested_key = "nested_value" }
            "#;
        let parsed_map = deserialize(toml_content.to_string()).unwrap();
        assert_eq!(
            parsed_map.get("key").unwrap(),
            &Value::String("value".to_string())
        );
        assert_eq!(parsed_map.get("int_key").unwrap(), &Value::Int(42));
        assert_eq!(parsed_map.get("float_key").unwrap(), &Value::Float(3.1));
        assert_eq!(parsed_map.get("bool_key").unwrap(), &Value::Bool(true));
        assert_eq!(
            parsed_map.get("array_key").unwrap(),
            &Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)])
        );
        let table = parsed_map.get("table_key").unwrap();
        assert_eq!(
            table.get("nested_key").unwrap(),
            &Value::String("nested_value".to_string())
        );
    }

    #[test]
    fn test_desetialize_section() {
        let toml_content = r#"
            [section]
            key = "value"
            int_key = 42
            date = 2023-10-01T12:00:00Z
            "#;
        let parsed_map = deserialize(toml_content.to_string()).unwrap();
        let table = parsed_map.get("section").unwrap();
        assert_eq!(
            table.get("key").unwrap(),
            &Value::String("value".to_string())
        );
        assert_eq!(table.get("int_key").unwrap(), &Value::Int(42));
    }

    #[test]
    fn test_serialize() {
        let mut map = Map::new();
        map.insert("key".to_string(), Value::String("value".to_string()));
        map.insert("int_key".to_string(), Value::Int(42));
        map.insert("float_key".to_string(), Value::Float(3.1));
        map.insert("bool_key".to_string(), Value::Bool(true));
        let serialized = serialize(map);
        assert!(serialized.contains("key = \"value\""));
        assert!(serialized.contains("int_key = 42"));
        assert!(serialized.contains("float_key = 3.1"));
        assert!(serialized.contains("bool_key = true"));
    }

    #[test]
    fn test_serialize_array() {
        let mut map = Map::new();
        map.insert(
            "array_key".to_string(),
            Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]),
        );
        let serialized = serialize(map);
        assert!(serialized.contains("array_key = [1, 2, 3]"));
    }

    mod from_toml_value {
        use super::*;

        #[test]
        fn test_from_toml_value() {
            let toml_value = toml::Value::String("value".to_string());
            let parsed_value = from_toml_value(&toml_value);
            assert_eq!(parsed_value, Value::String("value".to_string()));
        }

        #[test]
        fn test_from_toml_array() {
            let toml_value = toml::Value::Array(vec![
                toml::Value::Integer(1),
                toml::Value::String("two".to_string()),
            ]);
            let parsed_value = from_toml_value(&toml_value);
            assert_eq!(
                parsed_value,
                Value::Array(vec![Value::Int(1), Value::String("two".to_string())])
            );
        }

        #[test]
        fn test_from_toml_table() {
            let toml_value = toml::Value::Table(toml::Table::new());
            let parsed_value = from_toml_value(&toml_value);
            assert_eq!(parsed_value, Value::Table(Map::new()));
        }

        #[test]
        fn test_from_toml_bool() {
            let toml_value = toml::Value::Boolean(true);
            let parsed_value = from_toml_value(&toml_value);
            assert_eq!(parsed_value, Value::Bool(true));
        }

        #[test]
        fn test_from_toml_integer() {
            let toml_value = toml::Value::Integer(42);
            let parsed_value = from_toml_value(&toml_value);
            assert_eq!(parsed_value, Value::Int(42));
        }

        #[test]
        fn test_from_toml_float() {
            let toml_value = toml::Value::Float(3.1);
            let parsed_value = from_toml_value(&toml_value);
            assert_eq!(parsed_value, Value::Float(3.1));
        }

        #[test]
        fn test_from_toml_string() {
            let toml_value = toml::Value::String("Hello".to_string());
            let parsed_value = from_toml_value(&toml_value);
            assert_eq!(parsed_value, Value::String("Hello".to_string()));
        }
    }

    mod to_toml_value {
        use super::*;

        #[test]
        fn test_to_toml_value() {
            let value = Value::String("value".to_string());
            let toml_value = to_toml_value(value);
            assert_eq!(toml_value, toml::Value::String("value".to_string()));
        }

        #[test]
        fn test_to_toml_array() {
            let value = Value::Array(vec![Value::Int(1), Value::String("two".to_string())]);
            let toml_value = to_toml_value(value);
            assert_eq!(
                toml_value,
                toml::Value::Array(vec![
                    toml::Value::Integer(1),
                    toml::Value::String("two".to_string())
                ])
            );
        }

        #[test]
        fn test_to_table() {
            let mut map = Map::new();
            map.insert("key".to_string(), Value::String("value".to_string()));
            let value = Value::Table(map);
            let toml_value = to_toml_value(value);
            let mut expected_table = toml::Table::new();
            expected_table.insert("key".to_string(), toml::Value::String("value".to_string()));
            assert_eq!(toml_value, toml::Value::Table(expected_table));
        }

        #[test]
        fn test_to_toml_bool() {
            let value = Value::Bool(true);
            let toml_value = to_toml_value(value);
            assert_eq!(toml_value, toml::Value::Boolean(true));
        }

        #[test]
        fn test_to_toml_integer() {
            let value = Value::Int(42);
            let toml_value = to_toml_value(value);
            assert_eq!(toml_value, toml::Value::Integer(42));
        }

        #[test]
        fn test_to_toml_float() {
            let value = Value::Float(3.1);
            let toml_value = to_toml_value(value);
            assert_eq!(toml_value, toml::Value::Float(3.1));
        }

        #[test]
        fn test_to_toml_string() {
            let value = Value::String("Hello".to_string());
            let toml_value = to_toml_value(value);
            assert_eq!(toml_value, toml::Value::String("Hello".to_string()));
        }

        #[test]
        fn test_to_toml_unsupported() {
            let value = Value::None;
            let result = std::panic::catch_unwind(|| to_toml_value(value));
            assert!(result.is_err());
        }
    }
}