1use crate::references::type_reference::{
2 NominalTypeDeclaration, TypeReference,
3};
4use crate::types::type_container::TypeContainer;
5use crate::values::core_value::CoreValue;
6
7use crate::references::value_reference::ValueReference;
8use crate::runtime::execution::ExecutionError;
9use crate::traits::apply::Apply;
10use crate::traits::identity::Identity;
11use crate::traits::structural_eq::StructuralEq;
12use crate::traits::value_eq::ValueEq;
13use crate::values::core_values::map::{Map, MapAccessError};
14use crate::values::core_values::r#type::Type;
15use crate::values::pointer::PointerAddress;
16use crate::values::value::Value;
17use crate::values::value_container::ValueContainer;
18use num_enum::TryFromPrimitive;
19use serde::{Deserialize, Serialize};
20use std::cell::RefCell;
21use std::fmt::Display;
22use std::hash::{Hash, Hasher};
23use std::rc::Rc;
24
25#[derive(Debug)]
26pub enum AccessError {
27 ImmutableReference,
28 InvalidOperation(String),
29 PropertyNotFound(String),
30 CanNotUseReferenceAsKey,
31 IndexOutOfBounds(u32),
32 InvalidPropertyKeyType(String),
33 MapAccessError(Box<MapAccessError>),
34}
35
36impl From<MapAccessError> for AccessError {
37 fn from(err: MapAccessError) -> Self {
38 AccessError::MapAccessError(Box::new(err))
39 }
40}
41
42impl Display for AccessError {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self {
45 AccessError::MapAccessError(err) => {
46 write!(f, "Map access error: {}", err)
47 }
48 AccessError::ImmutableReference => {
49 write!(f, "Cannot modify an immutable reference")
50 }
51 AccessError::InvalidOperation(op) => {
52 write!(f, "Invalid operation: {}", op)
53 }
54 AccessError::PropertyNotFound(prop) => {
55 write!(f, "Property not found: {}", prop)
56 }
57 AccessError::CanNotUseReferenceAsKey => {
58 write!(f, "Cannot use a reference as a property key")
59 }
60 AccessError::IndexOutOfBounds(index) => {
61 write!(f, "Index out of bounds: {}", index)
62 }
63 AccessError::InvalidPropertyKeyType(ty) => {
64 write!(f, "Invalid property key type: {}", ty)
65 }
66 }
67 }
68}
69
70#[derive(Debug)]
71pub enum TypeError {
72 TypeMismatch {
73 expected: TypeContainer,
74 found: TypeContainer,
75 },
76}
77impl Display for TypeError {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 match self {
80 TypeError::TypeMismatch { expected, found } => write!(
81 f,
82 "Type mismatch: expected {}, found {}",
83 expected, found
84 ),
85 }
86 }
87}
88
89#[derive(Debug)]
90pub enum AssignmentError {
91 ImmutableReference,
92 TypeError(Box<TypeError>),
93}
94
95impl Display for AssignmentError {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 AssignmentError::ImmutableReference => {
99 write!(f, "Cannot assign to an immutable reference")
100 }
101 AssignmentError::TypeError(e) => write!(f, "Type error: {}", e),
102 }
103 }
104}
105
106#[derive(
107 Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, TryFromPrimitive,
108)]
109#[repr(u8)]
110pub enum ReferenceMutability {
111 Mutable = 0,
112 Immutable = 1,
113 Final = 2,
114}
115
116pub mod mutability_as_int {
117 use super::ReferenceMutability;
118 use serde::de::Error;
119 use serde::{Deserialize, Deserializer, Serializer};
120
121 pub fn serialize<S>(
122 value: &ReferenceMutability,
123 serializer: S,
124 ) -> Result<S::Ok, S::Error>
125 where
126 S: Serializer,
127 {
128 match value {
129 (ReferenceMutability::Mutable) => serializer.serialize_u8(0),
130 (ReferenceMutability::Immutable) => serializer.serialize_u8(1),
131 (ReferenceMutability::Final) => serializer.serialize_u8(2),
132 }
133 }
134
135 pub fn deserialize<'de, D>(
136 deserializer: D,
137 ) -> Result<ReferenceMutability, D::Error>
138 where
139 D: Deserializer<'de>,
140 {
141 let opt = u8::deserialize(deserializer)?;
142 Ok(match opt {
143 (0) => (ReferenceMutability::Mutable),
144 (1) => (ReferenceMutability::Immutable),
145 (2) => (ReferenceMutability::Final),
146 (x) => {
147 return Err(D::Error::custom(format!(
148 "invalid mutability code: {}",
149 x
150 )));
151 }
152 })
153 }
154}
155pub mod mutability_option_as_int {
156 use super::ReferenceMutability;
157 use serde::de::Error;
158 use serde::{Deserialize, Deserializer, Serializer};
159
160 pub fn serialize<S>(
161 value: &Option<ReferenceMutability>,
162 serializer: S,
163 ) -> Result<S::Ok, S::Error>
164 where
165 S: Serializer,
166 {
167 match value {
168 Some(ReferenceMutability::Mutable) => serializer.serialize_u8(0),
169 Some(ReferenceMutability::Immutable) => serializer.serialize_u8(1),
170 Some(ReferenceMutability::Final) => serializer.serialize_u8(2),
171 None => serializer.serialize_none(),
172 }
173 }
174
175 pub fn deserialize<'de, D>(
176 deserializer: D,
177 ) -> Result<Option<ReferenceMutability>, D::Error>
178 where
179 D: Deserializer<'de>,
180 {
181 let opt = Option::<u8>::deserialize(deserializer)?;
182 Ok(match opt {
183 Some(0) => Some(ReferenceMutability::Mutable),
184 Some(1) => Some(ReferenceMutability::Immutable),
185 Some(2) => Some(ReferenceMutability::Final),
186 Some(x) => {
187 return Err(D::Error::custom(format!(
188 "invalid mutability code: {}",
189 x
190 )));
191 }
192 None => None,
193 })
194 }
195}
196
197impl Display for ReferenceMutability {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 match self {
200 ReferenceMutability::Mutable => write!(f, "&mut"),
201 ReferenceMutability::Final => write!(f, "&final"),
202 ReferenceMutability::Immutable => write!(f, "&"),
203 }
204 }
205}
206
207#[derive(Debug, Clone)]
208pub enum Reference {
209 ValueReference(Rc<RefCell<ValueReference>>),
210 TypeReference(Rc<RefCell<TypeReference>>),
211}
212
213impl Display for Reference {
214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215 match self {
216 Reference::ValueReference(vr) => {
217 let vr = vr.borrow();
218 write!(f, "{} {}", vr.mutability, vr.value_container)
219 }
220 Reference::TypeReference(tr) => {
221 let tr = tr.borrow();
222 write!(f, "{}", tr)
223 }
224 }
225 }
226}
227
228impl From<ValueReference> for Reference {
229 fn from(reference: ValueReference) -> Self {
230 Reference::ValueReference(Rc::new(RefCell::new(reference)))
231 }
232}
233impl From<TypeReference> for Reference {
234 fn from(reference: TypeReference) -> Self {
235 Reference::TypeReference(Rc::new(RefCell::new(reference)))
236 }
237}
238
239impl Identity for Reference {
241 fn identical(&self, other: &Self) -> bool {
242 match (self, other) {
243 (Reference::ValueReference(a), Reference::ValueReference(b)) => {
244 Rc::ptr_eq(a, b)
245 }
246 (Reference::TypeReference(a), Reference::TypeReference(b)) => {
247 Rc::ptr_eq(a, b)
248 }
249 _ => false,
250 }
251 }
252}
253
254impl Eq for Reference {}
255
256impl PartialEq for Reference {
258 fn eq(&self, other: &Self) -> bool {
259 self.identical(other)
260 }
261}
262
263impl StructuralEq for Reference {
264 fn structural_eq(&self, other: &Self) -> bool {
265 match (self, other) {
266 (Reference::TypeReference(a), Reference::TypeReference(b)) => {
267 a.borrow().type_value.structural_eq(&b.borrow().type_value)
268 }
269 (Reference::ValueReference(a), Reference::ValueReference(b)) => a
270 .borrow()
271 .value_container
272 .structural_eq(&b.borrow().value_container),
273 _ => false,
274 }
275 }
276}
277
278impl ValueEq for Reference {
279 fn value_eq(&self, other: &Self) -> bool {
280 match (self, other) {
281 (Reference::TypeReference(a), Reference::TypeReference(b)) => {
282 a.borrow().type_value.structural_eq(&b.borrow().type_value)
284 }
285 (Reference::ValueReference(a), Reference::ValueReference(b)) => a
286 .borrow()
287 .value_container
288 .value_eq(&b.borrow().value_container),
289 _ => false,
290 }
291 }
292}
293
294impl Hash for Reference {
295 fn hash<H: Hasher>(&self, state: &mut H) {
296 match self {
297 Reference::TypeReference(tr) => {
298 let ptr = Rc::as_ptr(tr);
299 ptr.hash(state); }
301 Reference::ValueReference(vr) => {
302 let ptr = Rc::as_ptr(vr);
303 ptr.hash(state); }
305 }
306 }
307}
308
309impl<T: Into<ValueContainer>> From<T> for Reference {
310 fn from(value_container: T) -> Self {
312 let value_container = value_container.into();
313 Reference::try_new_from_value_container(
314 value_container,
315 None,
316 None,
317 ReferenceMutability::Immutable,
318 )
319 .unwrap()
320 }
321}
322
323#[derive(Debug, Clone, PartialEq, Eq, Hash)]
324pub enum ReferenceCreationError {
325 InvalidType,
326 MutableTypeReference,
327 CannotCreateFinalFromMutableRef,
328}
329
330impl Display for ReferenceCreationError {
331 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332 match self {
333 ReferenceCreationError::CannotCreateFinalFromMutableRef => {
334 write!(
335 f,
336 "Cannot create final reference from mutable reference"
337 )
338 }
339 ReferenceCreationError::InvalidType => {
340 write!(
341 f,
342 "Cannot create reference from value container: invalid type"
343 )
344 }
345 ReferenceCreationError::MutableTypeReference => {
346 write!(f, "Cannot create mutable reference for type")
347 }
348 }
349 }
350}
351
352impl Reference {
353 pub(crate) fn with_value<R, F: FnOnce(&mut Value) -> R>(
355 &self,
356 f: F,
357 ) -> Option<R> {
358 let reference = self.collapse_reference_chain();
359 match reference {
360 Reference::ValueReference(vr) => {
361 match &mut vr.borrow_mut().value_container {
362 ValueContainer::Value(value) => Some(f(value)),
363 ValueContainer::Reference(_) => {
364 unreachable!(
365 "Expected a ValueContainer::Value, but found a Reference"
366 )
367 }
368 }
369 }
370 Reference::TypeReference(_) => None,
371 }
372 }
373
374 pub(crate) fn with_value_unchecked<R, F: FnOnce(&mut Value) -> R>(
376 &self,
377 f: F,
378 ) -> R {
379 unsafe { self.with_value(f).unwrap_unchecked() }
380 }
381
382 pub fn supports_clear(&self) -> bool {
384 self.with_value(|value| match value.inner {
385 CoreValue::Map(ref mut map) => match map {
386 Map::Dynamic(_) => true,
387 Map::Fixed(_) | Map::Structural(_) => false,
388 },
389 _ => false,
390 })
391 .unwrap_or(false)
392 }
393
394 pub fn supports_property_access(&self) -> bool {
400 self.with_value(|value| {
401 matches!(
402 value.inner,
403 CoreValue::Map(_) | CoreValue::List(_) | CoreValue::Text(_)
404 )
405 })
406 .unwrap_or(false)
407 }
408
409 pub fn supports_text_property_access(&self) -> bool {
412 self.with_value(|value| matches!(value.inner, CoreValue::Map(_)))
413 .unwrap_or(false)
414 }
415
416 pub fn supports_numeric_property_access(&self) -> bool {
419 self.with_value(|value| {
420 matches!(
421 value.inner,
422 CoreValue::Map(_) | CoreValue::List(_) | CoreValue::Text(_)
423 )
424 })
425 .unwrap_or(false)
426 }
427
428 pub fn supports_push(&self) -> bool {
430 self.with_value(|value| matches!(value.inner, CoreValue::List(_)))
431 .unwrap_or(false)
432 }
433}
434
435impl Reference {
436 pub fn pointer_address(&self) -> Option<PointerAddress> {
437 match self {
438 Reference::ValueReference(vr) => {
439 vr.borrow().pointer_address().clone()
440 }
441 Reference::TypeReference(tr) => tr.borrow().pointer_address.clone(),
442 }
443 }
444
445 pub fn set_pointer_address(&self, pointer_address: PointerAddress) {
448 if self.pointer_address().is_some() {
449 panic!(
450 "Cannot set pointer address on reference that already has one"
451 );
452 }
453 match self {
454 Reference::ValueReference(vr) => {
455 vr.borrow_mut().pointer_address = Some(pointer_address)
456 }
457 Reference::TypeReference(tr) => {
458 tr.borrow_mut().pointer_address = Some(pointer_address)
459 }
460 }
461 }
462
463 pub(crate) fn mutability(&self) -> ReferenceMutability {
466 match self {
467 Reference::ValueReference(vr) => vr.borrow().mutability.clone(),
468
469 Reference::TypeReference(_) => ReferenceMutability::Immutable,
471 }
472 }
473
474 pub fn is_mutable(&self) -> bool {
480 match self {
481 Reference::TypeReference(_) => false, Reference::ValueReference(vr) => {
483 let vr_borrow = vr.borrow();
484 if vr_borrow.mutability != ReferenceMutability::Mutable {
486 return false;
487 }
488
489 match &vr_borrow.value_container {
491 ValueContainer::Reference(inner) => inner.is_mutable(),
492 ValueContainer::Value(_) => true,
493 }
494 }
495 }
496 }
497
498 pub fn try_new_from_value_container(
500 value_container: ValueContainer,
501 allowed_type: Option<TypeContainer>,
502 maybe_pointer_id: Option<PointerAddress>,
503 mutability: ReferenceMutability,
504 ) -> Result<Self, ReferenceCreationError> {
505 Ok(match value_container {
507 ValueContainer::Reference(ref reference) => {
508 match reference {
509 Reference::ValueReference(vr) => {
510 let allowed_type = allowed_type.unwrap_or_else(|| {
511 vr.borrow().allowed_type.clone()
512 });
513 Reference::ValueReference(Rc::new(RefCell::new(
515 ValueReference::new(
516 value_container,
517 maybe_pointer_id,
518 allowed_type,
519 mutability,
520 ),
521 )))
522 }
523 Reference::TypeReference(tr) => {
524 if mutability == ReferenceMutability::Mutable {
525 return Err(
526 ReferenceCreationError::MutableTypeReference,
527 );
528 }
529 Reference::TypeReference(
530 TypeReference::anonymous(
531 Type::reference(tr.clone(), Some(mutability)),
532 maybe_pointer_id,
533 )
534 .as_ref_cell(),
535 )
536 }
537 }
538 }
539 ValueContainer::Value(value) => {
540 match value.inner {
541 CoreValue::Type(type_value) => {
543 if allowed_type.is_some() {
545 return Err(ReferenceCreationError::InvalidType);
546 }
547 if mutability == ReferenceMutability::Mutable {
548 return Err(
549 ReferenceCreationError::MutableTypeReference,
550 );
551 }
552 Reference::new_from_type(
553 type_value,
554 maybe_pointer_id,
555 None,
556 )
557 }
558 _ => {
560 let allowed_type = allowed_type.unwrap_or_else(|| {
561 value.actual_type.as_ref().clone()
562 });
563 Reference::ValueReference(Rc::new(RefCell::new(
564 ValueReference::new(
565 ValueContainer::Value(value),
566 maybe_pointer_id,
567 allowed_type,
568 mutability,
569 ),
570 )))
571 }
572 }
573 }
574 })
575 }
576
577 pub fn new_from_type(
578 type_value: Type,
579 maybe_pointer_address: Option<PointerAddress>,
580 maybe_nominal_type_declaration: Option<NominalTypeDeclaration>,
581 ) -> Self {
582 let type_reference = TypeReference {
583 pointer_address: maybe_pointer_address,
584 nominal_type_declaration: maybe_nominal_type_declaration,
585 type_value,
586 };
587 Reference::TypeReference(Rc::new(RefCell::new(type_reference)))
588 }
589
590 pub fn try_mut_from(
591 value_container: ValueContainer,
592 ) -> Result<Self, ReferenceCreationError> {
593 Reference::try_new_from_value_container(
594 value_container,
595 None,
596 None,
597 ReferenceMutability::Mutable,
598 )
599 }
600
601 pub fn try_final_from(
606 value_container: ValueContainer,
607 ) -> Result<Self, ReferenceCreationError> {
608 match &value_container {
609 ValueContainer::Reference(reference) => {
610 if reference.is_mutable() {
613 return Err(
614 ReferenceCreationError::CannotCreateFinalFromMutableRef,
615 );
616 }
617 }
618 ValueContainer::Value(_) => {}
619 }
620
621 Reference::try_new_from_value_container(
622 value_container,
623 None,
624 None,
625 ReferenceMutability::Final,
626 )
627 }
628
629 pub fn collapse_reference_chain(&self) -> Reference {
631 match self {
632 Reference::TypeReference(tr) => Reference::TypeReference(Rc::new(
634 RefCell::new(tr.borrow().collapse_reference_chain()),
635 )),
636 Reference::ValueReference(vr) => {
637 match &vr.borrow().value_container {
638 ValueContainer::Reference(reference) => {
639 reference.collapse_reference_chain()
641 }
642 ValueContainer::Value(_) => {
643 self.clone()
645 }
646 }
647 }
648 }
649 }
650
651 pub fn collapse_to_value(&self) -> Rc<RefCell<Value>> {
653 let reference = self.collapse_reference_chain();
654 match reference {
655 Reference::ValueReference(vr) => match &vr.borrow().value_container
656 {
657 ValueContainer::Value(_) => {
658 vr.borrow().value_container.to_value()
659 }
660 ValueContainer::Reference(_) => unreachable!(
661 "Expected a ValueContainer::Value, but found a Reference"
662 ),
663 },
664 Reference::TypeReference(tr) => Rc::new(RefCell::new(Value::from(
666 CoreValue::Type(tr.borrow().type_value.clone()),
667 ))),
668 }
669 }
670
671 pub fn value_container(&self) -> ValueContainer {
673 match self {
674 Reference::ValueReference(vr) => {
675 vr.borrow().value_container.clone()
676 }
677 Reference::TypeReference(tr) => ValueContainer::Value(Value::from(
678 CoreValue::Type(tr.borrow().type_value.clone()),
679 )),
680 }
681 }
682
683 pub fn upgrade_inner_combined_values_to_references(&self) {
685 self.with_value(|value| {
686 match &mut value.inner {
687 CoreValue::Map(map) => {
688 for (_, prop) in map.into_iter() {
690 *prop = self.bind_child(prop.clone());
692 }
693 }
694 _ => {
696 }
698 }
699 });
700 }
701
702 pub fn bind_child(&self, child: ValueContainer) -> ValueContainer {
704 child.upgrade_combined_value_to_reference()
707 }
708
709 pub fn allowed_type(&self) -> TypeContainer {
710 match self {
711 Reference::ValueReference(vr) => vr.borrow().allowed_type.clone(),
712 Reference::TypeReference(_) => todo!("#293 type Type"),
713 }
714 }
715
716 pub fn actual_type(&self) -> TypeContainer {
717 match self {
718 Reference::ValueReference(vr) => vr
719 .borrow()
720 .value_container
721 .to_value()
722 .borrow()
723 .actual_type()
724 .clone(),
725 Reference::TypeReference(tr) => todo!("#294 type Type"),
726 }
727 }
728
729 pub fn is_type(&self) -> bool {
730 match self {
731 Reference::TypeReference(_) => true,
732 Reference::ValueReference(vr) => {
733 vr.borrow().resolve_current_value().borrow().is_type()
734 }
735 }
736 }
737
738 pub fn non_final_reference(&self) -> Option<Rc<RefCell<ValueReference>>> {
740 match self {
741 Reference::TypeReference(_) => None,
742 Reference::ValueReference(vr) => {
743 if !vr.borrow().is_final() {
744 Some(vr.clone())
745 } else {
746 None
747 }
748 }
749 }
750 }
751
752 pub fn set_value_container(
755 &self,
756 new_value_container: ValueContainer,
757 ) -> Result<(), AssignmentError> {
758 match &self {
759 Reference::TypeReference(_) => {
760 Err(AssignmentError::ImmutableReference)
761 }
762 Reference::ValueReference(vr) => {
763 if self.is_mutable() {
764 vr.borrow_mut().value_container = new_value_container;
766 Ok(())
767 } else {
768 Err(AssignmentError::ImmutableReference)
769 }
770 }
771 }
772 }
773}
774impl Reference {
776 pub fn try_get_property<T: Into<ValueContainer>>(
784 &self,
785 key: T,
786 ) -> Result<ValueContainer, AccessError> {
787 let key = key.into();
788 self.with_value(|value| {
789 match value.inner {
790 CoreValue::Map(ref mut map) => {
791 Ok(map
793 .get(&key)
794 .ok_or(AccessError::PropertyNotFound(key.to_string()))?
795 .clone())
796 }
797 _ => {
798 Err(AccessError::InvalidOperation(
800 "Cannot get property".to_string(),
801 ))
802 }
803 }
804 })
805 .unwrap_or(Err(AccessError::InvalidOperation(
806 "Cannot get property on invalid reference".to_string(),
807 )))
808 }
809
810 pub fn try_get_text_property(
812 &self,
813 key: &str,
814 ) -> Result<ValueContainer, AccessError> {
815 self.with_value(|value| {
816 match value.inner {
817 CoreValue::Map(ref mut struct_val) => struct_val
818 .get_text(key)
819 .ok_or_else(|| {
820 AccessError::PropertyNotFound(key.to_string())
821 })
822 .cloned(),
823 _ => {
824 Err(AccessError::InvalidOperation(
826 "Cannot get property".to_string(),
827 ))
828 }
829 }
830 })
831 .unwrap_or(Err(AccessError::InvalidOperation(
832 "Cannot get property on invalid reference".to_string(),
833 )))
834 }
835
836 pub fn get_numeric_property(
838 &self,
839 index: u32,
840 ) -> Result<ValueContainer, AccessError> {
841 self.with_value(|value| match value.inner {
842 CoreValue::List(ref mut list) => list
843 .get(index)
844 .cloned()
845 .ok_or(AccessError::IndexOutOfBounds(index)),
846 CoreValue::Text(ref text) => {
847 let char = text
848 .char_at(index as usize)
849 .ok_or(AccessError::IndexOutOfBounds(index))?;
850 Ok(ValueContainer::from(char.to_string()))
851 }
852 _ => Err(AccessError::InvalidOperation(
853 "Cannot get numeric property".to_string(),
854 )),
855 })
856 .unwrap_or(Err(AccessError::InvalidOperation(
857 "Cannot get numeric property on invalid reference".to_string(),
858 )))
859 }
860}
861
862impl Apply for Reference {
863 fn apply(
864 &self,
865 args: &[ValueContainer],
866 ) -> Result<Option<ValueContainer>, ExecutionError> {
867 todo!("#297 Undescribed by author.")
868 }
869
870 fn apply_single(
871 &self,
872 arg: &ValueContainer,
873 ) -> Result<Option<ValueContainer>, ExecutionError> {
874 match self {
875 Reference::TypeReference(tr) => tr.borrow().apply_single(arg),
876 Reference::ValueReference(vr) => todo!("#298 Undescribed by author."),
877 }
878 }
879}
880
881#[cfg(test)]
882mod tests {
883 use super::*;
884 use crate::runtime::global_context::{GlobalContext, set_global_context};
885 use crate::runtime::memory::Memory;
886 use crate::traits::value_eq::ValueEq;
887 use crate::{assert_identical, assert_structural_eq, assert_value_eq};
888 use datex_core::values::core_values::map::Map;
889 use std::assert_matches::assert_matches;
890
891 #[test]
892 fn try_final_from() {
893 let value = ValueContainer::from(42);
895 let reference = Reference::try_final_from(value).unwrap();
896 assert_eq!(reference.mutability(), ReferenceMutability::Final);
897
898 let final_ref =
900 Reference::try_final_from(ValueContainer::from(42)).unwrap();
901 assert!(
902 Reference::try_final_from(ValueContainer::Reference(final_ref))
903 .is_ok()
904 );
905
906 let mutable_ref =
908 Reference::try_mut_from(ValueContainer::from(42)).unwrap();
909 assert_matches!(
910 Reference::try_final_from(ValueContainer::Reference(mutable_ref)),
911 Err(ReferenceCreationError::CannotCreateFinalFromMutableRef)
912 );
913
914 let type_value = ValueContainer::Reference(Reference::TypeReference(
916 TypeReference::anonymous(Type::UNIT, None).as_ref_cell(),
917 ));
918 let type_ref = Reference::try_final_from(type_value).unwrap();
919 assert!(type_ref.is_type());
920 assert_eq!(type_ref.mutability(), ReferenceMutability::Immutable);
921 }
922
923 #[test]
924 fn try_mut_from() {
925 let value = ValueContainer::from(42);
927 let reference = Reference::try_mut_from(value).unwrap();
928 assert_eq!(reference.mutability(), ReferenceMutability::Mutable);
929
930 let type_value = ValueContainer::Reference(Reference::TypeReference(
932 TypeReference::anonymous(Type::UNIT, None).as_ref_cell(),
933 ));
934 assert_matches!(
935 Reference::try_mut_from(type_value),
936 Err(ReferenceCreationError::MutableTypeReference)
937 );
938 }
939
940 #[test]
941 fn property() {
942 let mut map = Map::default();
943 map.set("name", ValueContainer::from("Jonas"));
944 map.set("age", ValueContainer::from(30));
945 let reference = Reference::from(ValueContainer::from(map));
946 assert_eq!(
947 reference.try_get_property("name").unwrap(),
948 ValueContainer::from("Jonas")
949 );
950 assert_eq!(
951 reference.try_get_property("age").unwrap(),
952 ValueContainer::from(30)
953 );
954 assert!(reference.try_get_property("nonexistent").is_err());
955 assert_matches!(
956 reference.try_get_property("nonexistent"),
957 Err(AccessError::PropertyNotFound(_))
958 );
959 }
960
961 #[test]
962 fn text_property() {
963 let struct_val = Map::from(vec![
964 ("name".to_string(), ValueContainer::from("Jonas")),
965 ("age".to_string(), ValueContainer::from(30)),
966 ]);
967 let reference = Reference::from(ValueContainer::from(struct_val));
968 assert_eq!(
969 reference.try_get_text_property("name").unwrap(),
970 ValueContainer::from("Jonas")
971 );
972 assert_eq!(
973 reference.try_get_text_property("age").unwrap(),
974 ValueContainer::from(30)
975 );
976 assert!(reference.try_get_text_property("nonexistent").is_err());
977 assert_matches!(
978 reference.try_get_text_property("nonexistent"),
979 Err(AccessError::PropertyNotFound(_))
980 );
981 }
982
983 #[test]
984 fn numeric_property() {
985 let list = vec![
986 ValueContainer::from(1),
987 ValueContainer::from(2),
988 ValueContainer::from(3),
989 ];
990 let reference = Reference::from(ValueContainer::from(list));
991
992 assert_eq!(
993 reference.get_numeric_property(0).unwrap(),
994 ValueContainer::from(1)
995 );
996 assert_eq!(
997 reference.get_numeric_property(1).unwrap(),
998 ValueContainer::from(2)
999 );
1000 assert_eq!(
1001 reference.get_numeric_property(2).unwrap(),
1002 ValueContainer::from(3)
1003 );
1004 assert!(reference.get_numeric_property(3).is_err());
1005
1006 assert_matches!(
1007 reference.get_numeric_property(100),
1008 Err(AccessError::IndexOutOfBounds(100))
1009 );
1010
1011 let text_ref = Reference::from(ValueContainer::from("hello"));
1012 assert_eq!(
1013 text_ref.get_numeric_property(1).unwrap(),
1014 ValueContainer::from("e".to_string())
1015 );
1016 assert!(text_ref.get_numeric_property(5).is_err());
1017 assert_matches!(
1018 text_ref.get_numeric_property(100),
1019 Err(AccessError::IndexOutOfBounds(100))
1020 );
1021 }
1022
1023 #[test]
1024 fn reference_identity() {
1025 let value = 42;
1026 let reference1 = Reference::from(value);
1027 let reference2 = reference1.clone();
1028
1029 assert_eq!(reference1, reference2);
1031 assert_eq!(
1033 ValueContainer::Reference(reference1.clone()),
1034 ValueContainer::Reference(reference2.clone())
1035 );
1036 assert_identical!(reference1.clone(), reference2);
1038 assert_ne!(reference1, Reference::from(value));
1040 }
1041
1042 #[test]
1043 fn reference_value_equality() {
1044 let value = 42;
1045 let reference1 = ValueContainer::Reference(Reference::from(value));
1046 let reference2 = ValueContainer::Reference(Reference::from(value));
1047
1048 assert_ne!(reference1, reference2);
1050 assert_value_eq!(reference1, ValueContainer::from(value));
1052 }
1053
1054 #[test]
1055 fn reference_structural_equality() {
1056 let reference1 = Reference::from(42.0);
1057 let reference2 = Reference::from(42);
1058
1059 assert_ne!(reference1, reference2);
1061 assert!(!reference1.structural_eq(&reference2));
1063 }
1064
1065 #[test]
1066 fn nested_references() {
1067 set_global_context(GlobalContext::native());
1068 let memory = &RefCell::new(Memory::default());
1069
1070 let mut map_a = Map::default();
1071 map_a.set("number", ValueContainer::from(42));
1072 map_a.set("obj", ValueContainer::new_reference(Map::default()));
1073
1074 let map_a_val = ValueContainer::new_value(map_a);
1076
1077 let map_b_ref = Reference::try_new_from_value_container(
1079 Map::default().into(),
1080 None,
1081 None,
1082 ReferenceMutability::Mutable,
1083 )
1084 .unwrap();
1085
1086 map_b_ref
1089 .try_set_property(0, "a".into(), map_a_val.clone(), memory)
1090 .unwrap();
1091
1092 let map_a_ref = map_b_ref.try_get_property("a").unwrap();
1094 assert_structural_eq!(map_a_ref, map_a_val);
1095 assert_matches!(map_a_ref, ValueContainer::Reference(_));
1097 map_a_ref.with_maybe_reference(|a_ref| {
1098 assert_matches!(
1100 a_ref.try_get_property("number"),
1101 Ok(ValueContainer::Value(_))
1102 );
1103 assert_matches!(
1105 a_ref.try_get_property("obj"),
1106 Ok(ValueContainer::Reference(_))
1107 );
1108 });
1109 }
1110}