lavendeux_parser/
value.rs

1use serde::{Deserialize, Serialize};
2
3const MAX_FLOAT_PRECISION: i32 = 8;
4
5/// The datatype for integer values
6pub type IntegerType = i64;
7
8/// The datatype for floating point values
9pub type FloatType = f64;
10
11/// The datatype for array values
12pub type ArrayType = Vec<Value>;
13
14/// Represents a single value resulting from a calculation
15/// Can take the form of an integer, float, boolean or string
16/// 
17/// Some types are interchangeable:
18/// ```rust
19/// use lavendeux_parser::Value;
20/// assert_eq!(Value::Boolean(true), Value::Integer(2).as_bool());
21/// assert_eq!(Value::String("5.0".to_string()), Value::Float(5.0).as_string());
22/// ```
23#[derive(Debug, Serialize, Deserialize)]
24pub enum Value {
25    /// The lack of a value
26    None, 
27
28    /// An unresolved identifier
29    Identifier(String),
30    
31    /// A boolean value - all types can be expressed as booleans
32    Boolean(bool), 
33    
34    /// An integer value - floats can also be expressed as integers
35    Integer(IntegerType), 
36    
37    /// A floating point value - integers can also be expressed as floats
38    Float(FloatType), 
39    
40    /// A string value - all types can be expressed as strings
41    String(String),
42
43    /// An array value
44    Array(ArrayType)
45}
46
47impl std::fmt::Display for Value {
48    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
49        write!(f, "{}", self.as_string())
50    }
51}
52
53impl Value {
54    /// Return the value as a string
55    pub fn as_string(&self) -> String {
56        match self {
57            Value::Boolean(v) => (if *v {"true"} else {"false"}).to_string(),
58            Value::Integer(n) => {format!("{}", *n)},
59            Value::Float(n) => {
60                let multiplier = f64::powi(10.0, MAX_FLOAT_PRECISION);
61                let mut v = (*n * multiplier).round() / multiplier;
62
63                if v == -0.0 { v = 0.0; }
64                let mut f = format!("{:}", v);
65                if !f.contains('.') {
66                    f += ".0";
67                }
68                
69                f
70            },
71            Value::String(s) => s.to_string(),
72            Value::Array(v) => format!("[{}]", v.iter().map(|e| e.as_string()).collect::<Vec<String>>().join(", ")),
73            Value::Identifier(s) => s.to_string(),
74            Value::None => "".to_string(),
75        }
76    }
77    
78    /// Return the value as a boolean
79    pub fn as_bool(&self) -> bool {
80        match self {
81            Value::None => false,
82            Value::Identifier(_) => false,
83            Value::Boolean(v) => *v,
84            Value::Integer(n) => *n != 0,
85            Value::Float(n) => *n != 0.0,
86            Value::String(s) => !s.is_empty(),
87            Value::Array(v) => v.iter().any(|e|e.as_bool())
88        }
89    }
90    
91    /// Return the value as an integer, if possible
92    pub fn as_int(&self) -> Option<IntegerType> {
93        match self {
94            Value::None => None,
95            Value::Identifier(_) => None,
96            Value::Boolean(v) => Some(*v as IntegerType),
97            Value::Integer(n) => Some(*n),
98            Value::Float(n) => Some(*n as IntegerType),
99            Value::String(_) => None,
100            Value::Array(_) => None,
101        }
102    }
103    
104    /// Return the value as a float, if possible
105    pub fn as_float(&self) -> Option<FloatType> {
106        match self {
107            Value::None => None,
108            Value::Identifier(_) => None,
109            Value::Boolean(v) => Some((*v as IntegerType) as FloatType),
110            Value::Integer(n) => Some(*n as FloatType),
111            Value::Float(n) => Some(*n),
112            Value::String(_) => None,
113            Value::Array(_) => None,
114        }
115    }
116    
117    /// Return the value as an array, if possible
118    pub fn as_array(&self) -> ArrayType {
119        match self {
120            Value::None => vec![],
121            Value::Identifier(_) => vec![],
122            Value::Boolean(_) => vec![self.clone()],
123            Value::Integer(_) => vec![self.clone()],
124            Value::Float(_) => vec![self.clone()],
125            Value::String(_) => vec![self.clone()],
126            Value::Array(v) => v.clone(),
127        }
128    }
129
130    /// Determine if the value is a boolean
131    pub fn is_bool(&self) -> bool {
132        matches!(self, Value::Boolean(_))
133    }
134
135    /// Determine if the value is an int
136    pub fn is_int(&self) -> bool {
137        matches!(self, Value::Integer(_))
138    }
139
140    /// Determine if the value is a float
141    pub fn is_float(&self) -> bool {
142        matches!(self, Value::Float(_))
143    }
144
145    /// Determine if the value is a float or int
146    pub fn is_numeric(&self) -> bool {
147        self.is_float() || self.is_int()
148    }
149
150    /// Determine if the value is a string
151    pub fn is_string(&self) -> bool {
152        matches!(self, Value::String(_))
153    }
154
155    /// Determine if the value is an array
156    pub fn is_array(&self) -> bool {
157        matches!(self, Value::Array(_))
158    }
159
160    /// Determine if the value is an identifier
161    pub fn is_identifier(&self) -> bool {
162        matches!(self, Value::Identifier(_))
163    }
164
165    /// Determine if the value is empty
166    pub fn is_none(&self) -> bool {
167        matches!(self, Value::None)
168    }
169}
170
171impl Clone for Value {
172    fn clone(&self) -> Value {
173        match self {
174            Value::None => Value::None,
175            Value::Identifier(s) => Value::Identifier(s.to_string()),
176            Value::Boolean(v) => Value::Boolean(*v),
177            Value::Integer(n) => Value::Integer(*n),
178            Value::Float(n) => Value::Float(*n),
179            Value::String(s) => Value::String(s.to_string()),
180            Value::Array(v) => Value::Array(v.clone()),
181        }
182    }
183}
184
185impl PartialEq for Value {
186    fn eq(&self, other: &Self) -> bool {
187        match (self, other) {
188            (Value::None, Value::None) => true,
189            (Value::Identifier(s), Value::Identifier(o)) => s == o,
190            (Value::Boolean(s), Value::Boolean(o)) => s == o,
191            (Value::Integer(s), Value::Integer(o)) => s == o,
192            (Value::Float(s), Value::Float(o)) => s == o,
193            (Value::String(s), Value::String(o)) => s == o,
194            (Value::Array(s), Value::Array(o)) => s == o,
195
196            _ => false
197        }
198    }
199}
200
201impl PartialEq<bool> for Value {
202    fn eq(&self, other: &bool) -> bool {
203        self.as_bool() == *other
204    }
205}
206
207impl PartialEq<IntegerType> for Value {
208    fn eq(&self, other: &IntegerType) -> bool {
209        if let Some(n) = self.as_int() {
210            n == *other
211        } else {
212            false
213        }
214    }
215}
216
217impl PartialEq<FloatType> for Value {
218    fn eq(&self, other: &FloatType) -> bool {
219        if let Some(n) = self.as_float() {
220            n == *other
221        } else {
222            false
223        }
224    }
225}
226
227impl PartialEq<String> for Value {
228    fn eq(&self, other: &String) -> bool {
229        self.as_string() == *other
230    }
231}
232
233impl PartialEq<&str> for Value {
234    fn eq(&self, other: &&str) -> bool {
235        self.as_string() == *other.to_string()
236    }
237}
238
239impl PartialEq<ArrayType> for Value {
240    fn eq(&self, other: &ArrayType) -> bool {
241        self.as_array().len() == other.len() &&
242        self.as_array().iter().zip(other.iter()).all(|(a,b)| a == b) 
243    }
244}
245
246impl Eq for Value {}
247
248#[cfg(test)]
249mod test_atomic_value {
250    use super::*;
251
252    #[test]
253    fn test_as_string() {
254        assert_eq!("5", Value::Integer(5).as_string());
255        assert_eq!("5.0", Value::Float(5.0).as_string());
256        assert_eq!("5.1", Value::Float(5.1).as_string());
257        assert_eq!("test", Value::String("test".to_string()).as_string());
258        assert_eq!("", Value::None.as_string());
259    }
260    
261    #[test]
262    fn test_as_bool() {
263        assert_eq!(true, Value::Float(5.0).as_bool());
264        assert_eq!(true, Value::Integer(5).as_bool());
265        assert_eq!(true, Value::String("5.0".to_string()).as_bool());
266    }
267    
268    #[test]
269    fn test_as_int() {
270        assert_eq!(true, Value::Float(5.0).as_int().is_some());
271        assert_eq!(5, Value::Float(5.0).as_int().unwrap());
272
273        assert_eq!(true, Value::Integer(5).as_int().is_some());
274        assert_eq!(5, Value::Integer(5).as_int().unwrap());
275
276        assert_eq!(false, Value::String("".to_string()).as_int().is_some());
277    }
278    
279    #[test]
280    fn test_as_float() {
281        assert_eq!(true, Value::Float(5.0).as_float().is_some());
282        assert_eq!(5.0, Value::Float(5.0).as_float().unwrap());
283
284        assert_eq!(true, Value::Integer(5).as_float().is_some());
285        assert_eq!(5.0, Value::Integer(5).as_float().unwrap());
286
287        assert_eq!(false, Value::String("".to_string()).as_float().is_some());
288    }
289    
290    #[test]
291    fn test_as_array() {
292        assert_eq!(1, Value::Float(5.0).as_array().len());
293        assert_eq!(2, Value::Array(vec![Value::Integer(5), Value::Integer(5)]).as_array().len());
294    }
295    
296    #[test]
297    fn test_is_float() {
298        assert_eq!(true, Value::Float(5.0).is_float());
299        assert_eq!(false, Value::Integer(5).is_float());
300    }
301    
302    #[test]
303    fn test_is_string() {
304        assert_eq!(true, Value::String("5.0".to_string()).is_string());
305        assert_eq!(false, Value::Integer(5).is_string());
306    }
307    
308    #[test]
309    fn test_is_array() {
310        assert_eq!(true, Value::Array(vec![Value::Integer(5)]).is_array());
311        assert_eq!(false, Value::Integer(5).is_array());
312    }
313    
314    #[test]
315    fn test_is_identifier() {
316        assert_eq!(false, Value::Array(vec![Value::Integer(5)]).is_identifier());
317        assert_eq!(false, Value::Integer(5).is_array());
318    }
319    
320    #[test]
321    fn test_eq() {
322        assert_eq!(false, Value::Float(5.0) == Value::Float(5.1));
323        assert_eq!(true, Value::Float(5.0) == Value::Float(5.0));
324        assert_eq!(true, Value::Integer(5) == Value::Integer(5));
325        assert_eq!(false, Value::Integer(6) == Value::Integer(5));
326        assert_eq!(true, Value::None == Value::None);
327        assert_eq!(true, Value::String("test".to_string()) == Value::String("test".to_string()));
328        assert_eq!(false, Value::String("test".to_string()) == Value::String("test2".to_string()));
329    }
330}