datex_core/values/
value_container.rs

1use crate::traits::identity::Identity;
2use crate::traits::structural_eq::StructuralEq;
3use crate::types::type_container::TypeContainer;
4use std::cell::RefCell;
5
6use super::value::Value;
7use crate::compiler::compile_value;
8use crate::runtime::execution::ExecutionError;
9use crate::serde::deserializer::DatexDeserializer;
10use crate::traits::apply::Apply;
11use crate::traits::value_eq::ValueEq;
12use datex_core::references::reference::Reference;
13use serde::{Deserialize, Serialize};
14use std::fmt::Display;
15use std::hash::Hash;
16use std::ops::{Add, Neg, Sub};
17use std::rc::Rc;
18
19#[derive(Debug, Clone, PartialEq)]
20pub enum ValueError {
21    IsVoid,
22    InvalidOperation,
23    IntegerOverflow,
24    TypeConversionError,
25}
26
27impl Display for ValueError {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        match self {
30            ValueError::IsVoid => write!(f, "Value is void"),
31            ValueError::InvalidOperation => {
32                write!(f, "Invalid operation on value")
33            }
34            ValueError::TypeConversionError => {
35                write!(f, "Type conversion error")
36            }
37            ValueError::IntegerOverflow => {
38                write!(f, "Integer overflow occurred")
39            }
40        }
41    }
42}
43
44#[derive(Clone, Debug, Eq)]
45pub enum ValueContainer {
46    Value(Value),
47    Reference(Reference),
48}
49
50impl Serialize for ValueContainer {
51    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
52    where
53        S: serde::Serializer,
54    {
55        serializer.serialize_newtype_struct(
56            "datex::value",
57            &compile_value(self).unwrap(),
58        )
59    }
60}
61
62impl<'a> Deserialize<'a> for ValueContainer {
63    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64    where
65        D: serde::Deserializer<'a>,
66    {
67        let deserializer: &DatexDeserializer = unsafe {
68            &*(&deserializer as *const D as *const DatexDeserializer)
69        };
70
71        Ok(deserializer.value.clone())
72    }
73}
74
75impl Hash for ValueContainer {
76    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
77        match self {
78            ValueContainer::Value(value) => value.hash(state),
79            ValueContainer::Reference(pointer) => pointer.hash(state),
80        }
81    }
82}
83
84/// Partial equality for ValueContainer is identical to Hash behavior:
85/// Identical references are partially equal, value-equal values are also partially equal.
86/// A pointer and a value are never partially equal.
87impl PartialEq for ValueContainer {
88    fn eq(&self, other: &Self) -> bool {
89        match (self, other) {
90            (ValueContainer::Value(a), ValueContainer::Value(b)) => a == b,
91            (ValueContainer::Reference(a), ValueContainer::Reference(b)) => {
92                a == b
93            }
94            _ => false,
95        }
96    }
97}
98
99/// Structural equality checks the structural equality of the underlying values, collapsing
100/// references to their current resolved values.
101impl StructuralEq for ValueContainer {
102    fn structural_eq(&self, other: &Self) -> bool {
103        match (self, other) {
104            (ValueContainer::Value(a), ValueContainer::Value(b)) => {
105                a.structural_eq(b)
106            }
107            (ValueContainer::Reference(a), ValueContainer::Reference(b)) => {
108                a.structural_eq(b)
109            }
110            (ValueContainer::Value(a), ValueContainer::Reference(b))
111            | (ValueContainer::Reference(b), ValueContainer::Value(a)) => {
112                a.structural_eq(&b.collapse_to_value().borrow())
113            }
114        }
115    }
116}
117
118/// Value equality checks the value equality of the underlying values, collapsing
119/// references to their current resolved values.
120impl ValueEq for ValueContainer {
121    fn value_eq(&self, other: &Self) -> bool {
122        match (self, other) {
123            (ValueContainer::Value(a), ValueContainer::Value(b)) => {
124                a.value_eq(b)
125            }
126            (ValueContainer::Reference(a), ValueContainer::Reference(b)) => {
127                a.value_eq(b)
128            }
129            (ValueContainer::Value(a), ValueContainer::Reference(b))
130            | (ValueContainer::Reference(b), ValueContainer::Value(a)) => {
131                a.value_eq(&b.collapse_to_value().borrow())
132            }
133        }
134    }
135}
136
137/// Identity checks only returns true if two references are identical.
138/// Values are never identical to references or other values.
139impl Identity for ValueContainer {
140    fn identical(&self, other: &Self) -> bool {
141        match (self, other) {
142            (ValueContainer::Value(_), ValueContainer::Value(_)) => false,
143            (ValueContainer::Reference(a), ValueContainer::Reference(b)) => {
144                a.identical(b)
145            }
146            _ => false,
147        }
148    }
149}
150
151impl Display for ValueContainer {
152    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153        match self {
154            ValueContainer::Value(value) => write!(f, "{value}"),
155            // TODO #118: only simple temporary way to distinguish between Value and Pointer
156            ValueContainer::Reference(reference) => {
157                write!(f, "&({})", reference.collapse_to_value().borrow())
158            }
159        }
160    }
161}
162
163impl ValueContainer {
164    pub fn to_value(&self) -> Rc<RefCell<Value>> {
165        match self {
166            ValueContainer::Value(value) => {
167                Rc::new(RefCell::new(value.clone()))
168            }
169            ValueContainer::Reference(pointer) => pointer.collapse_to_value(),
170        }
171    }
172
173    pub fn is_type(&self) -> bool {
174        match self {
175            ValueContainer::Value(value) => value.is_type(),
176            ValueContainer::Reference(reference) => reference.is_type(),
177        }
178    }
179
180    /// Returns the allowed type of the value container
181    pub fn allowed_type(&self) -> TypeContainer {
182        match self {
183            // If it's a Value, return its actual type
184            ValueContainer::Value(value) => value.actual_type().clone(),
185            ValueContainer::Reference(reference) => {
186                reference.allowed_type().clone()
187            }
188        }
189    }
190
191    /// Returns the actual type of the contained value, resolving references if necessary.
192    pub fn actual_type(&self) -> TypeContainer {
193        match self {
194            ValueContainer::Value(value) => value.actual_type().clone(),
195            ValueContainer::Reference(reference) => {
196                reference.actual_type().clone()
197            }
198        }
199    }
200
201    pub fn new_value<T: Into<Value>>(value: T) -> ValueContainer {
202        ValueContainer::Value(value.into())
203    }
204
205    pub fn new_reference<T: Into<Reference>>(value: T) -> ValueContainer {
206        ValueContainer::Reference(value.into())
207    }
208
209    /// Returns the contained Reference if it is a Reference, otherwise returns None.
210    pub fn maybe_reference(&self) -> Option<&Reference> {
211        if let ValueContainer::Reference(reference) = self {
212            Some(reference)
213        } else {
214            None
215        }
216    }
217
218    /// Runs a closure with the contained Reference if it is a Reference, otherwise returns None.
219    pub fn with_maybe_reference<F, R>(&self, f: F) -> Option<R>
220    where
221        F: FnOnce(&Reference) -> R,
222    {
223        if let ValueContainer::Reference(reference) = self {
224            Some(f(reference))
225        } else {
226            None
227        }
228    }
229
230    /// Returns a reference to the contained Reference, panics if it is not a Reference.
231    pub fn reference_unchecked(&self) -> &Reference {
232        match self {
233            ValueContainer::Reference(reference) => reference,
234            _ => panic!("Cannot convert ValueContainer to Reference"),
235        }
236    }
237
238    /// Upgrades the ValueContainer to a ValueContainer::Reference if it is a ValueContainer::Value
239    /// and if the contained value is a combined value, not a primitive value like integer, text, etc.
240    pub fn upgrade_combined_value_to_reference(self) -> ValueContainer {
241        match &self {
242            // already a reference, no need to upgrade
243            ValueContainer::Reference(_) => self,
244            ValueContainer::Value(value) => {
245                if value.is_collection_value() {
246                    ValueContainer::new_reference(self)
247                }
248                // if the value is not a combined value, keep it as a ValueContainer::Value
249                else {
250                    self
251                }
252            }
253        }
254    }
255}
256
257impl Apply for ValueContainer {
258    fn apply(
259        &self,
260        args: &[ValueContainer],
261    ) -> Result<Option<ValueContainer>, ExecutionError> {
262        match self {
263            ValueContainer::Value(value) => todo!("#309 implement apply for Value"),
264            ValueContainer::Reference(reference) => reference.apply(args),
265        }
266    }
267
268    fn apply_single(
269        &self,
270        arg: &ValueContainer,
271    ) -> Result<Option<ValueContainer>, ExecutionError> {
272        match self {
273            ValueContainer::Value(value) => {
274                todo!("#310 implement apply_single for Value")
275            }
276            ValueContainer::Reference(reference) => reference.apply_single(arg),
277        }
278    }
279}
280
281impl<T: Into<Value>> From<T> for ValueContainer {
282    fn from(value: T) -> Self {
283        ValueContainer::Value(value.into())
284    }
285}
286
287impl From<TypeContainer> for ValueContainer {
288    fn from(type_container: TypeContainer) -> Self {
289        match type_container {
290            TypeContainer::Type(type_value) => {
291                ValueContainer::Value(Value::from(type_value))
292            }
293            TypeContainer::TypeReference(type_reference) => {
294                ValueContainer::Reference(Reference::TypeReference(
295                    type_reference,
296                ))
297            }
298        }
299    }
300}
301
302impl Add<ValueContainer> for ValueContainer {
303    type Output = Result<ValueContainer, ValueError>;
304
305    fn add(self, rhs: ValueContainer) -> Self::Output {
306        match (self, rhs) {
307            (ValueContainer::Value(lhs), ValueContainer::Value(rhs)) => {
308                (lhs + rhs).map(ValueContainer::Value)
309            }
310            (
311                ValueContainer::Reference(lhs),
312                ValueContainer::Reference(rhs),
313            ) => {
314                let lhs_value = lhs.collapse_to_value().borrow().clone();
315                let rhs_value = rhs.collapse_to_value().borrow().clone();
316                (lhs_value + rhs_value).map(ValueContainer::Value)
317            }
318            (ValueContainer::Value(lhs), ValueContainer::Reference(rhs)) => {
319                let rhs_value = rhs.collapse_to_value().borrow().clone();
320                (lhs + rhs_value).map(ValueContainer::Value)
321            }
322            (ValueContainer::Reference(lhs), ValueContainer::Value(rhs)) => {
323                let lhs_value = lhs.collapse_to_value().borrow().clone();
324                (lhs_value + rhs).map(ValueContainer::Value)
325            }
326        }
327    }
328}
329
330impl Add<&ValueContainer> for &ValueContainer {
331    type Output = Result<ValueContainer, ValueError>;
332
333    fn add(self, rhs: &ValueContainer) -> Self::Output {
334        match (self, rhs) {
335            (ValueContainer::Value(lhs), ValueContainer::Value(rhs)) => {
336                (lhs + rhs).map(ValueContainer::Value)
337            }
338            (
339                ValueContainer::Reference(lhs),
340                ValueContainer::Reference(rhs),
341            ) => {
342                let lhs_value = lhs.collapse_to_value().borrow().clone();
343                let rhs_value = rhs.collapse_to_value().borrow().clone();
344                (lhs_value + rhs_value).map(ValueContainer::Value)
345            }
346            (ValueContainer::Value(lhs), ValueContainer::Reference(rhs)) => {
347                let rhs_value = rhs.collapse_to_value().borrow().clone();
348                (lhs + &rhs_value).map(ValueContainer::Value)
349            }
350            (ValueContainer::Reference(lhs), ValueContainer::Value(rhs)) => {
351                let lhs_value = lhs.collapse_to_value().borrow().clone();
352                (&lhs_value + rhs).map(ValueContainer::Value)
353            }
354        }
355    }
356}
357
358impl Sub<ValueContainer> for ValueContainer {
359    type Output = Result<ValueContainer, ValueError>;
360
361    fn sub(self, rhs: ValueContainer) -> Self::Output {
362        match (self, rhs) {
363            (ValueContainer::Value(lhs), ValueContainer::Value(rhs)) => {
364                (lhs - rhs).map(ValueContainer::Value)
365            }
366            (
367                ValueContainer::Reference(lhs),
368                ValueContainer::Reference(rhs),
369            ) => {
370                let lhs_value = lhs.collapse_to_value().borrow().clone();
371                let rhs_value = rhs.collapse_to_value().borrow().clone();
372                (lhs_value - rhs_value).map(ValueContainer::Value)
373            }
374            (ValueContainer::Value(lhs), ValueContainer::Reference(rhs)) => {
375                let rhs_value = rhs.collapse_to_value().borrow().clone();
376                (lhs - rhs_value).map(ValueContainer::Value)
377            }
378            (ValueContainer::Reference(lhs), ValueContainer::Value(rhs)) => {
379                let lhs_value = lhs.collapse_to_value().borrow().clone();
380                (lhs_value - rhs).map(ValueContainer::Value)
381            }
382        }
383    }
384}
385
386impl Sub<&ValueContainer> for &ValueContainer {
387    type Output = Result<ValueContainer, ValueError>;
388
389    fn sub(self, rhs: &ValueContainer) -> Self::Output {
390        match (self, rhs) {
391            (ValueContainer::Value(lhs), ValueContainer::Value(rhs)) => {
392                (lhs - rhs).map(ValueContainer::Value)
393            }
394            (
395                ValueContainer::Reference(lhs),
396                ValueContainer::Reference(rhs),
397            ) => {
398                let lhs_value = lhs.collapse_to_value().borrow().clone();
399                let rhs_value = rhs.collapse_to_value().borrow().clone();
400                (lhs_value - rhs_value).map(ValueContainer::Value)
401            }
402            (ValueContainer::Value(lhs), ValueContainer::Reference(rhs)) => {
403                let rhs_value = rhs.collapse_to_value().borrow().clone();
404                (lhs - &rhs_value).map(ValueContainer::Value)
405            }
406            (ValueContainer::Reference(lhs), ValueContainer::Value(rhs)) => {
407                let lhs_value = lhs.collapse_to_value().borrow().clone();
408                (&lhs_value - rhs).map(ValueContainer::Value)
409            }
410        }
411    }
412}
413
414impl Neg for ValueContainer {
415    type Output = Result<ValueContainer, ValueError>;
416
417    fn neg(self) -> Self::Output {
418        match self {
419            ValueContainer::Value(value) => (-value).map(ValueContainer::Value),
420            ValueContainer::Reference(reference) => {
421                let value = reference.collapse_to_value().borrow().clone(); // FIXME #311: Avoid clone
422                (-value).map(ValueContainer::Value)
423            }
424        }
425    }
426}