expr/
value.rs

1use crate::Rule;
2use indexmap::IndexMap;
3use log::trace;
4use pest::iterators::{Pair, Pairs};
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7use std::fmt;
8use std::fmt::{Display, Formatter};
9
10/// Represents a data value as input or output to an expr program
11#[derive(Debug, Default, Clone, PartialEq)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13#[cfg_attr(feature = "serde", serde(untagged))]
14pub enum Value {
15    Number(i64),
16    Bool(bool),
17    Float(f64),
18    #[default]
19    Nil,
20    String(String),
21    Array(Vec<Value>),
22    Map(IndexMap<String, Value>),
23}
24
25impl Value {
26    pub fn as_bool(&self) -> Option<bool> {
27        match self {
28            Value::Bool(b) => Some(*b),
29            _ => None,
30        }
31    }
32
33    pub fn as_number(&self) -> Option<i64> {
34        match self {
35            Value::Number(n) => Some(*n),
36            _ => None,
37        }
38    }
39
40    pub fn as_float(&self) -> Option<f64> {
41        match self {
42            Value::Float(f) => Some(*f),
43            _ => None,
44        }
45    }
46
47    pub fn as_string(&self) -> Option<&str> {
48        match self {
49            Value::String(s) => Some(s),
50            _ => None,
51        }
52    }
53
54    pub fn as_array(&self) -> Option<&[Value]> {
55        match self {
56            Value::Array(a) => Some(a),
57            _ => None,
58        }
59    }
60
61    pub fn as_map(&self) -> Option<&IndexMap<String, Value>> {
62        match self {
63            Value::Map(m) => Some(m),
64            _ => None,
65        }
66    }
67
68    pub fn is_nil(&self) -> bool {
69        matches!(self, Value::Nil)
70    }
71}
72
73impl<K, V> FromIterator<(K, V)> for Value
74where
75    K: Into<String>, 
76    V: Into<Value>,
77{
78    fn from_iter<I>(iter: I) -> Self
79    where I: IntoIterator<Item = (K, V)> {
80        Value::Map(iter.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
81    }
82}
83
84impl AsRef<Value> for Value {
85    fn as_ref(&self) -> &Value {
86        self
87    }
88}
89
90impl From<i64> for Value {
91    fn from(n: i64) -> Self {
92        Value::Number(n)
93    }
94}
95
96impl From<i32> for Value {
97    fn from(n: i32) -> Self {
98        Value::Number(n as i64)
99    }
100}
101
102impl From<usize> for Value {
103    fn from(n: usize) -> Self {
104        Value::Number(n as i64)
105    }
106}
107
108impl From<f64> for Value {
109    fn from(f: f64) -> Self {
110        Value::Float(f)
111    }
112}
113
114impl From<bool> for Value {
115    fn from(b: bool) -> Self {
116        Value::Bool(b)
117    }
118}
119
120impl From<String> for Value {
121    fn from(s: String) -> Self {
122        Value::String(s)
123    }
124}
125
126impl From<&String> for Value {
127    fn from(s: &String) -> Self {
128        s.to_string().into()
129    }
130}
131
132impl From<&str> for Value {
133    fn from(s: &str) -> Self {
134        s.to_string().into()
135    }
136}
137
138impl<V: Into<Value>> From<Vec<V>> for Value {
139    fn from(a: Vec<V>) -> Self {
140        Value::Array(a.into_iter().map(|v| v.into()).collect())
141    }
142}
143
144impl From<IndexMap<String, Value>> for Value {
145    fn from(m: IndexMap<String, Value>) -> Self {
146        Value::Map(m)
147    }
148}
149
150impl Display for Value {
151    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
152        match self {
153            Value::Number(n) => write!(f, "{n}"),
154            Value::Float(n) => write!(f, "{n}"),
155            Value::Bool(b) => write!(f, "{b}"),
156            Value::Nil => write!(f, "nil"),
157            Value::String(s) => write!(
158                f,
159                r#""{}""#,
160                s.replace("\\", "\\\\")
161                    .replace("\n", "\\n")
162                    .replace("\r", "\\r")
163                    .replace("\t", "\\t")
164                    .replace("\"", "\\\"")
165            ),
166            Value::Array(a) => write!(
167                f,
168                "[{}]",
169                a.iter()
170                    .map(|v| v.to_string())
171                    .collect::<Vec<String>>()
172                    .join(", ")
173            ),
174            Value::Map(m) => write!(
175                f,
176                "{{{}}}",
177                m.iter()
178                    .map(|(k, v)| format!("{}: {}", k, v))
179                    .collect::<Vec<String>>()
180                    .join(", ")
181            ),
182        }
183    }
184}
185
186impl From<Pairs<'_, Rule>> for Value {
187    fn from(mut pairs: Pairs<Rule>) -> Self {
188        pairs.next().unwrap().into()
189    }
190}
191
192impl From<Pair<'_, Rule>> for Value {
193    fn from(pair: Pair<Rule>) -> Self {
194        trace!("{:?} = {}", &pair.as_rule(), pair.as_str());
195        match pair.as_rule() {
196            Rule::value => pair.into_inner().into(),
197            Rule::nil => Value::Nil,
198            Rule::bool => Value::Bool(pair.as_str().parse().unwrap()),
199            Rule::int => Value::Number(pair.as_str().parse().unwrap()),
200            Rule::decimal => Value::Float(pair.as_str().parse().unwrap()),
201            Rule::string_multiline => pair.into_inner().as_str().into(),
202            Rule::string => pair
203                .into_inner()
204                .as_str()
205                .replace("\\\\", "\\")
206                .replace("\\n", "\n")
207                .replace("\\r", "\r")
208                .replace("\\t", "\t")
209                .replace("\\\"", "\"")
210                .into(),
211            // Rule::operation => {
212            //     let mut pairs = pair.into_inner();
213            //     let operator = pairs.next().unwrap().into();
214            //     let left = Box::new(pairs.next().unwrap().into());
215            //     let right = Box::new(pairs.next().unwrap().into());
216            //     Node::Operation {
217            //         operator,
218            //         left,
219            //         right,
220            //     }
221            // }
222            rule => unreachable!("Unexpected rule: {rule:?} {}", pair.as_str()),
223        }
224    }
225}