Skip to main content

datex_core/values/
value.rs

1use crate::{
2    libs::core::CoreLibPointerId,
3    prelude::*,
4    runtime::execution::ExecutionError,
5    shared_values::shared_container::AccessError,
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::SharedReference(type_reference) =
147            self.actual_type.as_ref()
148            && let Ok(actual_type_core_ptr_id) = CoreLibPointerId::try_from(
149                &type_reference.borrow().pointer.address(),
150            )
151        {
152            // actual_type has core type pointer id which is equal to the default core type pointer id of self.inner
153            let self_default_type_ptr_id = CoreLibPointerId::from(&self.inner);
154            self_default_type_ptr_id == actual_type_core_ptr_id
155        } else {
156            false
157        }
158    }
159
160    /// Gets a property on the value if applicable (e.g. for map and structs)
161    pub fn try_get_property<'a>(
162        &self,
163        key: impl Into<ValueKey<'a>>,
164    ) -> Result<ValueContainer, AccessError> {
165        match self.inner {
166            CoreValue::Map(ref map) => {
167                // If the value is a map, get the property
168                Ok(map.get(key)?.clone())
169            }
170            CoreValue::List(ref list) => {
171                if let Some(index) = key.into().try_as_index() {
172                    Ok(list.get(index)?.clone())
173                } else {
174                    Err(AccessError::InvalidIndexKey)
175                }
176            }
177            CoreValue::Text(ref text) => {
178                if let Some(index) = key.into().try_as_index() {
179                    let char = text.char_at(index)?;
180                    Ok(ValueContainer::from(char.to_string()))
181                } else {
182                    Err(AccessError::InvalidIndexKey)
183                }
184            }
185            _ => {
186                // If the value is not an map, we cannot get a property
187                Err(AccessError::InvalidOperation(
188                    "Cannot get property".to_string(),
189                ))
190            }
191        }
192    }
193
194    /// Sets a property on the value if applicable (e.g. for maps)
195    pub fn try_set_property<'a>(
196        &mut self,
197        key: impl Into<ValueKey<'a>>,
198        val: ValueContainer,
199    ) -> Result<(), AccessError> {
200        let key = key.into();
201
202        match self.inner {
203            CoreValue::Map(ref mut map) => {
204                // If the value is an map, set the property
205                map.try_set(key, val)?;
206            }
207            CoreValue::List(ref mut list) => {
208                if let Some(index) = key.try_as_index() {
209                    list.set(index, val)
210                        .map_err(AccessError::IndexOutOfBounds)?;
211                } else {
212                    return Err(AccessError::InvalidIndexKey);
213                }
214            }
215            CoreValue::Text(ref mut text) => {
216                if let Some(index) = key.try_as_index() {
217                    if let ValueContainer::Local(v) = &val
218                        && let CoreValue::Text(new_char) = &v.inner
219                        && new_char.0.len() == 1
220                    {
221                        let char = new_char.0.chars().next().unwrap_or('\0');
222                        text.set_char_at(index, char).map_err(|err| {
223                            AccessError::IndexOutOfBounds(err)
224                        })?;
225                    } else {
226                        return Err(AccessError::InvalidOperation(
227                            "Can only set char character in text".to_string(),
228                        ));
229                    }
230                } else {
231                    return Err(AccessError::InvalidIndexKey);
232                }
233            }
234            _ => {
235                // If the value is not an map, we cannot set a property
236                return Err(AccessError::InvalidOperation(format!(
237                    "Cannot set property '{}' on non-map value: {:?}",
238                    key, self
239                )));
240            }
241        }
242
243        Ok(())
244    }
245}
246
247impl Add for Value {
248    type Output = Result<Value, ValueError>;
249    fn add(self, rhs: Value) -> Self::Output {
250        Ok((&self.inner + &rhs.inner)?.into())
251    }
252}
253
254impl Add for &Value {
255    type Output = Result<Value, ValueError>;
256    fn add(self, rhs: &Value) -> Self::Output {
257        Value::add(self.clone(), rhs.clone())
258    }
259}
260
261impl Sub for Value {
262    type Output = Result<Value, ValueError>;
263    fn sub(self, rhs: Value) -> Self::Output {
264        Ok((&self.inner - &rhs.inner)?.into())
265    }
266}
267
268impl Sub for &Value {
269    type Output = Result<Value, ValueError>;
270    fn sub(self, rhs: &Value) -> Self::Output {
271        Value::sub(self.clone(), rhs.clone())
272    }
273}
274
275impl Neg for Value {
276    type Output = Result<Value, ValueError>;
277
278    fn neg(self) -> Self::Output {
279        (-self.inner).map(Value::from)
280    }
281}
282
283impl Not for Value {
284    type Output = Option<Value>;
285
286    fn not(self) -> Self::Output {
287        (!self.inner).map(Value::from)
288    }
289}
290
291// TODO #119: crate a TryAddAssign trait etc.
292impl<T> AddAssign<T> for Value
293where
294    Value: From<T>,
295{
296    fn add_assign(&mut self, rhs: T) {
297        let rhs: Value = rhs.into();
298        let res = self.inner.clone() + rhs.inner;
299        if let Ok(res) = res {
300            self.inner = res;
301        } else {
302            error!("Failed to add value: {res:?}");
303        }
304    }
305}
306
307impl Display for Value {
308    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
309        core::write!(f, "{}", self.inner)
310    }
311}
312
313impl<T> From<Option<T>> for Value
314where
315    T: Into<Value>,
316{
317    fn from(opt: Option<T>) -> Self {
318        match opt {
319            Some(v) => v.into(),
320            None => Value::null(),
321        }
322    }
323}
324
325#[cfg(test)]
326/// Tests for the Value struct and its methods.
327/// This module contains unit tests for the Value struct, including its methods and operations.
328/// The value is a holder for a combination of a CoreValue representation and its actual type.
329mod tests {
330    use super::*;
331    use crate::{
332        assert_structural_eq, datex_list,
333        libs::core::{get_core_lib_type, get_core_lib_type_reference},
334        prelude::*,
335        values::core_values::{
336            endpoint::Endpoint,
337            integer::{Integer, typed_integer::TypedInteger},
338            list::List,
339        },
340    };
341    use core::str::FromStr;
342    use log::info;
343
344    #[test]
345    fn endpoint() {
346        let endpoint = Value::from(Endpoint::from_str("@test").unwrap());
347        assert_eq!(endpoint.to_string(), "@test");
348    }
349
350    #[test]
351    fn new_addition_assignments() {
352        let mut x = Value::from(42i8);
353        let y = Value::from(27i8);
354
355        x += y.clone();
356        assert_eq!(x, Value::from(69i8));
357    }
358
359    #[test]
360    fn new_additions() {
361        let x = Value::from(42i8);
362        let y = Value::from(27i8);
363
364        let z = (x.clone() + y.clone()).unwrap();
365        assert_eq!(z, Value::from(69i8));
366    }
367
368    #[test]
369    fn list() {
370        let mut a = List::from(vec![
371            Value::from("42"),
372            Value::from(42),
373            Value::from(true),
374        ]);
375
376        a.push(Value::from(42));
377        a.push(4);
378
379        assert_eq!(a.len(), 5);
380
381        let b = List::from(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
382        assert_eq!(b.len(), 11);
383
384        let c = datex_list![1, "test", 3, true, false];
385        assert_eq!(c.len(), 5);
386        assert_eq!(c[0], 1.into());
387        assert_eq!(c[1], "test".into());
388        assert_eq!(c[2], 3.into());
389    }
390
391    #[test]
392    fn boolean() {
393        let a = Value::from(true);
394        let b = Value::from(false);
395        let c = Value::from(false);
396        assert_ne!(a, b);
397        assert_eq!(b, c);
398
399        let d = (!b.clone()).unwrap();
400        assert_eq!(a, d);
401
402        // We can't add two booleans together, so this should return None
403        let a_plus_b = a.clone() + b.clone();
404        assert!(a_plus_b.is_err());
405    }
406
407    #[test]
408    fn equality_same_type() {
409        let a = Value::from(42i8);
410        let b = Value::from(42i8);
411        let c = Value::from(27i8);
412
413        assert_eq!(a, b);
414        assert_ne!(a, c);
415        assert_ne!(b, c);
416
417        info!("{} === {}", a.clone(), b.clone());
418        info!("{} !== {}", a.clone(), c.clone());
419    }
420
421    #[test]
422    fn decimal() {
423        let a = Value::from(42.1f32);
424        let b = Value::from(27f32);
425
426        let a_plus_b = (a.clone() + b.clone()).unwrap();
427        assert_eq!(a_plus_b, Value::from(69.1f32));
428        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
429    }
430
431    #[test]
432    fn null() {
433        let null_value = Value::null();
434        assert_eq!(null_value.to_string(), "null");
435
436        let maybe_value: Option<i8> = None;
437        let null_value = Value::from(maybe_value);
438        assert_eq!(null_value.to_string(), "null");
439        assert!(null_value.is_null());
440    }
441
442    #[test]
443    fn addition() {
444        let a = Value::from(42i8);
445        let b = Value::from(27i8);
446
447        let a_plus_b = (a.clone() + b.clone()).unwrap();
448        assert_eq!(a_plus_b, Value::from(69i8));
449        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
450    }
451
452    #[test]
453    fn string_concatenation() {
454        let a = Value::from("Hello ");
455        let b = Value::from(42i8);
456
457        assert!(a.is_text());
458        assert!(b.is_integer_i8());
459
460        let a_plus_b = (a.clone() + b.clone()).unwrap();
461        let b_plus_a = (b.clone() + a.clone()).unwrap();
462
463        assert!(a_plus_b.is_text());
464        assert!(b_plus_a.is_text());
465
466        assert_eq!(a_plus_b, Value::from("Hello 42"));
467        assert_eq!(b_plus_a, Value::from("42Hello "));
468
469        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
470        info!("{} + {} = {}", b.clone(), a.clone(), b_plus_a);
471    }
472
473    #[test]
474    fn structural_equality() {
475        let a = Value::from(42_i8);
476        let b = Value::from(42_i32);
477        assert!(a.is_integer_i8());
478
479        assert_structural_eq!(a, b);
480
481        assert_structural_eq!(
482            Value::from(TypedInteger::I8(42)),
483            Value::from(TypedInteger::U32(42)),
484        );
485
486        assert_structural_eq!(
487            Value::from(42_i8),
488            Value::from(Integer::from(42_i8))
489        );
490    }
491
492    #[test]
493    fn default_types() {
494        let val = Value::from(Integer::from(42));
495        assert!(val.has_default_type());
496
497        let val = Value::from(42i8);
498        assert!(val.has_default_type());
499
500        let val = Value {
501            inner: CoreValue::Integer(Integer::from(42)),
502            actual_type: Box::new(TypeDefinition::ImplType(
503                Box::new(get_core_lib_type(CoreLibPointerId::Integer(None))),
504                vec![],
505            )),
506        };
507
508        assert!(!val.has_default_type());
509    }
510}