datex_core/values/
value.rs

1use crate::traits::structural_eq::StructuralEq;
2use crate::traits::value_eq::ValueEq;
3use crate::types::type_container::TypeContainer;
4use crate::values::core_value::CoreValue;
5use crate::values::core_values::integer::typed_integer::TypedInteger;
6use crate::values::value_container::ValueError;
7use log::error;
8use std::fmt::{Display, Formatter};
9use std::ops::{Add, AddAssign, Deref, Neg, Not, Sub};
10
11#[derive(Clone, Debug, Eq, PartialEq, Hash)]
12pub struct Value {
13    pub inner: CoreValue,
14    pub actual_type: Box<TypeContainer>,
15}
16
17/// Two values are structurally equal, if their inner values are structurally equal, regardless
18/// of the actual_type of the values
19impl StructuralEq for Value {
20    fn structural_eq(&self, other: &Self) -> bool {
21        self.inner.structural_eq(&other.inner)
22    }
23}
24
25/// Value equality corresponds to partial equality:
26/// Both type and inner value are the same
27impl ValueEq for Value {
28    fn value_eq(&self, other: &Self) -> bool {
29        self == other
30    }
31}
32
33impl Deref for Value {
34    type Target = CoreValue;
35
36    fn deref(&self) -> &Self::Target {
37        &self.inner
38    }
39}
40
41impl<T: Into<CoreValue>> From<T> for Value {
42    fn from(inner: T) -> Self {
43        let inner = inner.into();
44        let new_type = inner.default_type();
45        Value {
46            inner,
47            actual_type: Box::new(new_type),
48        }
49    }
50}
51impl Value {
52    pub fn null() -> Self {
53        CoreValue::Null.into()
54    }
55}
56
57impl Value {
58    pub fn is_type(&self) -> bool {
59        matches!(self.inner, CoreValue::Type(_))
60    }
61    pub fn is_null(&self) -> bool {
62        matches!(self.inner, CoreValue::Null)
63    }
64    pub fn is_text(&self) -> bool {
65        matches!(self.inner, CoreValue::Text(_))
66    }
67    pub fn is_integer_i8(&self) -> bool {
68        matches!(&self.inner, CoreValue::TypedInteger(TypedInteger::I8(_)))
69    }
70    pub fn is_bool(&self) -> bool {
71        matches!(self.inner, CoreValue::Boolean(_))
72    }
73    pub fn is_map(&self) -> bool {
74        matches!(self.inner, CoreValue::Map(_))
75    }
76    pub fn is_list(&self) -> bool {
77        matches!(self.inner, CoreValue::List(_))
78    }
79    pub fn actual_type(&self) -> &TypeContainer {
80        self.actual_type.as_ref()
81    }
82}
83
84impl Add for Value {
85    type Output = Result<Value, ValueError>;
86    fn add(self, rhs: Value) -> Self::Output {
87        Ok((&self.inner + &rhs.inner)?.into())
88    }
89}
90
91impl Add for &Value {
92    type Output = Result<Value, ValueError>;
93    fn add(self, rhs: &Value) -> Self::Output {
94        Value::add(self.clone(), rhs.clone())
95    }
96}
97
98impl Sub for Value {
99    type Output = Result<Value, ValueError>;
100    fn sub(self, rhs: Value) -> Self::Output {
101        Ok((&self.inner - &rhs.inner)?.into())
102    }
103}
104
105impl Sub for &Value {
106    type Output = Result<Value, ValueError>;
107    fn sub(self, rhs: &Value) -> Self::Output {
108        Value::sub(self.clone(), rhs.clone())
109    }
110}
111
112impl Neg for Value {
113    type Output = Result<Value, ValueError>;
114
115    fn neg(self) -> Self::Output {
116        (-self.inner).map(Value::from)
117    }
118}
119
120impl Not for Value {
121    type Output = Option<Value>;
122
123    fn not(self) -> Self::Output {
124        (!self.inner).map(Value::from)
125    }
126}
127
128// TODO #119: crate a TryAddAssign trait etc.
129impl<T> AddAssign<T> for Value
130where
131    Value: From<T>,
132{
133    fn add_assign(&mut self, rhs: T) {
134        let rhs: Value = rhs.into();
135        let res = self.inner.clone() + rhs.inner;
136        if let Ok(res) = res {
137            self.inner = res;
138        } else {
139            error!("Failed to add value: {res:?}");
140        }
141    }
142}
143
144impl Display for Value {
145    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
146        write!(f, "{}", self.inner)
147    }
148}
149
150impl<T> From<Option<T>> for Value
151where
152    T: Into<Value>,
153{
154    fn from(opt: Option<T>) -> Self {
155        match opt {
156            Some(v) => v.into(),
157            None => Value::null(),
158        }
159    }
160}
161
162#[cfg(test)]
163/// Tests for the Value struct and its methods.
164/// This module contains unit tests for the Value struct, including its methods and operations.
165/// The value is a holder for a combination of a CoreValue representation and its actual type.
166mod tests {
167    use super::*;
168    use crate::{
169        assert_structural_eq, datex_list,
170        logger::init_logger_debug,
171        values::core_values::{
172            endpoint::Endpoint,
173            integer::{Integer, typed_integer::TypedInteger},
174            list::List,
175        },
176    };
177    use log::{debug, info};
178    use std::str::FromStr;
179
180    #[test]
181    fn endpoint() {
182        init_logger_debug();
183        let endpoint = Value::from(Endpoint::from_str("@test").unwrap());
184        assert_eq!(endpoint.to_string(), "@test");
185    }
186
187    #[test]
188    fn new_addition_assignments() {
189        let mut x = Value::from(42i8);
190        let y = Value::from(27i8);
191
192        x += y.clone();
193        assert_eq!(x, Value::from(69i8));
194    }
195
196    #[test]
197    fn new_additions() {
198        let x = Value::from(42i8);
199        let y = Value::from(27i8);
200
201        let z = (x.clone() + y.clone()).unwrap();
202        assert_eq!(z, Value::from(69i8));
203    }
204
205    #[test]
206    fn list() {
207        init_logger_debug();
208        let mut a = List::from(vec![
209            Value::from("42"),
210            Value::from(42),
211            Value::from(true),
212        ]);
213
214        a.push(Value::from(42));
215        a.push(4);
216
217        assert_eq!(a.len(), 5);
218
219        let b = List::from(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
220        assert_eq!(b.len(), 11);
221
222        let c = datex_list![1, "test", 3, true, false];
223        assert_eq!(c.len(), 5);
224        assert_eq!(c[0], 1.into());
225        assert_eq!(c[1], "test".into());
226        assert_eq!(c[2], 3.into());
227    }
228
229    #[test]
230    fn boolean() {
231        init_logger_debug();
232        let a = Value::from(true);
233        let b = Value::from(false);
234        let c = Value::from(false);
235        assert_ne!(a, b);
236        assert_eq!(b, c);
237
238        let d = (!b.clone()).unwrap();
239        assert_eq!(a, d);
240
241        // We can't add two booleans together, so this should return None
242        let a_plus_b = a.clone() + b.clone();
243        assert!(a_plus_b.is_err());
244    }
245
246    #[test]
247    fn equality_same_type() {
248        init_logger_debug();
249        let a = Value::from(42i8);
250        let b = Value::from(42i8);
251        let c = Value::from(27i8);
252
253        assert_eq!(a, b);
254        assert_ne!(a, c);
255        assert_ne!(b, c);
256
257        info!("{} === {}", a.clone(), b.clone());
258        info!("{} !== {}", a.clone(), c.clone());
259    }
260
261    #[test]
262    fn decimal() {
263        init_logger_debug();
264        let a = Value::from(42.1f32);
265        let b = Value::from(27f32);
266
267        let a_plus_b = (a.clone() + b.clone()).unwrap();
268        assert_eq!(a_plus_b, Value::from(69.1f32));
269        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
270    }
271
272    #[test]
273    fn null() {
274        init_logger_debug();
275
276        let null_value = Value::null();
277        assert_eq!(null_value.to_string(), "null");
278
279        let maybe_value: Option<i8> = None;
280        let null_value = Value::from(maybe_value);
281        assert_eq!(null_value.to_string(), "null");
282        assert!(null_value.is_null());
283    }
284
285    #[test]
286    fn addition() {
287        init_logger_debug();
288        let a = Value::from(42i8);
289        let b = Value::from(27i8);
290
291        let a_plus_b = (a.clone() + b.clone()).unwrap();
292        assert_eq!(a_plus_b, Value::from(69i8));
293        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
294    }
295
296    #[test]
297    fn string_concatenation() {
298        init_logger_debug();
299        let a = Value::from("Hello ");
300        let b = Value::from(42i8);
301
302        assert!(a.is_text());
303        assert!(b.is_integer_i8());
304
305        let a_plus_b = (a.clone() + b.clone()).unwrap();
306        let b_plus_a = (b.clone() + a.clone()).unwrap();
307
308        assert!(a_plus_b.is_text());
309        assert!(b_plus_a.is_text());
310
311        assert_eq!(a_plus_b, Value::from("Hello 42"));
312        assert_eq!(b_plus_a, Value::from("42Hello "));
313
314        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
315        info!("{} + {} = {}", b.clone(), a.clone(), b_plus_a);
316    }
317
318    #[test]
319    fn structural_equality() {
320        let a = Value::from(42_i8);
321        let b = Value::from(42_i32);
322        assert!(a.is_integer_i8());
323
324        assert_structural_eq!(a, b);
325
326        assert_structural_eq!(
327            Value::from(TypedInteger::I8(42)),
328            Value::from(TypedInteger::U32(42)),
329        );
330
331        assert_structural_eq!(
332            Value::from(42_i8),
333            Value::from(Integer::from(42_i8))
334        );
335    }
336}