datex_core/values/
reference.rs

1use super::datex_type::CoreValueType;
2use crate::values::pointer::Pointer;
3use crate::values::traits::identity::Identity;
4use crate::values::traits::structural_eq::StructuralEq;
5use crate::values::traits::value_eq::ValueEq;
6use crate::values::value::Value;
7use crate::values::value_container::ValueContainer;
8use std::cell::RefCell;
9use std::hash::{Hash, Hasher};
10use std::ops::Deref;
11use std::rc::Rc;
12
13#[derive(Clone, Debug, Eq)]
14pub struct Reference(pub Rc<RefCell<ReferenceData>>);
15
16/// Two references are identical if they point to the same data
17impl Identity for Reference {
18    fn identical(&self, other: &Self) -> bool {
19        Rc::ptr_eq(&self.0, &other.0)
20    }
21}
22
23/// PartialEq corresponds to pointer equality / identity for `Reference`.
24impl PartialEq for Reference {
25    fn eq(&self, other: &Self) -> bool {
26        self.identical(other)
27    }
28}
29
30impl StructuralEq for Reference {
31    fn structural_eq(&self, other: &Self) -> bool {
32        // Two references are structurally equal if their current resolved values are equal
33        self.borrow()
34            .current_resolved_value()
35            .borrow()
36            .structural_eq(&other.borrow().current_resolved_value().borrow())
37    }
38}
39
40impl ValueEq for Reference {
41    fn value_eq(&self, other: &Self) -> bool {
42        // Two references are value-equal if their current resolved values are equal
43        self.borrow()
44            .current_resolved_value()
45            .borrow()
46            .value_eq(&other.borrow().current_resolved_value().borrow())
47    }
48}
49
50impl Hash for Reference {
51    fn hash<H: Hasher>(&self, state: &mut H) {
52        let ptr = Rc::as_ptr(&self.0); // gets *const RefCell<ReferenceData>
53        ptr.hash(state); // hash the address
54    }
55}
56
57impl<T: Into<ValueContainer>> From<T> for Reference {
58    fn from(value_container: T) -> Self {
59        let value_container = value_container.into();
60        let allowed_type =
61            value_container.to_value().borrow().actual_type.clone();
62        Reference(Rc::new(RefCell::new(ReferenceData {
63            value_container,
64            pointer: None,
65            allowed_type,
66        })))
67    }
68}
69
70// Implement Deref to allow access to ReferenceData directly
71impl Deref for Reference {
72    type Target = RefCell<ReferenceData>;
73
74    fn deref(&self) -> &Self::Target {
75        &self.0
76    }
77}
78
79#[derive(Debug, PartialEq, Eq, Hash)]
80pub struct ReferenceData {
81    /// the value that this reference points to
82    pub value_container: ValueContainer,
83    /// pointer information
84    /// this can be None if only a local reference is needed
85    pointer: Option<Pointer>,
86    /// custom type for the pointer that the Datex value is allowed to reference
87    pub allowed_type: CoreValueType,
88}
89
90impl ReferenceData {
91    pub fn pointer_id(&self) -> Option<u64> {
92        self.pointer.as_ref().map(|p| p.pointer_id())
93    }
94
95    pub fn current_value_container(&self) -> &ValueContainer {
96        &self.value_container
97    }
98
99    pub fn current_resolved_value(&self) -> Rc<RefCell<Value>> {
100        self.value_container.to_value()
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use crate::values::traits::value_eq::ValueEq;
108    use crate::{assert_identical, assert_value_eq};
109
110    #[test]
111    fn test_reference_identity() {
112        let value = 42;
113        let reference1 = Reference::from(value);
114        let reference2 = reference1.clone();
115
116        // cloned reference should be equal (identical)
117        assert_eq!(reference1, reference2);
118        // value containers containing the references should also be equal
119        assert_eq!(
120            ValueContainer::Reference(reference1.clone()),
121            ValueContainer::Reference(reference2.clone())
122        );
123        // assert_identical! should also confirm identity
124        assert_identical!(reference1.clone(), reference2);
125        // separate reference containing the same value should not be equal
126        assert_ne!(reference1, Reference::from(value));
127    }
128
129    #[test]
130    fn test_reference_value_equality() {
131        let value = 42;
132        let reference1 = ValueContainer::Reference(Reference::from(value));
133        let reference2 = ValueContainer::Reference(Reference::from(value));
134
135        // different references should not be equal a.k.a. identical
136        assert_ne!(reference1, reference2);
137        // but their current resolved values should be equal
138        assert_value_eq!(reference1, ValueContainer::from(value));
139    }
140
141    #[test]
142    fn test_reference_structural_equality() {
143        let reference1 = Reference::from(42.0);
144        let reference2 = Reference::from(42);
145
146        // different references should not be equal a.k.a. identical
147        assert_ne!(reference1, reference2);
148        // but their current resolved values should be structurally equal
149        assert!(!reference1.structural_eq(&reference2));
150    }
151}