Skip to main content

datex_core/values/
value_container.rs

1use crate::traits::{identity::Identity, structural_eq::StructuralEq};
2use core::{cell::RefCell, result::Result};
3
4use super::value::Value;
5use crate::{
6    prelude::*,
7    runtime::execution::ExecutionError,
8    serde::{
9        deserializer::{DatexDeserializer, from_value_container},
10        error::DeserializationError,
11    },
12    shared_values::{
13        observers::TransceiverId,
14        shared_container::{AccessError, SharedContainer},
15    },
16    traits::{apply::Apply, value_eq::ValueEq},
17    types::definition::TypeDefinition,
18    values::{core_value::CoreValue, core_values::r#type::Type},
19};
20
21use crate::{
22    dif::update::DIFUpdateData,
23    serde::{error::SerializationError, serializer::to_value_container},
24    values::core_values::r#type::TypeMetadata,
25};
26use core::{
27    fmt::Display,
28    hash::{Hash, Hasher},
29    ops::{Add, FnOnce, Neg, Sub},
30};
31use serde::{Deserialize, de::DeserializeOwned};
32
33#[derive(Debug, Clone, PartialEq)]
34pub enum ValueError {
35    IsVoid,
36    InvalidOperation,
37    IntegerOverflow,
38    TypeConversionError,
39}
40
41impl Display for ValueError {
42    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
43        match self {
44            ValueError::IsVoid => core::write!(f, "Value is void"),
45            ValueError::InvalidOperation => {
46                core::write!(f, "Invalid operation on value")
47            }
48            ValueError::TypeConversionError => {
49                core::write!(f, "Type conversion error")
50            }
51            ValueError::IntegerOverflow => {
52                core::write!(f, "Integer overflow occurred")
53            }
54        }
55    }
56}
57
58#[derive(Clone, Debug, PartialEq, Eq, Hash)]
59pub enum ValueKey<'a> {
60    Text(Cow<'a, str>),
61    Index(i64),
62    Value(Cow<'a, ValueContainer>),
63}
64
65impl<'a> ValueKey<'a> {
66    pub fn with_value_container<R>(
67        &self,
68        callback: impl FnOnce(&ValueContainer) -> R,
69    ) -> R {
70        match self {
71            ValueKey::Value(value_container) => callback(value_container),
72            ValueKey::Text(text) => {
73                let value_container =
74                    ValueContainer::Local(text.as_ref().into());
75                callback(&value_container)
76            }
77            ValueKey::Index(index) => {
78                let value_container =
79                    ValueContainer::Local(Value::from(*index));
80                callback(&value_container)
81            }
82        }
83    }
84}
85
86impl<'a> Display for ValueKey<'a> {
87    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
88        match self {
89            ValueKey::Text(text) => core::write!(f, "{}", text),
90            ValueKey::Index(index) => core::write!(f, "{}", index),
91            ValueKey::Value(value_container) => {
92                core::write!(f, "{}", value_container)
93            }
94        }
95    }
96}
97
98impl<'a> From<&'a String> for ValueKey<'a> {
99    fn from(text: &'a String) -> Self {
100        ValueKey::Text(Cow::from(text))
101    }
102}
103
104impl<'a> From<&'a str> for ValueKey<'a> {
105    fn from(text: &'a str) -> Self {
106        ValueKey::Text(Cow::from(text))
107    }
108}
109
110impl<'a> From<i64> for ValueKey<'a> {
111    fn from(index: i64) -> Self {
112        ValueKey::Index(index)
113    }
114}
115
116impl<'a> From<u32> for ValueKey<'a> {
117    fn from(index: u32) -> Self {
118        ValueKey::Index(index as i64)
119    }
120}
121
122impl<'a> From<i32> for ValueKey<'a> {
123    fn from(index: i32) -> Self {
124        ValueKey::Index(index as i64)
125    }
126}
127
128impl<'a> From<&'a ValueContainer> for ValueKey<'a> {
129    fn from(value_container: &'a ValueContainer) -> Self {
130        ValueKey::Value(Cow::Borrowed(value_container))
131    }
132}
133
134impl<'a> ValueKey<'a> {
135    pub fn try_as_text(&self) -> Option<&str> {
136        if let ValueKey::Text(text) = self {
137            Some(text)
138        } else if let ValueKey::Value(val) = self
139            && let ValueContainer::Local(Value {
140                inner: CoreValue::Text(text),
141                ..
142            }) = val.as_ref()
143        {
144            Some(&text.0)
145        } else {
146            None
147        }
148    }
149
150    pub fn try_as_index(&self) -> Option<i64> {
151        if let ValueKey::Index(index) = self {
152            Some(*index)
153        } else if let ValueKey::Value(value) = self
154            && let ValueContainer::Local(Value {
155                inner: CoreValue::Integer(index),
156                ..
157            }) = value.as_ref()
158        {
159            index.as_i64()
160        } else if let ValueKey::Value(value) = self
161            && let ValueContainer::Local(Value {
162                inner: CoreValue::TypedInteger(index),
163                ..
164            }) = value.as_ref()
165        {
166            index.as_i64()
167        } else {
168            None
169        }
170    }
171}
172
173impl<'a> From<ValueKey<'a>> for ValueContainer {
174    fn from(value_key: ValueKey) -> Self {
175        match value_key {
176            ValueKey::Text(text) => {
177                ValueContainer::Local(text.into_owned().into())
178            }
179            ValueKey::Index(index) => ValueContainer::Local(index.into()),
180            ValueKey::Value(value_container) => value_container.into_owned(),
181        }
182    }
183}
184
185#[derive(Debug)]
186pub enum OwnedValueKey {
187    Text(String),
188    Index(i64),
189    Value(ValueContainer),
190}
191
192impl<'a> From<OwnedValueKey> for ValueKey<'a> {
193    fn from(owned: OwnedValueKey) -> Self {
194        match owned {
195            OwnedValueKey::Text(text) => ValueKey::Text(Cow::Owned(text)),
196            OwnedValueKey::Index(index) => ValueKey::Index(index),
197            OwnedValueKey::Value(value_container) => {
198                ValueKey::Value(Cow::Owned(value_container))
199            }
200        }
201    }
202}
203
204#[derive(Clone, Debug, Eq)]
205pub enum ValueContainer {
206    Local(Value), // TODO: add references to local values (for recursive structures)
207    Shared(SharedContainer),
208}
209
210impl<'a> Deserialize<'a> for ValueContainer {
211    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
212    where
213        D: serde::Deserializer<'a>,
214    {
215        // IMPORTANT: this only works if deserializer is actually a DatexDeserializer
216        let deserializer: &DatexDeserializer = unsafe {
217            &*(&deserializer as *const D as *const DatexDeserializer)
218        };
219
220        Ok(deserializer.to_value_container().into_owned())
221    }
222}
223
224impl Hash for ValueContainer {
225    fn hash<H: Hasher>(&self, state: &mut H) {
226        match self {
227            ValueContainer::Local(value) => value.hash(state),
228            ValueContainer::Shared(pointer) => pointer.hash(state),
229        }
230    }
231}
232
233/// Partial equality for ValueContainer is identical to Hash behavior:
234/// Identical references are partially equal, value-equal values are also partially equal.
235/// A pointer and a value are never partially equal.
236impl PartialEq for ValueContainer {
237    fn eq(&self, other: &Self) -> bool {
238        match (self, other) {
239            (ValueContainer::Local(a), ValueContainer::Local(b)) => a == b,
240            (ValueContainer::Shared(a), ValueContainer::Shared(b)) => a == b,
241            _ => false,
242        }
243    }
244}
245
246/// Structural equality checks the structural equality of the underlying values, collapsing
247/// references to their current resolved values.
248impl StructuralEq for ValueContainer {
249    fn structural_eq(&self, other: &Self) -> bool {
250        match (self, other) {
251            (ValueContainer::Local(a), ValueContainer::Local(b)) => {
252                a.structural_eq(b)
253            }
254            (ValueContainer::Shared(a), ValueContainer::Shared(b)) => {
255                a.structural_eq(b)
256            }
257            (ValueContainer::Local(a), ValueContainer::Shared(b))
258            | (ValueContainer::Shared(b), ValueContainer::Local(a)) => {
259                a.structural_eq(&b.collapse_to_value().borrow())
260            }
261        }
262    }
263}
264
265/// Value equality checks the value equality of the underlying values, collapsing
266/// references to their current resolved values.
267impl ValueEq for ValueContainer {
268    fn value_eq(&self, other: &Self) -> bool {
269        match (self, other) {
270            (ValueContainer::Local(a), ValueContainer::Local(b)) => {
271                a.value_eq(b)
272            }
273            (ValueContainer::Shared(a), ValueContainer::Shared(b)) => {
274                a.value_eq(b)
275            }
276            (ValueContainer::Local(a), ValueContainer::Shared(b))
277            | (ValueContainer::Shared(b), ValueContainer::Local(a)) => {
278                a.value_eq(&b.collapse_to_value().borrow())
279            }
280        }
281    }
282}
283
284/// Identity checks only returns true if two references are identical.
285/// Values are never identical to references or other values.
286impl Identity for ValueContainer {
287    fn identical(&self, other: &Self) -> bool {
288        match (self, other) {
289            (ValueContainer::Local(_), ValueContainer::Local(_)) => false,
290            (ValueContainer::Shared(a), ValueContainer::Shared(b)) => {
291                a.identical(b)
292            }
293            _ => false,
294        }
295    }
296}
297
298impl Display for ValueContainer {
299    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
300        match self {
301            ValueContainer::Local(value) => core::write!(f, "{value}"),
302            // TODO #118: only simple temporary way to distinguish between Value and Pointer
303            ValueContainer::Shared(reference) => {
304                core::write!(f, "&({})", reference.collapse_to_value().borrow())
305            }
306        }
307    }
308}
309
310impl ValueContainer {
311    pub fn to_value(&self) -> Rc<RefCell<Value>> {
312        match self {
313            ValueContainer::Local(value) => {
314                Rc::new(RefCell::new(value.clone()))
315            }
316            ValueContainer::Shared(pointer) => pointer.collapse_to_value(),
317        }
318    }
319
320    pub fn is_type(&self) -> bool {
321        match self {
322            ValueContainer::Local(value) => value.is_type(),
323            ValueContainer::Shared(reference) => reference.is_type(),
324        }
325    }
326
327    /// Returns the actual type of the contained value, resolving shared values if necessary.
328    pub fn actual_value_type(&self) -> TypeDefinition {
329        match self {
330            ValueContainer::Local(local) => local.actual_type().clone(),
331            ValueContainer::Shared(shared) => shared.actual_type().clone(),
332        }
333    }
334
335    /// Returns the actual type that describes the value container (e.g. integer or &&mut integer).
336    pub fn actual_container_type(&self) -> Type {
337        match self {
338            ValueContainer::Local(value) => {
339                Type::new(*value.actual_type.clone(), TypeMetadata::default())
340            }
341            ValueContainer::Shared(shared) => {
342                let inner_type =
343                    shared.value_container().actual_container_type();
344                Type::new(
345                    // when nesting references, we need to keep the reference information
346                    if inner_type.is_shared_type() {
347                        TypeDefinition::Type(Box::new(inner_type))
348                    }
349                    // for simple non-ref type, we can collapse the definition
350                    else {
351                        inner_type.type_definition
352                    },
353                    TypeMetadata::Shared {
354                        mutability: shared.mutability(),
355                        reference_mutability: shared
356                            .pointer()
357                            .reference_mutability()
358                            .cloned(),
359                    },
360                )
361            }
362        }
363    }
364
365    /// Returns the allowed type of the value container
366    /// For local values, this is the same as the actual type.
367    /// For shared values, this is the defined allowed type
368    pub fn allowed_type(&self) -> TypeDefinition {
369        match self {
370            ValueContainer::Local(value) => *value.actual_type.clone(),
371            ValueContainer::Shared(shared) => shared.allowed_type(),
372        }
373    }
374
375    /// Casts the contained Value or Reference to the desired type T using serde deserialization.
376    pub fn cast_to_deserializable<T: DeserializeOwned>(
377        &self,
378    ) -> Result<T, DeserializationError> {
379        from_value_container::<T>(self)
380    }
381
382    /// Creates a ValueContainer from a serializable value T using serde serialization.
383    pub fn from_serializable<T: serde::Serialize>(
384        value: &T,
385    ) -> Result<ValueContainer, SerializationError> {
386        to_value_container(value)
387    }
388
389    /// Returns the contained SharedContainer if it is a SharedContainer, otherwise returns None.
390    pub fn maybe_shared(&self) -> Option<&SharedContainer> {
391        if let ValueContainer::Shared(shared) = self {
392            Some(shared)
393        } else {
394            None
395        }
396    }
397
398    /// Runs a closure with the contained SharedContainer if it is a SharedContainer, otherwise returns None.
399    pub fn with_maybe_shared<F, R>(&self, f: F) -> Option<R>
400    where
401        F: FnOnce(&SharedContainer) -> R,
402    {
403        if let ValueContainer::Shared(shared) = self {
404            Some(f(shared))
405        } else {
406            None
407        }
408    }
409
410    /// Returns a reference to the contained SharedContainer, panics if it is not a SharedContainer.
411    pub fn shared_unchecked(&self) -> &SharedContainer {
412        match self {
413            ValueContainer::Shared(shared) => shared,
414            _ => {
415                core::panic!("Cannot convert ValueContainer to SharedContainer")
416            }
417        }
418    }
419
420    pub fn try_get_property<'a>(
421        &self,
422        key: impl Into<ValueKey<'a>>,
423    ) -> Result<ValueContainer, AccessError> {
424        match self {
425            ValueContainer::Local(value) => value.try_get_property(key),
426            ValueContainer::Shared(reference) => {
427                reference.try_get_property(key)
428            }
429        }
430    }
431
432    pub fn try_set_property<'a>(
433        &mut self,
434        source_id: TransceiverId,
435        maybe_update_data: Option<&'a DIFUpdateData>,
436        key: impl Into<ValueKey<'a>>,
437        val: ValueContainer,
438    ) -> Result<(), AccessError> {
439        match self {
440            ValueContainer::Local(v) => v.try_set_property(key, val),
441            ValueContainer::Shared(r) => {
442                r.try_set_property(source_id, maybe_update_data, key, val)
443            }
444        }
445    }
446}
447
448impl Apply for ValueContainer {
449    fn apply(
450        &self,
451        args: &[ValueContainer],
452    ) -> Result<Option<ValueContainer>, ExecutionError> {
453        match self {
454            ValueContainer::Local(value) => value.apply(args),
455            ValueContainer::Shared(reference) => reference.apply(args),
456        }
457    }
458
459    fn apply_single(
460        &self,
461        arg: &ValueContainer,
462    ) -> Result<Option<ValueContainer>, ExecutionError> {
463        match self {
464            ValueContainer::Local(value) => value.apply_single(arg),
465            ValueContainer::Shared(reference) => reference.apply_single(arg),
466        }
467    }
468}
469
470impl<T: Into<Value>> From<T> for ValueContainer {
471    fn from(value: T) -> Self {
472        ValueContainer::Local(value.into())
473    }
474}
475
476impl Add<ValueContainer> for ValueContainer {
477    type Output = Result<ValueContainer, ValueError>;
478
479    fn add(self, rhs: ValueContainer) -> Self::Output {
480        match (self, rhs) {
481            (ValueContainer::Local(lhs), ValueContainer::Local(rhs)) => {
482                (lhs + rhs).map(ValueContainer::Local)
483            }
484            (ValueContainer::Shared(lhs), ValueContainer::Shared(rhs)) => {
485                let lhs_value = lhs.collapse_to_value().borrow().clone();
486                let rhs_value = rhs.collapse_to_value().borrow().clone();
487                (lhs_value + rhs_value).map(ValueContainer::Local)
488            }
489            (ValueContainer::Local(lhs), ValueContainer::Shared(rhs)) => {
490                let rhs_value = rhs.collapse_to_value().borrow().clone();
491                (lhs + rhs_value).map(ValueContainer::Local)
492            }
493            (ValueContainer::Shared(lhs), ValueContainer::Local(rhs)) => {
494                let lhs_value = lhs.collapse_to_value().borrow().clone();
495                (lhs_value + rhs).map(ValueContainer::Local)
496            }
497        }
498    }
499}
500
501impl Add<&ValueContainer> for &ValueContainer {
502    type Output = Result<ValueContainer, ValueError>;
503
504    fn add(self, rhs: &ValueContainer) -> Self::Output {
505        match (self, rhs) {
506            (ValueContainer::Local(lhs), ValueContainer::Local(rhs)) => {
507                (lhs + rhs).map(ValueContainer::Local)
508            }
509            (ValueContainer::Shared(lhs), ValueContainer::Shared(rhs)) => {
510                let lhs_value = lhs.collapse_to_value().borrow().clone();
511                let rhs_value = rhs.collapse_to_value().borrow().clone();
512                (lhs_value + rhs_value).map(ValueContainer::Local)
513            }
514            (ValueContainer::Local(lhs), ValueContainer::Shared(rhs)) => {
515                let rhs_value = rhs.collapse_to_value().borrow().clone();
516                (lhs + &rhs_value).map(ValueContainer::Local)
517            }
518            (ValueContainer::Shared(lhs), ValueContainer::Local(rhs)) => {
519                let lhs_value = lhs.collapse_to_value().borrow().clone();
520                (&lhs_value + rhs).map(ValueContainer::Local)
521            }
522        }
523    }
524}
525
526impl Sub<ValueContainer> for ValueContainer {
527    type Output = Result<ValueContainer, ValueError>;
528
529    fn sub(self, rhs: ValueContainer) -> Self::Output {
530        match (self, rhs) {
531            (ValueContainer::Local(lhs), ValueContainer::Local(rhs)) => {
532                (lhs - rhs).map(ValueContainer::Local)
533            }
534            (ValueContainer::Shared(lhs), ValueContainer::Shared(rhs)) => {
535                let lhs_value = lhs.collapse_to_value().borrow().clone();
536                let rhs_value = rhs.collapse_to_value().borrow().clone();
537                (lhs_value - rhs_value).map(ValueContainer::Local)
538            }
539            (ValueContainer::Local(lhs), ValueContainer::Shared(rhs)) => {
540                let rhs_value = rhs.collapse_to_value().borrow().clone();
541                (lhs - rhs_value).map(ValueContainer::Local)
542            }
543            (ValueContainer::Shared(lhs), ValueContainer::Local(rhs)) => {
544                let lhs_value = lhs.collapse_to_value().borrow().clone();
545                (lhs_value - rhs).map(ValueContainer::Local)
546            }
547        }
548    }
549}
550
551impl Sub<&ValueContainer> for &ValueContainer {
552    type Output = Result<ValueContainer, ValueError>;
553
554    fn sub(self, rhs: &ValueContainer) -> Self::Output {
555        match (self, rhs) {
556            (ValueContainer::Local(lhs), ValueContainer::Local(rhs)) => {
557                (lhs - rhs).map(ValueContainer::Local)
558            }
559            (ValueContainer::Shared(lhs), ValueContainer::Shared(rhs)) => {
560                let lhs_value = lhs.collapse_to_value().borrow().clone();
561                let rhs_value = rhs.collapse_to_value().borrow().clone();
562                (lhs_value - rhs_value).map(ValueContainer::Local)
563            }
564            (ValueContainer::Local(lhs), ValueContainer::Shared(rhs)) => {
565                let rhs_value = rhs.collapse_to_value().borrow().clone();
566                (lhs - &rhs_value).map(ValueContainer::Local)
567            }
568            (ValueContainer::Shared(lhs), ValueContainer::Local(rhs)) => {
569                let lhs_value = lhs.collapse_to_value().borrow().clone();
570                (&lhs_value - rhs).map(ValueContainer::Local)
571            }
572        }
573    }
574}
575
576impl Neg for ValueContainer {
577    type Output = Result<ValueContainer, ValueError>;
578
579    fn neg(self) -> Self::Output {
580        match self {
581            ValueContainer::Local(value) => (-value).map(ValueContainer::Local),
582            ValueContainer::Shared(reference) => {
583                let value = reference.collapse_to_value().borrow().clone(); // FIXME #311: Avoid clone
584                (-value).map(ValueContainer::Local)
585            }
586        }
587    }
588}