chap 2.5.0

Chap is an easy to learn, interpretive, scripting language written in Rust
Documentation
use std::{collections::HashMap, fmt::Display};

use serde::{Deserialize, Serialize};

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DataType {
    String(String),
    Int(i32),
    Float(f64),
    Bool(bool),
    List(Vec<DataType>),
    Map(HashMap<String, DataType>),
}

impl Display for DataType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::String(m) => write!(f, "{}", m.clone()),
            Self::Int(i) => write!(f, "{}", i),
            Self::Float(f_) => write!(f, "{}", f_),
            Self::Bool(b) => write!(f, "{}", b),
            Self::List(b) => {
                let a = b.iter().map(|x| x.to_string());
                let a: Vec<String> = a.collect();
                let i = a.join(" ");
                write!(f, "[{}]", i)
            }
            Self::Map(b) => {
                let mut a: Vec<_> = b.iter().collect();
                a.sort_by_key(|(k, _)| *k);
                let a: Vec<String> = a.iter().map(|(k, v)| format!("\"{}\": {}", k, v)).collect();
                let i = a.join(" ");
                write!(f, "{{{}}}", i)
            }
        }
    }
}

impl DataType {
    pub fn type_name(&self) -> String {
        match self {
            DataType::String(_) => "string".to_string(),
            DataType::Int(_) => "int".to_string(),
            DataType::Float(_) => "float".to_string(),
            DataType::Bool(_) => "boolean".to_string(),
            DataType::List(_) => "list".to_string(),
            DataType::Map(_) => "map".to_string(),
        }
    }
}

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

    #[test]
    fn data_type_equal_test() {
        assert!(DataType::String("abcd".to_string()) == DataType::String("abcd".to_string()));
        assert!(DataType::String("abce".to_string()) != DataType::String("abcd".to_string()));
    }

    #[test]
    fn list_to_string() {
        assert_eq!(
            DataType::List(vec![
                DataType::Int(1),
                DataType::String("hello".to_string())
            ])
            .to_string(),
            "[1 hello]"
        );
    }

    #[test]
    fn map_to_string() {
        let mut map: HashMap<String, DataType> = HashMap::new();
        let mut inner: HashMap<String, DataType> = HashMap::new();

        inner.insert("a".to_string(), DataType::Int(1));

        map.insert("alpha".to_string(), DataType::Bool(true));
        map.insert("bravo".to_string(), DataType::Float(3.1415));
        map.insert("charlie".to_string(), DataType::Int(42));
        map.insert(
            "delta".to_string(),
            DataType::List(vec![
                DataType::Int(1),
                DataType::String("hello".to_string()),
            ]),
        );
        map.insert("echo".to_string(), DataType::Map(inner));
        map.insert(
            "foxtrot".to_string(),
            DataType::String("String".to_string()),
        );

        assert_eq!(
            DataType::Map(map).to_string(),
            "{\"alpha\": true \"bravo\": 3.1415 \"charlie\": 42 \"delta\": [1 hello] \"echo\": {\"a\": 1} \"foxtrot\": String}"
        );
    }
}