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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use crate::tree::parser::ast::arg::MesType;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::{Display, Formatter};

/// A gathering structure for numeric scalar values
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
pub enum Number {
    Int(i64),
    Float(f64),
    Hex(i64),
    Binary(isize),
}

/// A gathering structure for string scalar values
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct StringLit(pub String);

/// A gathering structure for boolean scalar values
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum Bool {
    True,
    False,
}

impl Into<bool> for Bool {
    fn into(self) -> bool {
        match self {
            Bool::True => true,
            Bool::False => false,
        }
    }
}

/// A gathering structure for scalar values
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum Message {
    Num(Number),
    String(StringLit),
    Bool(Bool),
    Array(Vec<Message>),
    Object(HashMap<String, Message>),
}

impl Display for Message {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Message::Num(v) => match v {
                Number::Int(v) => write!(f, "{}", v),
                Number::Float(v) => write!(f, "{}", v),
                Number::Hex(v) => write!(f, "{}", v),
                Number::Binary(v) => write!(f, "{}", v),
            },
            Message::String(v) => write!(f, "{}", v.0),
            Message::Bool(b) => match b {
                Bool::True => write!(f, "true"),
                Bool::False => write!(f, "false"),
            },
            Message::Array(array) => {
                let mut list = f.debug_list();
                let strings: Vec<_> = array.iter().map(|v| format!("{}", v)).collect();
                list.entries(strings);
                list.finish()
            }
            Message::Object(obj) => {
                let mut map = f.debug_map();
                let entries: Vec<_> = obj.iter().map(|(k, v)| (k, format!("{}", v))).collect();
                map.entries(entries);
                map.finish()
            }
        }
    }
}

impl Message {
    pub fn same(&self, mt: &MesType) -> bool {
        matches!(
            (&self, mt),
            (Message::Num(_), MesType::Num)
                | (Message::String(_), MesType::String)
                | (Message::Bool(_), MesType::Bool)
                | (Message::Array(_), MesType::Array)
                | (Message::Object(_), MesType::Object)
        )
    }

    pub fn str(v: &str) -> Self {
        Message::String(StringLit(v.to_string()))
    }
    pub fn bool(v: bool) -> Self {
        if v {
            Message::Bool(Bool::True)
        } else {
            Message::Bool(Bool::False)
        }
    }
    pub fn int(v: i64) -> Self {
        Message::Num(Number::Int(v))
    }
    pub fn float(v: f64) -> Self {
        Message::Num(Number::Float(v))
    }
    pub fn object(pairs: Vec<(String, Message)>) -> Self {
        Message::Object(HashMap::from_iter(pairs))
    }
    pub fn array(elems: Vec<Message>) -> Self {
        Message::Array(elems)
    }
}