datex_core/values/
value.rs

1use super::datex_type::CoreValueType;
2use crate::values::core_value::CoreValue;
3use crate::values::traits::structural_eq::StructuralEq;
4use crate::values::traits::value_eq::ValueEq;
5use crate::values::value_container::ValueError;
6use log::error;
7use std::fmt::{Display, Formatter};
8use std::ops::{Add, AddAssign, Deref, Not, Sub};
9
10#[derive(Clone, Debug, Eq, PartialEq, Hash)]
11pub struct Value {
12    pub inner: CoreValue,
13    pub actual_type: CoreValueType, // custom type for the value that can not be changed
14}
15
16/// Two values are structurally equal, if their inner values are structurally equal, regardless
17/// of the actual_type of the values
18impl StructuralEq for Value {
19    fn structural_eq(&self, other: &Self) -> bool {
20        self.inner.structural_eq(&other.inner)
21    }
22}
23
24/// Value equality corresponds to partial equality:
25/// Both type and inner value are the same
26impl ValueEq for Value {
27    fn value_eq(&self, other: &Self) -> bool {
28        self == other
29    }
30}
31
32impl Deref for Value {
33    type Target = CoreValue;
34
35    fn deref(&self) -> &Self::Target {
36        &self.inner
37    }
38}
39
40impl<T: Into<CoreValue>> From<T> for Value {
41    fn from(inner: T) -> Self {
42        let inner = inner.into();
43        let actual_type = inner.get_default_type();
44        Value { inner, actual_type }
45    }
46}
47
48impl Value {
49    pub fn is_of_type(&self, target: CoreValueType) -> bool {
50        self.get_type() == target
51    }
52    pub fn is_null(&self) -> bool {
53        self.is_of_type(CoreValueType::Null)
54    }
55    pub fn is_text(&self) -> bool {
56        self.is_of_type(CoreValueType::Text)
57    }
58    pub fn is_i8(&self) -> bool {
59        self.is_of_type(CoreValueType::I8)
60    }
61    pub fn is_bool(&self) -> bool {
62        self.is_of_type(CoreValueType::Bool)
63    }
64
65    /// Attempts to cast the value to the target type, returning an Option<Value>.
66    /// If the cast fails, it returns None.
67    /// This is useful for cases where you want to handle the failure gracefully.
68    /// # Arguments
69    /// * `target_type` - The target type to cast the value to.
70    /// # Returns
71    /// * `Option<Value>` - Some(Value) if the cast is successful, None if it fails.
72    ////
73    /// # Example
74    /// ```
75    /// # use datex_core::values::datex_type::CoreValueType;
76    /// # use datex_core::values::value::Value;
77    /// let value = Value::from(42);
78    /// let casted_value = value.try_cast_to(CoreValueType::Text);
79    /// assert!(casted_value.is_some());
80    /// assert_eq!(casted_value.unwrap().get_type(), CoreValueType::Text);
81    /// ```
82    pub fn try_cast_to(&self, target_type: CoreValueType) -> Option<Value> {
83        self.inner.cast_to(target_type.clone()).map(|inner| Value {
84            inner,
85            actual_type: target_type,
86        })
87    }
88
89    /// Casts the value to the target type, returning a Value.
90    /// If the cast fails, it panics with an error message.
91    /// This is useful for cases where you expect the cast to succeed and want to avoid handling the failure.
92    /// # Arguments
93    /// * `target_type` - The target type to cast the value to.
94    /// # Returns
95    /// * `Value` - The casted value.
96    /// # Panics
97    /// * If the cast fails, it panics with an error message.
98    /// # Example
99    /// ```
100    /// # use datex_core::values::datex_type::CoreValueType;
101    /// # use datex_core::values::value::Value;
102    /// let value = Value::from(42);
103    /// let casted_value = value.cast_to(CoreValueType::Text);
104    /// assert_eq!(casted_value.get_type(), CoreValueType::Text);
105    /// assert_eq!(casted_value, "42".into());
106    /// ```
107    pub fn cast_to(&self, target_type: CoreValueType) -> Value {
108        self.try_cast_to(target_type.clone()).unwrap_or_else(|| {
109            panic!("Failed to cast value to target type: {target_type:?}")
110        })
111    }
112
113    /// Casts the value to the target type, returning a Value.
114    /// If the cast fails, it returns a Value with type Null.
115    /// This is similar to `cast_to`, but it returns a Value instead of an Option<Value>.
116    /// # Arguments
117    /// * `target_type` - The target type to cast the value to.
118    /// # Returns
119    /// * `Value` - The casted value, or a Value::null() if the cast fails.
120    /// # Example
121    /// ```
122    /// # use datex_core::values::datex_type::CoreValueType;
123    /// # use datex_core::values::value::Value;
124    /// let value = Value::from(42);
125    /// let casted_value = value.cast_or_null(CoreValueType::Text);
126    /// assert_eq!(casted_value.get_type(), CoreValueType::Text);
127    /// assert_eq!(casted_value.inner.cast_to_text().0, "42".to_string());
128    /// ```
129    pub fn cast_or_null(&self, target_type: CoreValueType) -> Value {
130        self.try_cast_to(target_type).unwrap_or(Value::null())
131    }
132
133    pub fn get_type(&self) -> CoreValueType {
134        self.actual_type.clone()
135    }
136
137    pub fn null() -> Self {
138        CoreValue::Null.into()
139    }
140}
141
142impl Add for Value {
143    type Output = Result<Value, ValueError>;
144    fn add(self, rhs: Value) -> Self::Output {
145        Ok((&self.inner + &rhs.inner)?.into())
146    }
147}
148
149impl Add for &Value {
150    type Output = Result<Value, ValueError>;
151    fn add(self, rhs: &Value) -> Self::Output {
152        Value::add(self.clone(), rhs.clone())
153    }
154}
155
156impl Sub for Value {
157    type Output = Result<Value, ValueError>;
158    fn sub(self, rhs: Value) -> Self::Output {
159        Ok((&self.inner - &rhs.inner)?.into())
160    }
161}
162
163impl Sub for &Value {
164    type Output = Result<Value, ValueError>;
165    fn sub(self, rhs: &Value) -> Self::Output {
166        Value::sub(self.clone(), rhs.clone())
167    }
168}
169
170impl Not for Value {
171    type Output = Option<Value>;
172
173    fn not(self) -> Self::Output {
174        (!self.inner).map(Value::from)
175    }
176}
177
178// TODO #119: crate a TryAddAssign trait etc.
179impl<T> AddAssign<T> for Value
180where
181    Value: From<T>,
182{
183    fn add_assign(&mut self, rhs: T) {
184        let rhs: Value = rhs.into();
185        let res = self.inner.clone() + rhs.inner;
186        if let Ok(res) = res {
187            self.inner = res;
188        } else {
189            error!("Failed to add value: {res:?}");
190        }
191    }
192}
193
194impl Display for Value {
195    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
196        write!(f, "{}", self.inner)
197    }
198}
199
200impl<T> From<Option<T>> for Value
201where
202    T: Into<Value>,
203{
204    fn from(opt: Option<T>) -> Self {
205        match opt {
206            Some(v) => v.into(),
207            None => Value::null(),
208        }
209    }
210}
211
212#[cfg(test)]
213/// Tests for the Value struct and its methods.
214/// This module contains unit tests for the Value struct, including its methods and operations.
215/// The value is a holder for a combination of a CoreValue representation and its actual type.
216mod tests {
217    use super::*;
218    use crate::{
219        assert_structural_eq, datex_array,
220        logger::init_logger_debug,
221        values::core_values::{
222            array::Array,
223            endpoint::Endpoint,
224            integer::{integer::Integer, typed_integer::TypedInteger},
225        },
226    };
227    use log::{debug, info};
228    use std::str::FromStr;
229
230    #[test]
231    fn test_endpoint() {
232        init_logger_debug();
233        let endpoint = Value::from(Endpoint::from_str("@test").unwrap());
234        assert_eq!(endpoint.get_type(), CoreValueType::Endpoint);
235        assert_eq!(endpoint.to_string(), "@test");
236
237        let endpoint = Value::from("@test").cast_to(CoreValueType::Endpoint);
238        assert_eq!(endpoint.get_type(), CoreValueType::Endpoint);
239        assert_eq!(endpoint.to_string(), "@test");
240    }
241
242    #[test]
243    fn new_addition_assignments() {
244        let mut x = Value::from(42i8);
245        let y = Value::from(27i8);
246
247        x += y.clone();
248        assert_eq!(x.get_type(), CoreValueType::I8);
249        assert_eq!(x, Value::from(69i8));
250    }
251
252    #[test]
253    fn new_additions() {
254        let x = Value::from(42i8);
255        let y = Value::from(27i8);
256
257        let z = (x.clone() + y.clone()).unwrap();
258        assert_eq!(z.get_type(), CoreValueType::I8);
259        assert_eq!(z, Value::from(69i8));
260    }
261
262    #[test]
263    fn array() {
264        init_logger_debug();
265        let mut a: Array = CoreValue::from(vec![
266            Value::from("42"),
267            Value::from(42),
268            Value::from(true),
269        ])
270        .try_into()
271        .unwrap();
272
273        a.push(Value::from(42));
274        a.push(4);
275
276        assert_eq!(a.len(), 5);
277
278        let b = Array::from(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
279        assert_eq!(b.len(), 11);
280
281        let c = datex_array![1, "test", 3, true, false];
282        assert_eq!(c.len(), 5);
283        assert_eq!(c[0], 1.into());
284        assert_eq!(c[1], "test".into());
285        assert_eq!(c[2], 3.into());
286        debug!("Array: {c}");
287    }
288
289    #[test]
290    fn boolean() {
291        init_logger_debug();
292        let a = Value::from(true);
293        let b = Value::from(false);
294        let c = Value::from(false);
295        assert_eq!(a.get_type(), CoreValueType::Bool);
296        assert_eq!(b.get_type(), CoreValueType::Bool);
297        assert_ne!(a, b);
298        assert_eq!(b, c);
299
300        let d = (!b.clone()).unwrap();
301        assert_eq!(a, d);
302
303        // We can't add two booleans together, so this should return None
304        let a_plus_b = a.clone() + b.clone();
305        assert!(a_plus_b.is_err());
306    }
307
308    #[test]
309    fn equality_same_type() {
310        init_logger_debug();
311        let a = Value::from(42i8);
312        let b = Value::from(42i8);
313        let c = Value::from(27i8);
314
315        assert_eq!(a.get_type(), CoreValueType::I8);
316        assert_eq!(b.get_type(), CoreValueType::I8);
317        assert_eq!(c.get_type(), CoreValueType::I8);
318
319        assert_eq!(a, b);
320        assert_ne!(a, c);
321        assert_ne!(b, c);
322
323        info!("{} === {}", a.clone(), b.clone());
324        info!("{} !== {}", a.clone(), c.clone());
325    }
326
327    #[test]
328    fn decimal() {
329        init_logger_debug();
330        let a = Value::from(42.1f32);
331        let b = Value::from(27f32);
332
333        assert_eq!(a.get_type(), CoreValueType::F32);
334        assert_eq!(b.get_type(), CoreValueType::F32);
335
336        let a_plus_b = (a.clone() + b.clone()).unwrap();
337        assert_eq!(a_plus_b.get_type(), CoreValueType::F32);
338        assert_eq!(a_plus_b, Value::from(69.1f32));
339        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
340    }
341
342    #[test]
343    fn test_cast_type() {
344        init_logger_debug();
345        let a = Value::from(42);
346        let b = a.try_cast_to(CoreValueType::Text).unwrap();
347        assert_eq!(b.get_type(), CoreValueType::Text);
348    }
349
350    #[test]
351    fn test_null() {
352        init_logger_debug();
353
354        let null_value = Value::null();
355        assert_eq!(null_value.get_type(), CoreValueType::Null);
356        assert_eq!(null_value.to_string(), "null");
357
358        let maybe_value: Option<i8> = None;
359        let null_value = Value::from(maybe_value);
360        assert_eq!(null_value.get_type(), CoreValueType::Null);
361        assert_eq!(null_value.to_string(), "null");
362    }
363
364    #[test]
365    fn test_addition() {
366        init_logger_debug();
367        let a = Value::from(42i8);
368        let b = Value::from(27i8);
369
370        assert_eq!(a.get_type(), CoreValueType::I8);
371        assert_eq!(b.get_type(), CoreValueType::I8);
372
373        let a_plus_b = (a.clone() + b.clone()).unwrap();
374
375        assert_eq!(a_plus_b.get_type(), CoreValueType::I8);
376
377        assert_eq!(a_plus_b, Value::from(69i8));
378        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
379    }
380
381    #[test]
382    fn test_string_concatenation() {
383        init_logger_debug();
384        let a = Value::from("Hello ");
385        let b = Value::from(42i8);
386
387        assert_eq!(a.get_type(), CoreValueType::Text);
388        assert_eq!(b.get_type(), CoreValueType::I8);
389
390        let a_plus_b = (a.clone() + b.clone()).unwrap();
391        let b_plus_a = (b.clone() + a.clone()).unwrap();
392
393        assert_eq!(a_plus_b.get_type(), CoreValueType::Text);
394        assert_eq!(b_plus_a.get_type(), CoreValueType::Text);
395
396        assert_eq!(a_plus_b, Value::from("Hello 42"));
397        assert_eq!(b_plus_a, Value::from("42Hello "));
398
399        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
400        info!("{} + {} = {}", b.clone(), a.clone(), b_plus_a);
401    }
402
403    #[test]
404    fn test_structural_equality() {
405        let a = Value::from(42_i8);
406        let b = Value::from(42_i32);
407
408        assert_eq!(a.get_type(), CoreValueType::I8);
409        assert_eq!(b.get_type(), CoreValueType::I32);
410
411        assert_structural_eq!(a, b);
412
413        assert_eq!(
414            Value::from(Integer(TypedInteger::I8(42))),
415            Value::from(Integer(TypedInteger::U32(42))),
416        );
417
418        assert_structural_eq!(
419            Value::from(Integer(TypedInteger::I8(42))),
420            Value::from(Integer(TypedInteger::U32(42))),
421        );
422
423        assert_structural_eq!(
424            Value::from(42_i8),
425            Value::from(Integer::from(42_i8))
426        );
427    }
428}