Skip to main content

datex_core/values/
value.rs

1use crate::{
2    libs::core::CoreLibPointerId,
3    prelude::*,
4    references::{reference::AccessError, type_reference::TypeReference},
5    runtime::execution::ExecutionError,
6    traits::{apply::Apply, structural_eq::StructuralEq, value_eq::ValueEq},
7    types::definition::TypeDefinition,
8    values::{
9        core_value::CoreValue,
10        core_values::{
11            callable::{Callable, CallableBody, CallableSignature},
12            integer::typed_integer::TypedInteger,
13        },
14        value_container::{ValueContainer, ValueError, ValueKey},
15    },
16};
17
18use core::{
19    fmt::{Display, Formatter},
20    ops::{Add, AddAssign, Deref, Neg, Not, Sub},
21    result::Result,
22};
23use log::error;
24
25#[derive(Clone, Debug, Eq, PartialEq, Hash)]
26pub struct Value {
27    pub inner: CoreValue,
28    pub actual_type: Box<TypeDefinition>,
29}
30
31/// Two values are structurally equal, if their inner values are structurally equal, regardless
32/// of the actual_type of the values
33impl StructuralEq for Value {
34    fn structural_eq(&self, other: &Self) -> bool {
35        self.inner.structural_eq(&other.inner)
36    }
37}
38
39/// Value equality corresponds to partial equality:
40/// Both type and inner value are the same
41impl ValueEq for Value {
42    fn value_eq(&self, other: &Self) -> bool {
43        self == other
44    }
45}
46
47impl Deref for Value {
48    type Target = CoreValue;
49
50    fn deref(&self) -> &Self::Target {
51        &self.inner
52    }
53}
54
55impl Apply for Value {
56    fn apply(
57        &self,
58        args: &[ValueContainer],
59    ) -> Result<Option<ValueContainer>, ExecutionError> {
60        match self.inner {
61            CoreValue::Callable(ref callable) => callable.apply(args),
62            _ => Err(ExecutionError::InvalidApply),
63        }
64    }
65    fn apply_single(
66        &self,
67        arg: &ValueContainer,
68    ) -> Result<Option<ValueContainer>, ExecutionError> {
69        match self.inner {
70            CoreValue::Callable(ref callable) => callable.apply_single(arg),
71            _ => Err(ExecutionError::InvalidApply),
72        }
73    }
74}
75
76impl<T: Into<CoreValue>> From<T> for Value {
77    fn from(inner: T) -> Self {
78        let inner = inner.into();
79        let new_type = inner.default_type_definition();
80        Value {
81            inner,
82            actual_type: Box::new(new_type),
83        }
84    }
85}
86impl Value {
87    pub fn null() -> Self {
88        CoreValue::Null.into()
89    }
90}
91
92impl Value {
93    pub fn callable(
94        name: Option<String>,
95        signature: CallableSignature,
96        body: CallableBody,
97    ) -> Self {
98        Value {
99            inner: CoreValue::Callable(Callable {
100                name,
101                signature: signature.clone(),
102                body,
103            }),
104            actual_type: Box::new(TypeDefinition::callable(signature)),
105        }
106    }
107
108    pub fn is_type(&self) -> bool {
109        core::matches!(self.inner, CoreValue::Type(_))
110    }
111    pub fn is_null(&self) -> bool {
112        core::matches!(self.inner, CoreValue::Null)
113    }
114    pub fn is_text(&self) -> bool {
115        core::matches!(self.inner, CoreValue::Text(_))
116    }
117    pub fn is_integer_i8(&self) -> bool {
118        core::matches!(
119            &self.inner,
120            CoreValue::TypedInteger(TypedInteger::I8(_))
121        )
122    }
123    pub fn is_bool(&self) -> bool {
124        core::matches!(self.inner, CoreValue::Boolean(_))
125    }
126    pub fn is_map(&self) -> bool {
127        core::matches!(self.inner, CoreValue::Map(_))
128    }
129    pub fn is_list(&self) -> bool {
130        core::matches!(self.inner, CoreValue::List(_))
131    }
132    pub fn actual_type(&self) -> &TypeDefinition {
133        self.actual_type.as_ref()
134    }
135
136    /// Returns true if the current Value's actual type is the same as its default type
137    /// E.g. if the type is integer for an Integer value, or integer/u8 for a typed integer value
138    /// This will return false for an integer value if the actual type is one of the following:
139    /// * an ImplType<integer, x>
140    /// * a new nominal type containing an integer
141    /// TODO #604: this does not match all cases of default types from the point of view of the compiler -
142    /// integer variants (despite bigint) can be distinguished based on the instruction code, but for text variants,
143    /// the variant must be included in the compiler output - so we need to handle theses cases as well.
144    /// Generally speaking, all variants except the few integer variants should never be considered default types.
145    pub fn has_default_type(&self) -> bool {
146        if let TypeDefinition::Reference(type_reference) =
147            self.actual_type.as_ref()
148            && let TypeReference {
149                pointer_address: Some(pointer_address),
150                ..
151            } = &*type_reference.borrow()
152            && let Ok(actual_type_core_ptr_id) =
153                CoreLibPointerId::try_from(pointer_address)
154        {
155            // actual_type has core type pointer id which is equal to the default core type pointer id of self.inner
156            let self_default_type_ptr_id = CoreLibPointerId::from(&self.inner);
157            self_default_type_ptr_id == actual_type_core_ptr_id
158        } else {
159            false
160        }
161    }
162
163    /// Gets a property on the value if applicable (e.g. for map and structs)
164    pub fn try_get_property<'a>(
165        &self,
166        key: impl Into<ValueKey<'a>>,
167    ) -> Result<ValueContainer, AccessError> {
168        match self.inner {
169            CoreValue::Map(ref map) => {
170                // If the value is a map, get the property
171                Ok(map.get(key)?.clone())
172            }
173            CoreValue::List(ref list) => {
174                if let Some(index) = key.into().try_as_index() {
175                    Ok(list.get(index)?.clone())
176                } else {
177                    Err(AccessError::InvalidIndexKey)
178                }
179            }
180            CoreValue::Text(ref text) => {
181                if let Some(index) = key.into().try_as_index() {
182                    let char = text.char_at(index)?;
183                    Ok(ValueContainer::from(char.to_string()))
184                } else {
185                    Err(AccessError::InvalidIndexKey)
186                }
187            }
188            _ => {
189                // If the value is not an map, we cannot get a property
190                Err(AccessError::InvalidOperation(
191                    "Cannot get property".to_string(),
192                ))
193            }
194        }
195    }
196
197    /// Sets a property on the value if applicable (e.g. for maps)
198    pub fn try_set_property<'a>(
199        &mut self,
200        key: impl Into<ValueKey<'a>>,
201        val: ValueContainer,
202    ) -> Result<(), AccessError> {
203        let key = key.into();
204
205        match self.inner {
206            CoreValue::Map(ref mut map) => {
207                // If the value is an map, set the property
208                map.try_set(key, val)?;
209            }
210            CoreValue::List(ref mut list) => {
211                if let Some(index) = key.try_as_index() {
212                    list.set(index, val)
213                        .map_err(AccessError::IndexOutOfBounds)?;
214                } else {
215                    return Err(AccessError::InvalidIndexKey);
216                }
217            }
218            CoreValue::Text(ref mut text) => {
219                if let Some(index) = key.try_as_index() {
220                    if let ValueContainer::Value(v) = &val
221                        && let CoreValue::Text(new_char) = &v.inner
222                        && new_char.0.len() == 1
223                    {
224                        let char = new_char.0.chars().next().unwrap_or('\0');
225                        text.set_char_at(index, char).map_err(|err| {
226                            AccessError::IndexOutOfBounds(err)
227                        })?;
228                    } else {
229                        return Err(AccessError::InvalidOperation(
230                            "Can only set char character in text".to_string(),
231                        ));
232                    }
233                } else {
234                    return Err(AccessError::InvalidIndexKey);
235                }
236            }
237            _ => {
238                // If the value is not an map, we cannot set a property
239                return Err(AccessError::InvalidOperation(format!(
240                    "Cannot set property '{}' on non-map value: {:?}",
241                    key, self
242                )));
243            }
244        }
245
246        Ok(())
247    }
248}
249
250impl Add for Value {
251    type Output = Result<Value, ValueError>;
252    fn add(self, rhs: Value) -> Self::Output {
253        Ok((&self.inner + &rhs.inner)?.into())
254    }
255}
256
257impl Add for &Value {
258    type Output = Result<Value, ValueError>;
259    fn add(self, rhs: &Value) -> Self::Output {
260        Value::add(self.clone(), rhs.clone())
261    }
262}
263
264impl Sub for Value {
265    type Output = Result<Value, ValueError>;
266    fn sub(self, rhs: Value) -> Self::Output {
267        Ok((&self.inner - &rhs.inner)?.into())
268    }
269}
270
271impl Sub for &Value {
272    type Output = Result<Value, ValueError>;
273    fn sub(self, rhs: &Value) -> Self::Output {
274        Value::sub(self.clone(), rhs.clone())
275    }
276}
277
278impl Neg for Value {
279    type Output = Result<Value, ValueError>;
280
281    fn neg(self) -> Self::Output {
282        (-self.inner).map(Value::from)
283    }
284}
285
286impl Not for Value {
287    type Output = Option<Value>;
288
289    fn not(self) -> Self::Output {
290        (!self.inner).map(Value::from)
291    }
292}
293
294// TODO #119: crate a TryAddAssign trait etc.
295impl<T> AddAssign<T> for Value
296where
297    Value: From<T>,
298{
299    fn add_assign(&mut self, rhs: T) {
300        let rhs: Value = rhs.into();
301        let res = self.inner.clone() + rhs.inner;
302        if let Ok(res) = res {
303            self.inner = res;
304        } else {
305            error!("Failed to add value: {res:?}");
306        }
307    }
308}
309
310impl Display for Value {
311    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
312        core::write!(f, "{}", self.inner)
313    }
314}
315
316impl<T> From<Option<T>> for Value
317where
318    T: Into<Value>,
319{
320    fn from(opt: Option<T>) -> Self {
321        match opt {
322            Some(v) => v.into(),
323            None => Value::null(),
324        }
325    }
326}
327
328#[cfg(test)]
329/// Tests for the Value struct and its methods.
330/// This module contains unit tests for the Value struct, including its methods and operations.
331/// The value is a holder for a combination of a CoreValue representation and its actual type.
332mod tests {
333    use super::*;
334    use crate::{
335        assert_structural_eq, datex_list,
336        libs::core::{get_core_lib_type, get_core_lib_type_reference},
337        prelude::*,
338        values::core_values::{
339            endpoint::Endpoint,
340            integer::{Integer, typed_integer::TypedInteger},
341            list::List,
342        },
343    };
344    use core::str::FromStr;
345    use log::info;
346
347    #[test]
348    fn endpoint() {
349        let endpoint = Value::from(Endpoint::from_str("@test").unwrap());
350        assert_eq!(endpoint.to_string(), "@test");
351    }
352
353    #[test]
354    fn new_addition_assignments() {
355        let mut x = Value::from(42i8);
356        let y = Value::from(27i8);
357
358        x += y.clone();
359        assert_eq!(x, Value::from(69i8));
360    }
361
362    #[test]
363    fn new_additions() {
364        let x = Value::from(42i8);
365        let y = Value::from(27i8);
366
367        let z = (x.clone() + y.clone()).unwrap();
368        assert_eq!(z, Value::from(69i8));
369    }
370
371    #[test]
372    fn list() {
373        let mut a = List::from(vec![
374            Value::from("42"),
375            Value::from(42),
376            Value::from(true),
377        ]);
378
379        a.push(Value::from(42));
380        a.push(4);
381
382        assert_eq!(a.len(), 5);
383
384        let b = List::from(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
385        assert_eq!(b.len(), 11);
386
387        let c = datex_list![1, "test", 3, true, false];
388        assert_eq!(c.len(), 5);
389        assert_eq!(c[0], 1.into());
390        assert_eq!(c[1], "test".into());
391        assert_eq!(c[2], 3.into());
392    }
393
394    #[test]
395    fn boolean() {
396        let a = Value::from(true);
397        let b = Value::from(false);
398        let c = Value::from(false);
399        assert_ne!(a, b);
400        assert_eq!(b, c);
401
402        let d = (!b.clone()).unwrap();
403        assert_eq!(a, d);
404
405        // We can't add two booleans together, so this should return None
406        let a_plus_b = a.clone() + b.clone();
407        assert!(a_plus_b.is_err());
408    }
409
410    #[test]
411    fn equality_same_type() {
412        let a = Value::from(42i8);
413        let b = Value::from(42i8);
414        let c = Value::from(27i8);
415
416        assert_eq!(a, b);
417        assert_ne!(a, c);
418        assert_ne!(b, c);
419
420        info!("{} === {}", a.clone(), b.clone());
421        info!("{} !== {}", a.clone(), c.clone());
422    }
423
424    #[test]
425    fn decimal() {
426        let a = Value::from(42.1f32);
427        let b = Value::from(27f32);
428
429        let a_plus_b = (a.clone() + b.clone()).unwrap();
430        assert_eq!(a_plus_b, Value::from(69.1f32));
431        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
432    }
433
434    #[test]
435    fn null() {
436        let null_value = Value::null();
437        assert_eq!(null_value.to_string(), "null");
438
439        let maybe_value: Option<i8> = None;
440        let null_value = Value::from(maybe_value);
441        assert_eq!(null_value.to_string(), "null");
442        assert!(null_value.is_null());
443    }
444
445    #[test]
446    fn addition() {
447        let a = Value::from(42i8);
448        let b = Value::from(27i8);
449
450        let a_plus_b = (a.clone() + b.clone()).unwrap();
451        assert_eq!(a_plus_b, Value::from(69i8));
452        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
453    }
454
455    #[test]
456    fn string_concatenation() {
457        let a = Value::from("Hello ");
458        let b = Value::from(42i8);
459
460        assert!(a.is_text());
461        assert!(b.is_integer_i8());
462
463        let a_plus_b = (a.clone() + b.clone()).unwrap();
464        let b_plus_a = (b.clone() + a.clone()).unwrap();
465
466        assert!(a_plus_b.is_text());
467        assert!(b_plus_a.is_text());
468
469        assert_eq!(a_plus_b, Value::from("Hello 42"));
470        assert_eq!(b_plus_a, Value::from("42Hello "));
471
472        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
473        info!("{} + {} = {}", b.clone(), a.clone(), b_plus_a);
474    }
475
476    #[test]
477    fn structural_equality() {
478        let a = Value::from(42_i8);
479        let b = Value::from(42_i32);
480        assert!(a.is_integer_i8());
481
482        assert_structural_eq!(a, b);
483
484        assert_structural_eq!(
485            Value::from(TypedInteger::I8(42)),
486            Value::from(TypedInteger::U32(42)),
487        );
488
489        assert_structural_eq!(
490            Value::from(42_i8),
491            Value::from(Integer::from(42_i8))
492        );
493    }
494
495    #[test]
496    fn default_types() {
497        let val = Value::from(Integer::from(42));
498        assert!(val.has_default_type());
499
500        let val = Value::from(42i8);
501        assert!(val.has_default_type());
502
503        let val = Value {
504            inner: CoreValue::Integer(Integer::from(42)),
505            actual_type: Box::new(TypeDefinition::ImplType(
506                Box::new(get_core_lib_type(CoreLibPointerId::Integer(None))),
507                vec![],
508            )),
509        };
510
511        assert!(!val.has_default_type());
512    }
513}