1use crate::{
8 identifier::LocIdent,
9 impl_display_from_pretty,
10 label::Label,
11 metrics::increment,
12 position::{PosIdx, PosTable, TermPos},
13 term::{
14 ForeignIdPayload, IndexMap, Number, RecordOpKind, RuntimeContract, SealingKey, Term,
15 record::Field, string::NickelString,
16 },
17 traverse::{Traverse, TraverseControl, TraverseOrder},
18 typ::Type,
19};
20
21use malachite::base::num::conversion::traits::ToSci as _;
22use nickel_lang_vector::Slice;
23use std::{
24 alloc::{Layout, alloc, dealloc},
25 borrow::ToOwned,
26 cell::{Cell, RefCell},
27 convert::Infallible,
28 fmt,
29 mem::{ManuallyDrop, size_of, transmute},
30 num::NonZero,
31 ptr::{self, NonNull},
32};
33
34pub use super::cache::lazy::{self, Thunk};
35pub use crate::term::record::RecordData;
36
37pub mod lens;
38
39pub type Array = Slice<NickelValue, 32>;
41
42#[derive(Clone, Copy, Debug, Eq, PartialEq)]
44pub struct TagMismatchError;
45
46#[derive(Eq)]
52pub struct NickelValue {
53 data: NonNull<u8>,
72 #[cfg(not(target_pointer_width = "64"))]
75 pos_idx: PosIdx,
76}
77
78impl PartialEq for NickelValue {
82 fn eq(&self, other: &Self) -> bool {
83 match (self.content_ref(), other.content_ref()) {
84 (ValueContentRef::Null, ValueContentRef::Null) => true,
85 (ValueContentRef::Bool(b1), ValueContentRef::Bool(b2)) => b1 == b2,
86
87 (ValueContentRef::Number(number1), ValueContentRef::Number(number2)) => {
88 number1 == number2
89 }
90 (ValueContentRef::Array(array1), ValueContentRef::Array(array2)) => array1 == array2,
91 (ValueContentRef::Record(record1), ValueContentRef::Record(record2)) => {
92 record1 == record2
93 }
94 (ValueContentRef::String(string1), ValueContentRef::String(string2)) => {
95 string1 == string2
96 }
97 (ValueContentRef::Thunk(thunk1), ValueContentRef::Thunk(thunk2)) => {
98 *thunk1.borrow() == *thunk2.borrow()
99 }
100 (ValueContentRef::Term(term1), ValueContentRef::Term(term2)) => term1 == term2,
101 (ValueContentRef::Label(label1), ValueContentRef::Label(label2)) => label1 == label2,
102 (
103 ValueContentRef::EnumVariant(enum_variant1),
104 ValueContentRef::EnumVariant(enum_variant2),
105 ) => enum_variant1 == enum_variant2,
106 (ValueContentRef::ForeignId(foreign_id1), ValueContentRef::ForeignId(foreign_id2)) => {
107 foreign_id1 == foreign_id2
108 }
109 (
110 ValueContentRef::SealingKey(sealing_key1),
111 ValueContentRef::SealingKey(sealing_key2),
112 ) => sealing_key1 == sealing_key2,
113 (
114 ValueContentRef::CustomContract(custom_contract1),
115 ValueContentRef::CustomContract(custom_contract2),
116 ) => custom_contract1 == custom_contract2,
117 (ValueContentRef::Type(type1), ValueContentRef::Type(type2)) => type1 == type2,
118 _ => false,
119 }
120 }
121}
122
123impl fmt::Debug for NickelValue {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "NickelValue {{ pos_idx: {:?}, data: ", self.pos_idx())?;
126
127 match self.content_ref() {
128 ValueContentRef::Null => write!(f, "InlineValue(null)"),
129 ValueContentRef::Bool(b) => write!(f, "InlineValue({b})"),
130 ValueContentRef::Number(number) => write!(f, "Number({number})"),
131 ValueContentRef::Array(container) => write!(f, "Array({container:?})"),
132 ValueContentRef::Record(container) => write!(f, "Record({container:?})"),
133 ValueContentRef::String(string) => write!(f, "String({string})"),
134 ValueContentRef::Thunk(thunk) => write!(f, "Thunk({:?})", thunk.borrow()),
135 ValueContentRef::Term(term) => write!(f, "Term({term:?})"),
136 ValueContentRef::Label(label) => write!(f, "Label({label:?})"),
137 ValueContentRef::EnumVariant(enum_variant_data) => {
138 write!(f, "EnumVariant({enum_variant_data:?})")
139 }
140 ValueContentRef::ForeignId(foreign_id) => {
141 write!(f, "ForeignId({foreign_id:?})")
142 }
143 ValueContentRef::SealingKey(sealing_key) => {
144 write!(f, "SealingKey({sealing_key:?})")
145 }
146 ValueContentRef::CustomContract(custom_contract) => {
147 write!(f, "CustomContract({custom_contract:?})")
148 }
149 ValueContentRef::Type(type_data) => write!(f, "Type({type_data:?})"),
150 }?;
151
152 write!(f, "}}")
153 }
154}
155
156impl std::fmt::Pointer for NickelValue {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 if self.is_inline() {
159 write!(f, "<inline>")
160 } else {
161 std::fmt::Pointer::fmt(&self.data, f)
162 }
163 }
164}
165
166#[cfg(target_pointer_width = "64")]
168impl NickelValue {
169 const INLINE_POS_IDX_MASK: usize = 0xFF_FF_FF_FF_00_00_00_00;
171
172 fn with_inline_pos_idx(mut self, idx: PosIdx) -> Self {
175 if self.tag() == ValueTag::Inline {
176 unsafe {
177 self.data = self.data.map_addr(|data| {
178 NonZero::new_unchecked(
181 (usize::from(data) & !Self::INLINE_POS_IDX_MASK) | (usize::from(idx) << 32),
182 )
183 });
184 }
185 }
186 self
187 }
188
189 #[inline]
191 fn inline_pos_idx(&self) -> Option<PosIdx> {
192 (self.tag() == ValueTag::Inline).then(|| {
193 PosIdx::from_usize_truncate((self.as_usize() & Self::INLINE_POS_IDX_MASK) >> 32)
194 })
195 }
196
197 #[inline]
199 pub const fn inline(inline: InlineValue, idx: PosIdx) -> Self {
200 NickelValue {
201 data: NonNull::without_provenance(unsafe {
204 NonZero::new_unchecked(inline as usize | (idx.to_usize() << 32))
205 }),
206 }
207 }
208
209 #[inline]
215 pub unsafe fn as_inline_unchecked(&self) -> InlineValue {
216 unsafe {
223 transmute::<u32, InlineValue>((self.as_usize() & !Self::INLINE_POS_IDX_MASK) as u32)
224 }
225 }
226
227 #[inline]
237 unsafe fn raw_copy(other: &Self) -> Self {
238 NickelValue { data: other.data }
239 }
240
241 #[inline]
251 unsafe fn block(data: NonNull<u8>) -> Self {
252 NickelValue { data }
253 }
254}
255
256#[cfg(not(target_pointer_width = "64"))]
258impl NickelValue {
259 #[inline]
262 fn with_inline_pos_idx(mut self, idx: PosIdx) -> Self {
263 self.pos_idx = idx;
266 self
267 }
268
269 fn inline_pos_idx(&self) -> Option<PosIdx> {
271 if self.tag() == ValueTag::Inline {
272 Some(self.pos_idx)
273 } else {
274 None
275 }
276 }
277
278 #[inline]
280 pub const fn inline(inline: InlineValue, pos_idx: PosIdx) -> Self {
281 NickelValue {
282 data: unsafe { NonNull::without_provenance(NonZero::new_unchecked(inline as usize)) },
285 pos_idx,
286 }
287 }
288
289 #[inline]
295 pub unsafe fn as_inline_unchecked(&self) -> InlineValue {
296 unsafe { transmute::<usize, InlineValue>(self.as_usize()) }
300 }
301
302 #[inline]
312 unsafe fn raw_copy(other: &Self) -> Self {
313 NickelValue {
314 data: other.data,
315 pos_idx: other.pos_idx,
316 }
317 }
318
319 #[inline]
330 unsafe fn block(data: NonNull<u8>) -> Self {
331 NickelValue {
332 data,
333 pos_idx: PosIdx::NONE,
334 }
335 }
336}
337
338impl NickelValue {
339 const VALUE_TAG_MASK: usize = 0b11;
341
342 #[inline]
345 fn as_usize(&self) -> usize {
346 self.data.addr().into()
347 }
348
349 #[inline]
355 unsafe fn header(&self) -> &ValueBlockHeader {
356 unsafe { ValueBlockRc::header_from_raw(self.data) }
359 }
360
361 #[inline]
363 pub fn tag(&self) -> ValueTag {
364 (self.as_usize() & Self::VALUE_TAG_MASK).try_into().unwrap()
365 }
366
367 #[inline]
370 pub const fn inline_posless(inline: InlineValue) -> Self {
371 Self::inline(inline, PosIdx::NONE)
372 }
373
374 #[inline]
376 pub const fn null() -> Self {
377 Self::inline_posless(InlineValue::Null)
378 }
379
380 #[inline]
382 pub const fn bool_true() -> Self {
383 Self::inline_posless(InlineValue::True)
384 }
385
386 #[inline]
388 pub const fn bool_false() -> Self {
389 Self::inline_posless(InlineValue::False)
390 }
391
392 pub fn bool_value(value: bool, pos_idx: PosIdx) -> Self {
394 if value {
395 Self::inline(InlineValue::True, pos_idx)
396 } else {
397 Self::inline(InlineValue::False, pos_idx)
398 }
399 }
400
401 #[inline]
403 pub fn bool_value_posless(value: bool) -> Self {
404 Self::bool_value(value, PosIdx::NONE)
405 }
406
407 #[inline]
409 pub const fn empty_array() -> Self {
410 Self::inline_posless(InlineValue::EmptyArray)
411 }
412
413 #[inline]
415 pub const fn empty_record() -> Self {
416 Self::inline_posless(InlineValue::EmptyRecord)
417 }
418
419 #[inline]
421 pub fn number(value: impl Into<Number>, pos_idx: PosIdx) -> Self {
422 ValueBlockRc::encode(value.into(), pos_idx).into()
423 }
424
425 #[inline]
428 pub fn number_posless(value: impl Into<Number>) -> Self {
429 Self::number(value, PosIdx::NONE)
430 }
431
432 #[inline]
434 pub fn string(value: impl Into<NickelString>, pos_idx: PosIdx) -> Self {
435 ValueBlockRc::encode(value.into(), pos_idx).into()
436 }
437
438 #[inline]
441 pub fn string_posless(value: impl Into<NickelString>) -> Self {
442 Self::string(value, PosIdx::NONE)
443 }
444
445 pub fn array(value: Array, pending_contracts: Vec<RuntimeContract>, pos_idx: PosIdx) -> Self {
448 if value.is_empty() {
449 Self::inline(InlineValue::EmptyArray, pos_idx)
450 } else {
451 ValueBlockRc::encode(
452 ArrayData {
453 array: value,
454 pending_contracts,
455 },
456 pos_idx,
457 )
458 .into()
459 }
460 }
461
462 #[inline]
465 pub fn array_posless(value: Array, pending_contracts: Vec<RuntimeContract>) -> Self {
466 Self::array(value, pending_contracts, PosIdx::NONE)
467 }
468
469 #[inline]
473 pub fn empty_array_block(pos_idx: PosIdx) -> Self {
474 ValueBlockRc::encode(ArrayData::default(), pos_idx).into()
475 }
476
477 pub fn record(value: RecordData, pos_idx: PosIdx) -> Self {
480 if value.is_empty() && !value.attrs.open {
483 Self::inline(InlineValue::EmptyRecord, pos_idx)
484 } else {
485 ValueBlockRc::encode(value, pos_idx).into()
486 }
487 }
488
489 pub fn record_posless(value: RecordData) -> Self {
492 if value.is_empty() {
493 Self::empty_record()
494 } else {
495 ValueBlockRc::encode(value, PosIdx::NONE).into()
496 }
497 }
498
499 #[inline]
503 pub fn empty_record_block(pos_idx: PosIdx) -> Self {
504 ValueBlockRc::encode(RecordData::empty(), pos_idx).into()
505 }
506
507 #[inline]
509 pub fn thunk(data: lazy::ThunkData, pos_idx: PosIdx) -> Self {
510 ValueBlockRc::encode(RefCell::new(data), pos_idx).into()
511 }
512
513 #[inline]
516 pub fn thunk_posless(data: lazy::ThunkData) -> Self {
517 Self::thunk(data, PosIdx::NONE)
518 }
519
520 #[inline]
522 pub fn term(value: Term, pos_idx: PosIdx) -> Self {
523 ValueBlockRc::encode(value, pos_idx).into()
524 }
525
526 #[inline]
529 pub fn term_posless(value: Term) -> Self {
530 Self::term(value, PosIdx::NONE)
531 }
532
533 #[inline]
535 pub fn label(value: Label, pos_idx: PosIdx) -> Self {
536 ValueBlockRc::encode(value, pos_idx).into()
537 }
538
539 #[inline]
542 pub fn label_posless(value: Label) -> Self {
543 Self::label(value, PosIdx::NONE)
544 }
545
546 pub fn enum_variant(
548 tag: impl Into<LocIdent>,
549 arg: Option<NickelValue>,
550 pos_idx: PosIdx,
551 ) -> Self {
552 ValueBlockRc::encode(
553 EnumVariantData {
554 tag: tag.into(),
555 arg,
556 },
557 pos_idx,
558 )
559 .into()
560 }
561
562 #[inline]
565 pub fn enum_variant_posless(tag: impl Into<LocIdent>, arg: Option<NickelValue>) -> Self {
566 Self::enum_variant(tag.into(), arg, PosIdx::NONE)
567 }
568
569 #[inline]
571 pub fn enum_tag(tag: impl Into<LocIdent>, pos_idx: PosIdx) -> Self {
572 Self::enum_variant(tag.into(), None, pos_idx)
573 }
574
575 #[inline]
578 pub fn enum_tag_posless(tag: impl Into<LocIdent>) -> Self {
579 Self::enum_tag(tag.into(), PosIdx::NONE)
580 }
581
582 #[inline]
584 pub fn foreign_id(value: ForeignIdPayload, pos_idx: PosIdx) -> Self {
585 ValueBlockRc::encode(value, pos_idx).into()
586 }
587
588 #[inline]
591 pub fn foreign_id_posless(value: ForeignIdPayload) -> Self {
592 Self::foreign_id(value, PosIdx::NONE)
593 }
594
595 #[inline]
597 pub fn sealing_key(value: SealingKey, pos_idx: PosIdx) -> Self {
598 ValueBlockRc::encode(value, pos_idx).into()
599 }
600
601 #[inline]
604 pub fn sealing_key_posless(value: SealingKey) -> Self {
605 Self::sealing_key(value, PosIdx::NONE)
606 }
607
608 #[inline]
610 pub fn custom_contract(value: NickelValue, pos_idx: PosIdx) -> Self {
611 ValueBlockRc::encode(value, pos_idx).into()
612 }
613
614 #[inline]
617 pub fn custom_contract_posless(value: NickelValue) -> Self {
618 Self::custom_contract(value, PosIdx::NONE)
619 }
620
621 #[inline]
623 pub fn typ(typ: Type, contract: NickelValue, pos_idx: PosIdx) -> Self {
624 ValueBlockRc::encode(TypeData { typ, contract }, pos_idx).into()
625 }
626
627 #[inline]
629 pub fn as_inline(&self) -> Option<InlineValue> {
630 InlineValue::try_from(self).ok()
631 }
632
633 #[inline]
635 pub fn as_bool(&self) -> Option<bool> {
636 match self.as_inline()? {
637 InlineValue::True => Some(true),
638 InlineValue::False => Some(false),
639 _ => None,
640 }
641 }
642
643 #[inline]
646 pub fn as_number(&self) -> Option<&NumberData> {
647 self.as_value_data()
648 }
649
650 #[inline]
653 pub fn as_string(&self) -> Option<&StringData> {
654 self.as_value_data()
655 }
656
657 #[inline]
660 pub fn as_array(&self) -> Option<Container<&ArrayData>> {
661 if self.is_inline_empty_array() {
662 Some(Container::Empty)
663 } else {
664 self.as_value_data().map(Container::Alloc)
665 }
666 }
667
668 pub fn as_record(&self) -> Option<Container<&RecordData>> {
671 if self.is_inline_empty_record() {
672 Some(Container::Empty)
673 } else {
674 self.as_value_data().map(Container::Alloc)
675 }
676 }
677
678 #[inline]
685 pub unsafe fn as_thunk_data_unchecked(&self) -> &ThunkData {
686 unsafe { ValueBlockRc::decode_from_raw_unchecked(self.data) }
688 }
689
690 pub fn as_thunk(&self) -> Option<&Thunk> {
696 if let Some(DataTag::Thunk) = self.data_tag() {
697 unsafe { Some(self.as_thunk_unchecked()) }
699 } else {
700 None
701 }
702 }
703
704 pub fn try_into_thunk(self) -> Result<Thunk, NickelValue> {
707 if let Some(DataTag::Thunk) = self.data_tag() {
708 Ok(Thunk(self))
709 } else {
710 Err(self)
711 }
712 }
713
714 #[inline]
725 pub(super) unsafe fn as_thunk_unchecked(&self) -> &Thunk {
726 unsafe { transmute::<&NickelValue, &Thunk>(self) }
729 }
730
731 #[inline]
738 pub(super) unsafe fn as_thunk_mut_unchecked(&mut self) -> &mut Thunk {
739 unsafe { transmute::<&mut NickelValue, &mut Thunk>(self) }
742 }
743
744 #[inline]
755 pub(super) unsafe fn into_thunk_unchecked(self) -> Thunk {
756 Thunk(self)
758 }
759
760 #[inline]
763 pub fn as_term(&self) -> Option<&TermData> {
764 self.as_value_data()
765 }
766
767 #[inline]
770 pub fn as_label(&self) -> Option<&LabelData> {
771 self.as_value_data()
772 }
773
774 #[inline]
777 pub fn as_enum_variant(&self) -> Option<&EnumVariantData> {
778 self.as_value_data()
779 }
780
781 pub fn as_enum_tag(&self) -> Option<LocIdent> {
784 let enum_var = self.as_enum_variant()?;
785 enum_var.arg.is_none().then_some(enum_var.tag)
786 }
787
788 #[inline]
791 pub fn as_sealing_key(&self) -> Option<&SealingKeyData> {
792 self.as_value_data()
793 }
794
795 #[inline]
798 pub fn as_type(&self) -> Option<&TypeData> {
799 self.as_value_data()
800 }
801
802 #[inline]
805 pub fn as_foreign_id(&self) -> Option<&ForeignIdData> {
806 self.as_value_data()
807 }
808
809 #[inline]
815 pub fn into_block(self) -> Result<ValueBlockRc, Self> {
816 ValueBlockRc::try_from(self)
817 }
818
819 fn as_value_data<T: ValueBlockData>(&self) -> Option<&T> {
822 if self.tag() == ValueTag::Pointer {
823 unsafe { ValueBlockRc::try_decode_from_raw(self.data) }
829 } else {
830 None
831 }
832 }
833
834 #[inline]
836 pub fn is_inline(&self) -> bool {
837 self.tag() == ValueTag::Inline
838 }
839
840 pub fn content_ref(&self) -> ValueContentRef<'_> {
843 match self.tag() {
844 ValueTag::Pointer => unsafe {
847 let tag = ValueBlockRc::tag_from_raw(self.data);
848
849 match tag {
852 DataTag::Number => {
853 ValueContentRef::Number(ValueBlockRc::decode_from_raw_unchecked(self.data))
854 }
855 DataTag::Array => ValueContentRef::Array(Container::Alloc(
856 ValueBlockRc::decode_from_raw_unchecked(self.data),
857 )),
858 DataTag::Record => ValueContentRef::Record(Container::Alloc(
859 ValueBlockRc::decode_from_raw_unchecked(self.data),
860 )),
861 DataTag::String => {
862 ValueContentRef::String(ValueBlockRc::decode_from_raw_unchecked(self.data))
863 }
864 DataTag::Thunk => {
865 ValueContentRef::Thunk(self.as_thunk_unchecked())
867 }
868 DataTag::Term => {
869 ValueContentRef::Term(ValueBlockRc::decode_from_raw_unchecked(self.data))
870 }
871 DataTag::Label => {
872 ValueContentRef::Label(ValueBlockRc::decode_from_raw_unchecked(self.data))
873 }
874 DataTag::EnumVariant => ValueContentRef::EnumVariant(
875 ValueBlockRc::decode_from_raw_unchecked(self.data),
876 ),
877 DataTag::ForeignId => ValueContentRef::ForeignId(
878 ValueBlockRc::decode_from_raw_unchecked(self.data),
879 ),
880 DataTag::SealingKey => ValueContentRef::SealingKey(
881 ValueBlockRc::decode_from_raw_unchecked(self.data),
882 ),
883 DataTag::CustomContract => ValueContentRef::CustomContract(
884 ValueBlockRc::decode_from_raw_unchecked(self.data),
885 ),
886 DataTag::Type => {
887 ValueContentRef::Type(ValueBlockRc::decode_from_raw_unchecked(self.data))
888 }
889 }
890 },
891 ValueTag::Inline => {
892 match unsafe { self.as_inline_unchecked() } {
894 InlineValue::EmptyArray => ValueContentRef::Array(Container::Empty),
895 InlineValue::EmptyRecord => ValueContentRef::Record(Container::Empty),
896 InlineValue::Null => ValueContentRef::Null,
897 InlineValue::True => ValueContentRef::Bool(true),
898 InlineValue::False => ValueContentRef::Bool(false),
899 }
900 }
901 }
902 }
903
904 pub fn content_mut(&mut self) -> Option<ValueContentRefMut<'_>> {
915 match self.tag() {
916 ValueTag::Pointer => unsafe {
919 let header = self.header();
920
921 if header.ref_count() != 1 && header.tag() != DataTag::Thunk {
926 return None;
927 }
928
929 Some(match header.tag() {
935 DataTag::Number => ValueContentRefMut::Number(
936 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
937 ),
938 DataTag::Array => ValueContentRefMut::Array(Container::Alloc(
939 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
940 )),
941 DataTag::Record => ValueContentRefMut::Record(Container::Alloc(
942 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
943 )),
944 DataTag::String => ValueContentRefMut::String(
945 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
946 ),
947 DataTag::Thunk => ValueContentRefMut::Thunk(self.as_thunk_mut_unchecked()),
950 DataTag::Term => ValueContentRefMut::Term(
951 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
952 ),
953 DataTag::Label => ValueContentRefMut::Label(
954 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
955 ),
956 DataTag::EnumVariant => ValueContentRefMut::EnumVariant(
957 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
958 ),
959 DataTag::ForeignId => ValueContentRefMut::ForeignId(
960 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
961 ),
962 DataTag::SealingKey => ValueContentRefMut::SealingKey(
963 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
964 ),
965 DataTag::CustomContract => ValueContentRefMut::CustomContract(
966 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
967 ),
968 DataTag::Type => ValueContentRefMut::Type(
969 ValueBlockRc::decode_mut_from_raw_unchecked(self.data),
970 ),
971 })
972 },
973 ValueTag::Inline => {
974 Some(match unsafe { self.as_inline_unchecked() } {
976 InlineValue::EmptyArray => ValueContentRefMut::Array(Container::Empty),
977 InlineValue::EmptyRecord => ValueContentRefMut::Record(Container::Empty),
978 InlineValue::Null => ValueContentRefMut::Null(self),
979 InlineValue::True => ValueContentRefMut::Bool(self),
980 InlineValue::False => ValueContentRefMut::Bool(self),
981 })
982 }
983 }
984 }
985
986 pub fn content(self) -> ValueContent {
988 use lens::{TermContent, ValueLens};
989
990 match self.tag() {
991 ValueTag::Pointer => {
992 unsafe {
995 match self.header().tag() {
998 DataTag::Number => ValueContent::Number(ValueLens::content_lens(self)),
999 DataTag::Array => ValueContent::Array(ValueLens::container_lens(self)),
1000 DataTag::Record => ValueContent::Record(ValueLens::container_lens(self)),
1001 DataTag::String => ValueContent::String(ValueLens::content_lens(self)),
1002 DataTag::Thunk => ValueContent::Thunk(ValueLens::thunk_lens(self)),
1003 DataTag::Term => {
1004 let term: &TermData =
1005 ValueBlockRc::decode_from_raw_unchecked(self.data);
1006
1007 ValueContent::Term(match term {
1008 Term::StrChunks(_) => {
1009 TermContent::StrChunks(ValueLens::term_str_chunks_lens(self))
1010 }
1011 Term::Fun(..) => TermContent::Fun(ValueLens::term_fun_lens(self)),
1012 Term::Let(..) => TermContent::Let(ValueLens::term_let_lens(self)),
1013 Term::App(..) => TermContent::App(ValueLens::term_app_lens(self)),
1014 Term::Var(..) => TermContent::Var(ValueLens::term_var_lens(self)),
1015 Term::RecRecord(..) => {
1016 TermContent::RecRecord(ValueLens::term_rec_record_lens(self))
1017 }
1018 Term::Closurize(_) => {
1019 TermContent::Closurize(ValueLens::term_closurize_lens(self))
1020 }
1021 Term::Op1(..) => TermContent::Op1(ValueLens::term_op1_lens(self)),
1022 Term::Op2(..) => TermContent::Op2(ValueLens::term_op2_lens(self)),
1023 Term::OpN(..) => TermContent::OpN(ValueLens::term_opn_lens(self)),
1024 Term::Sealed(..) => {
1025 TermContent::Sealed(ValueLens::term_sealed_lens(self))
1026 }
1027 Term::Annotated(..) => {
1028 TermContent::Annotated(ValueLens::term_annotated_lens(self))
1029 }
1030 Term::Import(_) => {
1031 TermContent::Import(ValueLens::term_import_lens(self))
1032 }
1033 Term::ResolvedImport(_) => TermContent::ResolvedImport(
1034 ValueLens::term_resolved_import_lens(self),
1035 ),
1036 Term::ParseError(_) => {
1037 TermContent::ParseError(ValueLens::term_parse_error_lens(self))
1038 }
1039 Term::RuntimeError(_) => TermContent::RuntimeError(
1040 ValueLens::term_runtime_error_lens(self),
1041 ),
1042 })
1043 }
1044 DataTag::Label => ValueContent::Label(ValueLens::content_lens(self)),
1045 DataTag::EnumVariant => {
1046 ValueContent::EnumVariant(ValueLens::content_lens(self))
1047 }
1048 DataTag::ForeignId => {
1049 ValueContent::ForeignId(ValueLens::content_lens(self))
1050 }
1051 DataTag::SealingKey => {
1052 ValueContent::SealingKey(ValueLens::content_lens(self))
1053 }
1054 DataTag::CustomContract => {
1055 ValueContent::CustomContract(ValueLens::content_lens(self))
1056 }
1057 DataTag::Type => ValueContent::Type(ValueLens::content_lens(self)),
1058 }
1059 }
1060 }
1061 ValueTag::Inline => {
1062 unsafe {
1069 match self.as_inline_unchecked() {
1070 InlineValue::Null => ValueContent::Null(ValueLens::null_lens(self)),
1071 InlineValue::True | InlineValue::False => {
1072 ValueContent::Bool(ValueLens::bool_lens(self))
1073 }
1074 InlineValue::EmptyArray => {
1075 ValueContent::Array(ValueLens::container_lens(self))
1076 }
1077 InlineValue::EmptyRecord => {
1078 ValueContent::Record(ValueLens::container_lens(self))
1079 }
1080 }
1081 }
1082 }
1083 }
1084 }
1085
1086 pub fn content_make_mut(&mut self) -> ValueContentRefMut<'_> {
1093 unsafe fn make_mut<T: ValueBlockData + Clone>(value: &mut NickelValue) -> &mut T {
1095 unsafe {
1096 if value.header().ref_count() != 1 {
1097 increment!("value::content_make_mut::strong clone");
1098 *value = ValueBlockRc::encode(
1101 ValueBlockRc::decode_from_raw_unchecked::<T>(value.data).clone(),
1103 value.header().pos_idx,
1104 )
1105 .into();
1106 } else {
1107 increment!("value::content_make_mut::no clone");
1108 }
1109
1110 ValueBlockRc::decode_mut_from_raw_unchecked::<T>(value.data)
1112 }
1113 }
1114
1115 match self.tag() {
1116 ValueTag::Pointer => unsafe {
1119 let tag = ValueBlockRc::tag_from_raw(self.data);
1120
1121 match tag {
1122 DataTag::Number => ValueContentRefMut::Number(make_mut(self)),
1123 DataTag::Array => ValueContentRefMut::Array(Container::Alloc(make_mut(self))),
1124 DataTag::Record => ValueContentRefMut::Record(Container::Alloc(make_mut(self))),
1125 DataTag::String => ValueContentRefMut::String(make_mut(self)),
1126 DataTag::Thunk => {
1128 ValueContentRefMut::Thunk(self.as_thunk_mut_unchecked())
1130 }
1131 DataTag::Term => ValueContentRefMut::Term(make_mut(self)),
1132 DataTag::Label => ValueContentRefMut::Label(make_mut(self)),
1133 DataTag::EnumVariant => ValueContentRefMut::EnumVariant(make_mut(self)),
1134 DataTag::ForeignId => ValueContentRefMut::ForeignId(make_mut(self)),
1135 DataTag::SealingKey => ValueContentRefMut::SealingKey(make_mut(self)),
1136 DataTag::CustomContract => ValueContentRefMut::CustomContract(make_mut(self)),
1137 DataTag::Type => ValueContentRefMut::Type(make_mut(self)),
1138 }
1139 },
1140 ValueTag::Inline => {
1141 match unsafe { self.as_inline_unchecked() } {
1143 InlineValue::Null => ValueContentRefMut::Null(self),
1144 InlineValue::True | InlineValue::False => ValueContentRefMut::Bool(self),
1145 InlineValue::EmptyArray => ValueContentRefMut::Array(Container::Empty),
1146 InlineValue::EmptyRecord => ValueContentRefMut::Record(Container::Empty),
1147 }
1148 }
1149 }
1150 }
1151
1152 pub fn data_tag(&self) -> Option<DataTag> {
1154 (self.tag() == ValueTag::Pointer).then(|| {
1155 unsafe { ValueBlockRc::tag_from_raw(self.data) }
1158 })
1159 }
1160
1161 pub fn is_inline_empty_array(&self) -> bool {
1165 self.as_inline()
1166 .is_some_and(|inl| matches!(inl, InlineValue::EmptyArray))
1167 }
1168
1169 pub fn is_inline_empty_record(&self) -> bool {
1173 self.as_inline()
1174 .is_some_and(|inl| matches!(inl, InlineValue::EmptyRecord))
1175 }
1176
1177 pub fn is_bool_true(&self) -> bool {
1179 self.as_inline()
1180 .is_some_and(|inl| matches!(inl, InlineValue::True))
1181 }
1182
1183 pub fn is_bool_false(&self) -> bool {
1185 self.as_inline()
1186 .is_some_and(|inl| matches!(inl, InlineValue::False))
1187 }
1188
1189 pub fn is_null(&self) -> bool {
1191 self.as_inline()
1192 .is_some_and(|inl| matches!(inl, InlineValue::Null))
1193 }
1194
1195 #[inline]
1198 pub fn is_whnf(&self) -> bool {
1199 !matches!(self.data_tag(), Some(DataTag::Thunk | DataTag::Term))
1200 }
1201
1202 pub fn type_of(&self) -> Option<&'static str> {
1209 match self.content_ref() {
1210 ValueContentRef::Null => Some("Other"),
1211 ValueContentRef::Bool(_) => Some("Bool"),
1212 ValueContentRef::Number(_) => Some("Number"),
1213 ValueContentRef::Array(_) => Some("Array"),
1214 ValueContentRef::Record(_) => Some("Record"),
1215 ValueContentRef::String(_) => Some("String"),
1216 ValueContentRef::Term(term) => match term {
1217 Term::Closurize(v) => v.type_of(),
1218 Term::RecRecord(..) => Some("Record"),
1219 Term::Fun(..) => Some("Function"),
1220 Term::Sealed(..) => Some("Sealed"),
1221 Term::Annotated(..) => Some("Annotated"),
1222 Term::Let(..)
1223 | Term::App(_)
1224 | Term::Var(_)
1225 | Term::Op1(_)
1226 | Term::Op2(_)
1227 | Term::OpN(_)
1228 | Term::Import(_)
1229 | Term::ResolvedImport(_)
1230 | Term::StrChunks(_)
1231 | Term::ParseError(_)
1232 | Term::RuntimeError(_) => None,
1233 },
1234 ValueContentRef::Label(_) => Some("Label"),
1235 ValueContentRef::EnumVariant(EnumVariantData { arg: None, tag: _ }) => Some("EnumTag"),
1236 ValueContentRef::EnumVariant(EnumVariantData {
1237 arg: Some(_),
1238 tag: _,
1239 }) => Some("EnumVariant"),
1240 ValueContentRef::ForeignId(_) => Some("ForeignId"),
1241 ValueContentRef::SealingKey(_) => Some("SealingKey"),
1242 ValueContentRef::CustomContract(_) => Some("CustomContract"),
1243 ValueContentRef::Type(_) => Some("Type"),
1244 _ => None,
1245 }
1246 }
1247
1248 pub fn is_constant(&self) -> bool {
1254 match self.content_ref() {
1255 ValueContentRef::Null
1256 | ValueContentRef::Bool(_)
1257 | ValueContentRef::Array(Container::Empty)
1258 | ValueContentRef::Record(Container::Empty)
1259 | ValueContentRef::Number(_)
1260 | ValueContentRef::Label(_)
1261 | ValueContentRef::ForeignId(_)
1262 | ValueContentRef::SealingKey(_)
1263 | ValueContentRef::String(_) => true,
1264 ValueContentRef::EnumVariant(enum_variant) => enum_variant.arg.is_none(),
1265 ValueContentRef::Array(_)
1266 | ValueContentRef::Record(_)
1267 | ValueContentRef::Thunk(_)
1268 | ValueContentRef::Term(_)
1269 | ValueContentRef::CustomContract(_)
1270 | ValueContentRef::Type(_) => false,
1271 }
1272 }
1273
1274 pub fn fmt_is_atom(&self) -> bool {
1277 let Some(data_tag) = self.data_tag() else {
1278 return true;
1282 };
1283
1284 match data_tag {
1285 DataTag::Array
1286 | DataTag::Record
1287 | DataTag::ForeignId
1288 | DataTag::SealingKey
1289 | DataTag::Label
1290 | DataTag::String => true,
1291 DataTag::Number => self.as_value_data::<NumberData>().unwrap() >= &0,
1292 DataTag::EnumVariant => self
1293 .as_value_data::<EnumVariantData>()
1294 .unwrap()
1295 .arg
1296 .is_none(),
1297 DataTag::Thunk => false,
1298 DataTag::Term => self.as_value_data::<TermData>().unwrap().fmt_is_atom(),
1299 DataTag::CustomContract => self
1300 .as_value_data::<CustomContractData>()
1301 .unwrap()
1302 .fmt_is_atom(),
1303 DataTag::Type => self.as_value_data::<TypeData>().unwrap().typ.fmt_is_atom(),
1304 }
1305 }
1306
1307 pub fn to_nickel_string(&self) -> Option<NickelString> {
1310 match self.content_ref() {
1311 ValueContentRef::Null => Some("null".into()),
1312 ValueContentRef::Bool(b) => Some(b.to_string().into()),
1313 ValueContentRef::String(s) => Some(s.clone()),
1314 ValueContentRef::EnumVariant(EnumVariantData { tag, arg: None }) => Some((*tag).into()),
1315 ValueContentRef::Number(n) => Some(format!("{}", n.to_sci()).into()),
1316 _ => None,
1317 }
1318 }
1319
1320 pub fn phys_eq(&self, other: &Self) -> bool {
1326 match self.tag() {
1327 ValueTag::Pointer => self.data == other.data,
1328 ValueTag::Inline => {
1330 other.is_inline()
1331 && unsafe {
1332 self.as_inline_unchecked() == other.as_inline_unchecked()
1335 }
1336 }
1337 }
1338 }
1339
1340 #[inline]
1343 pub fn with_pos(self, pos_table: &mut PosTable, pos: TermPos) -> Self {
1344 self.with_pos_idx(pos_table.push(pos))
1345 }
1346
1347 pub fn with_pos_idx(self, pos_idx: PosIdx) -> Self {
1351 match self.tag() {
1352 ValueTag::Pointer => {
1353 let mut block: ValueBlockRc = self.try_into().unwrap();
1355 block.make_unique();
1356 unsafe { block.0.cast::<ValueBlockHeader>().as_mut().pos_idx = pos_idx }
1359 block.into()
1360 }
1361 ValueTag::Inline => self.with_inline_pos_idx(pos_idx),
1363 }
1364 }
1365
1366 pub fn pos_idx(&self) -> PosIdx {
1368 match self.tag() {
1369 ValueTag::Pointer => unsafe { self.header().pos_idx },
1372 ValueTag::Inline => self.inline_pos_idx().unwrap(),
1374 }
1375 }
1376
1377 #[inline]
1379 pub fn pos(&self, table: &PosTable) -> TermPos {
1380 table.get(self.pos_idx())
1381 }
1382
1383 pub fn without_pos(self) -> Self {
1389 self.traverse(
1390 &mut |t: Type| {
1391 Ok::<_, Infallible>(Type {
1392 pos: TermPos::None,
1393 ..t
1394 })
1395 },
1396 TraverseOrder::BottomUp,
1397 )
1398 .unwrap()
1399 .traverse(
1400 &mut |val: NickelValue| {
1401 Ok::<_, Infallible>(val.with_pos_idx(PosIdx::NONE))
1403 },
1404 TraverseOrder::BottomUp,
1405 )
1406 .unwrap()
1407 }
1408}
1409
1410impl Default for NickelValue {
1411 #[inline]
1412 fn default() -> Self {
1413 Self::null()
1414 }
1415}
1416
1417impl Clone for NickelValue {
1420 #[inline]
1421 fn clone(&self) -> Self {
1422 if self.tag() == ValueTag::Pointer {
1423 unsafe {
1424 self.header().inc_ref_count();
1429 }
1430 }
1431
1432 unsafe { NickelValue::raw_copy(self) }
1434 }
1435}
1436
1437impl Drop for NickelValue {
1440 #[inline]
1441 fn drop(&mut self) {
1442 if self.tag() == ValueTag::Pointer {
1443 unsafe {
1444 let _ = ValueBlockRc::from_raw(self.data);
1447 }
1448 }
1449 }
1450}
1451
1452impl From<InlineValue> for NickelValue {
1453 #[inline]
1454 fn from(inline: InlineValue) -> Self {
1455 NickelValue::inline_posless(inline)
1456 }
1457}
1458
1459impl<'a> TryFrom<&'a NickelValue> for InlineValue {
1460 type Error = TagMismatchError;
1461
1462 fn try_from(value: &'a NickelValue) -> Result<Self, Self::Error> {
1463 if value.tag() == ValueTag::Inline {
1464 unsafe { Ok(value.as_inline_unchecked()) }
1466 } else {
1467 Err(TagMismatchError)
1468 }
1469 }
1470}
1471
1472impl TryFrom<NickelValue> for ValueBlockRc {
1473 type Error = NickelValue;
1475
1476 fn try_from(value: NickelValue) -> Result<Self, Self::Error> {
1477 if value.tag() == ValueTag::Pointer {
1478 Ok(unsafe {
1479 let value = ManuallyDrop::new(value);
1481 ValueBlockRc::from_raw(value.data)
1484 })
1485 } else {
1486 Err(value)
1487 }
1488 }
1489}
1490
1491impl From<ValueBlockRc> for NickelValue {
1492 #[inline]
1496 fn from(block: ValueBlockRc) -> Self {
1497 let this = ManuallyDrop::new(block);
1499 unsafe { NickelValue::block(this.0) }
1502 }
1503}
1504
1505impl_display_from_pretty!(NickelValue);
1506
1507#[repr(usize)]
1509#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1510pub enum ValueTag {
1519 Pointer = 0,
1521 Inline = 1,
1523}
1524
1525impl ValueTag {
1526 pub const MAX: usize = ValueTag::Inline as usize;
1528}
1529
1530impl From<ValueTag> for usize {
1531 #[inline]
1532 fn from(tag: ValueTag) -> Self {
1533 tag as usize
1534 }
1535}
1536
1537#[derive(Clone, Copy, Eq, PartialEq, Debug)]
1539pub struct TagOutOfBoundsError;
1540
1541impl TryFrom<usize> for ValueTag {
1542 type Error = TagOutOfBoundsError;
1543
1544 fn try_from(value: usize) -> Result<Self, Self::Error> {
1545 if value <= ValueTag::MAX {
1546 Ok(unsafe { transmute::<usize, ValueTag>(value) })
1549 } else {
1550 Err(TagOutOfBoundsError)
1551 }
1552 }
1553}
1554
1555const fn tag_inline(inline: u32) -> u32 {
1557 debug_assert!(inline <= (u32::MAX >> 2));
1560 (inline << 2) | (ValueTag::Inline as u32)
1561}
1562
1563#[repr(u32)]
1567#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1568pub enum InlineValue {
1569 Null = tag_inline(0),
1570 True = tag_inline(1),
1571 False = tag_inline(2),
1572 EmptyArray = tag_inline(3),
1573 EmptyRecord = tag_inline(4),
1574}
1575
1576#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1586#[repr(u8)]
1587pub enum DataTag {
1588 Number = 0,
1589 Array = 1,
1590 Record = 2,
1591 String = 3,
1592 Thunk = 4,
1593 Term = 5,
1598 Label = 6,
1599 EnumVariant = 7,
1600 ForeignId = 8,
1601 SealingKey = 9,
1602 CustomContract = 10,
1603 Type = 11,
1604}
1605
1606impl DataTag {
1607 const fn data_offset(&self) -> usize {
1610 match self {
1611 DataTag::Number => ValueBlockRc::data_offset::<NumberData>(),
1612 DataTag::String => ValueBlockRc::data_offset::<StringData>(),
1613 DataTag::Array => ValueBlockRc::data_offset::<ArrayData>(),
1614 DataTag::Record => ValueBlockRc::data_offset::<RecordData>(),
1615 DataTag::Thunk => ValueBlockRc::data_offset::<ThunkData>(),
1616 DataTag::Term => ValueBlockRc::data_offset::<TermData>(),
1617 DataTag::Label => ValueBlockRc::data_offset::<LabelData>(),
1618 DataTag::EnumVariant => ValueBlockRc::data_offset::<EnumVariantData>(),
1619 DataTag::ForeignId => ValueBlockRc::data_offset::<ForeignIdData>(),
1620 DataTag::SealingKey => ValueBlockRc::data_offset::<SealingKeyData>(),
1621 DataTag::CustomContract => ValueBlockRc::data_offset::<CustomContractData>(),
1622 DataTag::Type => ValueBlockRc::data_offset::<TypeData>(),
1623 }
1624 }
1625
1626 const fn block_layout(&self) -> Layout {
1630 match self {
1631 DataTag::Number => ValueBlockRc::block_layout::<NumberData>(),
1632 DataTag::String => ValueBlockRc::block_layout::<StringData>(),
1633 DataTag::Array => ValueBlockRc::block_layout::<ArrayData>(),
1634 DataTag::Record => ValueBlockRc::block_layout::<RecordData>(),
1635 DataTag::Thunk => ValueBlockRc::block_layout::<ThunkData>(),
1636 DataTag::Term => ValueBlockRc::block_layout::<TermData>(),
1637 DataTag::Label => ValueBlockRc::block_layout::<LabelData>(),
1638 DataTag::EnumVariant => ValueBlockRc::block_layout::<EnumVariantData>(),
1639 DataTag::ForeignId => ValueBlockRc::block_layout::<ForeignIdData>(),
1640 DataTag::SealingKey => ValueBlockRc::block_layout::<SealingKeyData>(),
1641 DataTag::CustomContract => ValueBlockRc::block_layout::<CustomContractData>(),
1642 DataTag::Type => ValueBlockRc::block_layout::<TypeData>(),
1643 }
1644 }
1645
1646 const MAX: u8 = DataTag::Type as u8;
1648}
1649
1650impl From<DataTag> for u8 {
1651 #[inline]
1652 fn from(tag: DataTag) -> Self {
1653 tag as u8
1654 }
1655}
1656
1657impl TryFrom<u8> for DataTag {
1658 type Error = TagOutOfBoundsError;
1659
1660 fn try_from(value: u8) -> Result<Self, Self::Error> {
1661 if value <= DataTag::MAX {
1662 Ok(unsafe { transmute::<u8, DataTag>(value) })
1665 } else {
1666 Err(TagOutOfBoundsError)
1667 }
1668 }
1669}
1670
1671#[repr(Rust, align(4))]
1678#[derive(Debug, Clone, PartialEq, Eq)]
1679struct ValueBlockHeader {
1680 tag_and_ref_count: Cell<u64>,
1691 pos_idx: PosIdx,
1693}
1694
1695impl ValueBlockHeader {
1696 const TAG_MASK: u64 = 0xFF_00_00_00_00_00_00_00;
1697 const MAX_REF_COUNT: u64 = 0x00_FF_FF_FF_FF_FF_FF_FF;
1698
1699 const unsafe fn pack(tag: DataTag, ref_count: u64) -> u64 {
1707 ((tag as u64) << 56) | ref_count
1708 }
1709
1710 #[inline]
1712 pub fn tag(&self) -> DataTag {
1713 unsafe { transmute::<u8, DataTag>((self.tag_and_ref_count.get() >> 56) as u8) }
1716 }
1717
1718 #[inline]
1721 pub fn new(tag: DataTag, pos_idx: PosIdx) -> Self {
1722 Self {
1723 tag_and_ref_count: unsafe { Cell::new(Self::pack(tag, 1)) },
1725 pos_idx,
1726 }
1727 }
1728
1729 #[inline]
1730 fn ref_count(&self) -> u64 {
1731 self.tag_and_ref_count.get() & !Self::TAG_MASK
1732 }
1733
1734 #[inline]
1735 fn set_ref_count(&self, count: u64) {
1736 unsafe {
1738 self.tag_and_ref_count.set(Self::pack(self.tag(), count));
1739 }
1740
1741 if count > Self::MAX_REF_COUNT {
1742 panic!("reference count overfow");
1743 }
1744 }
1745
1746 #[inline]
1747 fn inc_ref_count(&self) {
1748 let count = self.ref_count();
1751
1752 unsafe {
1755 std::hint::assert_unchecked(count != 0);
1756 }
1757
1758 self.set_ref_count(count + 1);
1759 }
1760
1761 #[inline]
1762 fn dec_ref_count(&self) {
1763 self.set_ref_count(self.ref_count() - 1);
1764 }
1765}
1766
1767pub trait ValueBlockData {
1769 const TAG: DataTag;
1770}
1771
1772pub type NumberData = Number;
1773pub type StringData = NickelString;
1774
1775#[derive(Clone, Debug, PartialEq, Default)]
1776pub struct ArrayData {
1777 pub array: Array,
1778 pub pending_contracts: Vec<RuntimeContract>,
1782}
1783
1784pub type ThunkData = RefCell<lazy::ThunkData>;
1785pub type TermData = Term;
1786pub type LabelData = Label;
1787
1788#[derive(Clone, Debug, PartialEq)]
1789pub struct EnumVariantData {
1790 pub tag: LocIdent,
1791 pub arg: Option<NickelValue>,
1792}
1793
1794pub type ForeignIdData = ForeignIdPayload;
1795pub type CustomContractData = NickelValue;
1796pub type SealingKeyData = SealingKey;
1797
1798#[derive(Clone, Debug, PartialEq)]
1799pub struct TypeData {
1800 pub typ: Type,
1802 pub contract: NickelValue,
1806}
1807
1808impl ValueBlockData for NumberData {
1809 const TAG: DataTag = DataTag::Number;
1810}
1811
1812impl ValueBlockData for ArrayData {
1813 const TAG: DataTag = DataTag::Array;
1814}
1815
1816impl ValueBlockData for RecordData {
1817 const TAG: DataTag = DataTag::Record;
1818}
1819
1820impl ValueBlockData for StringData {
1821 const TAG: DataTag = DataTag::String;
1822}
1823
1824impl ValueBlockData for ThunkData {
1825 const TAG: DataTag = DataTag::Thunk;
1826}
1827
1828impl ValueBlockData for TermData {
1829 const TAG: DataTag = DataTag::Term;
1830}
1831
1832impl ValueBlockData for LabelData {
1833 const TAG: DataTag = DataTag::Label;
1834}
1835
1836impl ValueBlockData for EnumVariantData {
1837 const TAG: DataTag = DataTag::EnumVariant;
1838}
1839
1840impl ValueBlockData for ForeignIdData {
1841 const TAG: DataTag = DataTag::ForeignId;
1842}
1843
1844impl ValueBlockData for CustomContractData {
1845 const TAG: DataTag = DataTag::CustomContract;
1846}
1847
1848impl ValueBlockData for SealingKeyData {
1849 const TAG: DataTag = DataTag::SealingKey;
1850}
1851
1852impl ValueBlockData for TypeData {
1853 const TAG: DataTag = DataTag::Type;
1854}
1855
1856pub struct ValueBlockRc(NonNull<u8>);
1879
1880impl ValueBlockRc {
1881 #[inline]
1887 pub unsafe fn from_raw(ptr: NonNull<u8>) -> Self {
1888 ValueBlockRc(ptr)
1889 }
1890
1891 #[inline]
1893 fn header(&self) -> &ValueBlockHeader {
1894 unsafe { Self::header_from_raw(self.0) }
1898 }
1899
1900 #[inline]
1902 fn tag(&self) -> DataTag {
1903 self.header().tag()
1904 }
1905
1906 #[inline]
1908 pub fn pos_idx(&self) -> PosIdx {
1909 self.header().pos_idx
1910 }
1911
1912 #[inline]
1919 unsafe fn header_from_raw<'a>(ptr: NonNull<u8>) -> &'a ValueBlockHeader {
1920 unsafe { ptr.cast::<ValueBlockHeader>().as_ref() }
1922 }
1923
1924 #[inline]
1930 unsafe fn tag_from_raw(ptr: NonNull<u8>) -> DataTag {
1931 unsafe { Self::header_from_raw(ptr).tag() }
1933 }
1934
1935 pub fn try_get_mut<T: ValueBlockData>(&mut self) -> Result<Option<&mut T>, TagMismatchError> {
1938 let header = self.header();
1939
1940 if header.tag() != T::TAG {
1941 Err(TagMismatchError)
1942 } else if header.ref_count() != 1 {
1943 Ok(None)
1944 } else {
1945 unsafe { Ok(Some(self.decode_mut_unchecked::<T>())) }
1949 }
1950 }
1951
1952 #[inline]
1955 pub fn get_mut<T: ValueBlockData>(&mut self) -> &mut T {
1956 self.try_get_mut().unwrap().unwrap()
1957 }
1958
1959 pub fn try_make_mut<T: ValueBlockData + Clone>(&mut self) -> Option<&mut T> {
1962 if self.tag() != T::TAG {
1963 return None;
1964 }
1965
1966 self.make_unique();
1967 unsafe { Some(self.decode_mut_unchecked::<T>()) }
1970 }
1971
1972 #[inline]
1974 pub fn make_mut<T: ValueBlockData + Clone>(&mut self) -> &mut T {
1975 self.try_make_mut().unwrap()
1976 }
1977
1978 pub fn make_unique(&mut self) {
1985 if self.header().ref_count() == 1 {
1986 increment!("value::make_unique::no clone");
1987 } else {
1988 increment!("value::make_unique::strong clone");
1989 *self = self.strong_clone();
1990 }
1991 }
1992
1993 pub fn strong_clone(&self) -> Self {
1998 match self.tag() {
1999 DataTag::Number => Self::encode(self.decode::<NumberData>().clone(), self.pos_idx()),
2000 DataTag::Array => Self::encode(self.decode::<ArrayData>().clone(), self.pos_idx()),
2001 DataTag::Record => Self::encode(self.decode::<RecordData>().clone(), self.pos_idx()),
2002 DataTag::String => Self::encode(self.decode::<StringData>().clone(), self.pos_idx()),
2003 DataTag::Thunk => Self::encode(self.decode::<ThunkData>().clone(), self.pos_idx()),
2004 DataTag::Term => Self::encode(self.decode::<TermData>().clone(), self.pos_idx()),
2005 DataTag::Label => Self::encode(self.decode::<LabelData>().clone(), self.pos_idx()),
2006 DataTag::EnumVariant => {
2007 Self::encode(self.decode::<EnumVariantData>().clone(), self.pos_idx())
2008 }
2009 DataTag::ForeignId => Self::encode(*self.decode::<ForeignIdData>(), self.pos_idx()),
2010 DataTag::SealingKey => Self::encode(*self.decode::<SealingKeyData>(), self.pos_idx()),
2011 DataTag::CustomContract => {
2012 Self::encode(self.decode::<CustomContractData>().clone(), self.pos_idx())
2013 }
2014 DataTag::Type => Self::encode(self.decode::<TypeData>().clone(), self.pos_idx()),
2015 }
2016 }
2017
2018 const fn padding<T: ValueBlockData>() -> usize {
2022 let align = Self::block_align::<T>();
2023 let leftover = size_of::<ValueBlockHeader>() % align;
2024
2025 (align - leftover) % align
2026 }
2027
2028 const fn data_offset<T: ValueBlockData>() -> usize {
2032 size_of::<ValueBlockHeader>() + Self::padding::<T>()
2033 }
2034
2035 const fn block_align<T: ValueBlockData>() -> usize {
2039 if align_of::<ValueBlockHeader>() < align_of::<T>() {
2041 align_of::<T>()
2042 } else {
2043 align_of::<ValueBlockHeader>()
2044 }
2045 }
2046
2047 const fn block_layout<T: ValueBlockData>() -> Layout {
2050 let header_layout = Layout::new::<ValueBlockHeader>();
2051 let data_layout = Layout::new::<T>();
2052 let size = header_layout.size() + Self::padding::<T>() + data_layout.size();
2053
2054 assert!(
2058 size + Self::block_align::<T>() <= isize::MAX as usize,
2059 "value block size overflow"
2060 );
2061
2062 unsafe { Layout::from_size_align_unchecked(size, Self::block_align::<T>()) }
2066 }
2067
2068 fn encode<T: ValueBlockData>(value: T, pos_idx: PosIdx) -> Self {
2070 unsafe {
2071 let start = alloc(Self::block_layout::<T>());
2073
2074 if start.is_null() {
2075 panic!("out of memory: failed to allocate memory for Nickel value")
2076 }
2077
2078 let header_ptr = start as *mut ValueBlockHeader;
2079 header_ptr.write(ValueBlockHeader::new(T::TAG, pos_idx));
2080
2081 let data_layout = start.add(Self::data_offset::<T>()) as *mut T;
2083 data_layout.write(value);
2084
2085 Self(NonNull::new_unchecked(start))
2087 }
2088 }
2089
2090 #[inline]
2093 fn try_decode<T: ValueBlockData>(&self) -> Option<&T> {
2094 (self.tag() == T::TAG).then(|| unsafe { self.decode_unchecked() })
2096 }
2097
2098 #[inline]
2100 #[track_caller]
2101 fn decode<T: ValueBlockData>(&self) -> &T {
2102 self.try_decode().unwrap()
2103 }
2104
2105 #[inline]
2113 unsafe fn decode_unchecked<T: ValueBlockData>(&self) -> &T {
2114 unsafe { Self::decode_from_raw_unchecked(self.0) }
2116 }
2117
2118 #[inline]
2128 unsafe fn decode_mut_unchecked<T: ValueBlockData>(&mut self) -> &mut T {
2129 unsafe { Self::decode_mut_from_raw_unchecked(self.0) }
2131 }
2132
2133 #[inline]
2142 unsafe fn decode_from_raw_unchecked<'a, T: ValueBlockData>(ptr: NonNull<u8>) -> &'a T {
2143 unsafe { ptr.add(Self::data_offset::<T>()).cast::<T>().as_ref() }
2145 }
2146
2147 #[inline]
2158 unsafe fn decode_mut_from_raw_unchecked<'a, T: ValueBlockData>(ptr: NonNull<u8>) -> &'a mut T {
2159 unsafe { ptr.add(Self::data_offset::<T>()).cast::<T>().as_mut() }
2161 }
2162
2163 #[inline]
2173 unsafe fn try_decode_from_raw<'a, T: ValueBlockData>(ptr: NonNull<u8>) -> Option<&'a T> {
2174 unsafe { (Self::tag_from_raw(ptr) == T::TAG).then(|| Self::decode_from_raw_unchecked(ptr)) }
2177 }
2178
2179 #[inline(never)]
2182 unsafe fn drop_slow(&mut self) {
2183 unsafe {
2184 let tag = self.tag();
2185 let data_ptr = self.0.as_ptr().add(tag.data_offset());
2188
2189 match tag {
2193 DataTag::Number => {
2194 ptr::drop_in_place(data_ptr as *mut NumberData);
2195 }
2196 DataTag::Array => {
2197 ptr::drop_in_place(data_ptr as *mut ArrayData);
2198 }
2199 DataTag::Record => {
2200 ptr::drop_in_place(data_ptr as *mut RecordData);
2201 }
2202 DataTag::String => {
2203 ptr::drop_in_place(data_ptr as *mut StringData);
2204 }
2205 DataTag::Thunk => {
2206 ptr::drop_in_place(data_ptr as *mut ThunkData);
2207 }
2208 DataTag::Term => {
2209 ptr::drop_in_place(data_ptr as *mut TermData);
2210 }
2211 DataTag::Label => {
2212 ptr::drop_in_place(data_ptr as *mut LabelData);
2213 }
2214 DataTag::EnumVariant => {
2215 ptr::drop_in_place(data_ptr as *mut EnumVariantData);
2216 }
2217 DataTag::ForeignId => {
2218 ptr::drop_in_place(data_ptr as *mut ForeignIdData);
2219 }
2220 DataTag::CustomContract => {
2221 ptr::drop_in_place(data_ptr as *mut CustomContractData);
2222 }
2223 DataTag::SealingKey => {
2224 ptr::drop_in_place(data_ptr as *mut SealingKeyData);
2225 }
2226 DataTag::Type => {
2227 ptr::drop_in_place(data_ptr as *mut TypeData);
2228 }
2229 };
2230
2231 dealloc(self.0.as_ptr(), tag.block_layout());
2232 }
2233 }
2234}
2235
2236impl Drop for ValueBlockRc {
2237 #[inline]
2238 fn drop(&mut self) {
2239 self.header().dec_ref_count();
2240
2241 if self.header().ref_count() == 0 {
2242 unsafe {
2243 self.drop_slow();
2244 }
2245 }
2246 }
2247}
2248
2249impl Clone for ValueBlockRc {
2250 #[inline]
2251 fn clone(&self) -> Self {
2252 self.header().inc_ref_count();
2253 Self(self.0)
2254 }
2255}
2256
2257#[derive(Clone, PartialEq, Debug, Copy)]
2261pub enum Container<C> {
2262 Empty,
2264 Alloc(C),
2268}
2269
2270impl<C> Container<C> {
2271 pub fn into_opt(self) -> Option<C> {
2274 match self {
2275 Container::Empty => None,
2276 Container::Alloc(c) => Some(c),
2277 }
2278 }
2279
2280 #[inline]
2282 pub fn unwrap_alloc(self) -> C {
2283 self.into_opt().unwrap()
2284 }
2285}
2286
2287impl<C: Default> Container<C> {
2288 #[inline]
2291 pub fn unwrap_or_alloc(self) -> C {
2292 self.into_opt().unwrap_or_default()
2293 }
2294}
2295
2296impl<C: ToOwned> Container<&C> {
2297 pub fn to_owned(&self) -> Container<C::Owned> {
2300 match self {
2301 Container::Empty => Container::Empty,
2302 Container::Alloc(c) => Container::Alloc((*c).to_owned()),
2303 }
2304 }
2305}
2306
2307impl Container<&RecordData> {
2308 pub fn get(&self, id: LocIdent) -> Option<&Field> {
2311 self.into_opt().and_then(|record| record.fields.get(&id))
2312 }
2313
2314 pub fn field_names(&self, op_kind: RecordOpKind) -> Vec<LocIdent> {
2317 self.into_opt()
2318 .map(|record| record.field_names(op_kind))
2319 .unwrap_or_default()
2320 }
2321
2322 pub fn len(&self) -> usize {
2324 self.into_opt().map_or(0, |record| record.fields.len())
2325 }
2326
2327 pub fn is_empty(&self) -> bool {
2330 match self {
2331 Container::Empty => true,
2332 Container::Alloc(record) => record.is_empty(),
2333 }
2334 }
2335
2336 pub fn has_only_empty_opts(&self) -> bool {
2340 match self {
2341 Container::Empty => true,
2342 Container::Alloc(record) => record.has_only_empty_opts(),
2343 }
2344 }
2345}
2346
2347impl Container<&ArrayData> {
2348 pub fn iter(&self) -> impl Iterator<Item = &NickelValue> {
2350 self.into_opt()
2351 .into_iter()
2352 .flat_map(|array_data| array_data.array.iter())
2353 }
2354
2355 pub fn iter_pending_contracts(&self) -> impl Iterator<Item = &RuntimeContract> {
2357 self.into_opt()
2358 .into_iter()
2359 .flat_map(|array_data| array_data.pending_contracts.iter())
2360 }
2361
2362 pub fn get(&self, idx: usize) -> Option<&NickelValue> {
2365 self.into_opt()
2366 .and_then(|array_data| array_data.array.get(idx))
2367 }
2368
2369 pub fn len(&self) -> usize {
2371 self.into_opt()
2372 .map_or(0, |array_data| array_data.array.len())
2373 }
2374
2375 pub fn is_empty(&self) -> bool {
2378 match self {
2379 Container::Empty => true,
2380 Container::Alloc(array_data) => array_data.array.is_empty(),
2381 }
2382 }
2383}
2384
2385#[derive(Clone, Copy, Debug)]
2394pub enum ValueContentRef<'a> {
2395 Null,
2396 Bool(bool),
2397 Number(&'a NumberData),
2398 Array(Container<&'a ArrayData>),
2399 Record(Container<&'a RecordData>),
2400 String(&'a StringData),
2401 Thunk(&'a Thunk),
2402 Term(&'a TermData),
2403 Label(&'a LabelData),
2404 EnumVariant(&'a EnumVariantData),
2405 ForeignId(&'a ForeignIdData),
2406 SealingKey(&'a SealingKeyData),
2407 CustomContract(&'a CustomContractData),
2408 Type(&'a TypeData),
2409}
2410
2411pub enum ValueContentRefMut<'a> {
2413 Null(&'a mut NickelValue),
2424 Bool(&'a mut NickelValue),
2425 Number(&'a mut NumberData),
2426 Array(Container<&'a mut ArrayData>),
2427 Record(Container<&'a mut RecordData>),
2428 String(&'a mut StringData),
2429 Thunk(&'a mut Thunk),
2430 Term(&'a mut TermData),
2431 Label(&'a mut LabelData),
2432 EnumVariant(&'a mut EnumVariantData),
2433 ForeignId(&'a mut ForeignIdData),
2434 SealingKey(&'a mut SealingKeyData),
2435 CustomContract(&'a mut CustomContractData),
2436 Type(&'a mut TypeData),
2437}
2438
2439pub enum ValueContent {
2450 Null(lens::ValueLens<()>),
2454 Bool(lens::ValueLens<bool>),
2455 Number(lens::ValueLens<NumberData>),
2456 Array(lens::ValueLens<Container<ArrayData>>),
2457 Record(lens::ValueLens<Container<RecordData>>),
2458 String(lens::ValueLens<StringData>),
2459 Thunk(lens::ValueLens<Thunk>),
2460 Term(lens::TermContent),
2461 Label(lens::ValueLens<LabelData>),
2462 EnumVariant(lens::ValueLens<EnumVariantData>),
2463 ForeignId(lens::ValueLens<ForeignIdData>),
2464 SealingKey(lens::ValueLens<SealingKeyData>),
2465 CustomContract(lens::ValueLens<CustomContractData>),
2466 Type(lens::ValueLens<TypeData>),
2467}
2468
2469impl ValueContent {
2470 pub fn restore(self) -> NickelValue {
2472 match self {
2473 ValueContent::Null(lens) => lens.restore(),
2474 ValueContent::Bool(lens) => lens.restore(),
2475 ValueContent::Number(lens) => lens.restore(),
2476 ValueContent::Array(lens) => lens.restore(),
2477 ValueContent::Record(lens) => lens.restore(),
2478 ValueContent::String(lens) => lens.restore(),
2479 ValueContent::Thunk(lens) => lens.restore(),
2480 ValueContent::Term(lens) => lens.restore(),
2481 ValueContent::Label(lens) => lens.restore(),
2482 ValueContent::EnumVariant(lens) => lens.restore(),
2483 ValueContent::ForeignId(lens) => lens.restore(),
2484 ValueContent::SealingKey(lens) => lens.restore(),
2485 ValueContent::CustomContract(lens) => lens.restore(),
2486 ValueContent::Type(lens) => lens.restore(),
2487 }
2488 }
2489}
2490
2491impl Traverse<NickelValue> for NickelValue {
2492 fn traverse<F, E>(self, f: &mut F, order: TraverseOrder) -> Result<Self, E>
2493 where
2494 F: FnMut(NickelValue) -> Result<NickelValue, E>,
2495 {
2496 let value = match order {
2497 TraverseOrder::TopDown => f(self)?,
2498 TraverseOrder::BottomUp => self,
2499 };
2500
2501 let pos_idx = value.pos_idx();
2502
2503 let result = match value.content() {
2504 lens @ (ValueContent::Null(_)
2505 | ValueContent::Bool(_)
2506 | ValueContent::Number(_)
2507 | ValueContent::String(_)
2508 | ValueContent::Label(_)
2509 | ValueContent::Thunk(_)
2510 | ValueContent::SealingKey(_)
2511 | ValueContent::ForeignId(_)) => lens.restore(),
2512 ValueContent::Array(lens) if lens.value().is_inline_empty_array() => lens.restore(),
2513 ValueContent::Record(lens) if lens.value().is_inline_empty_record() => lens.restore(),
2514 ValueContent::Term(lens) => {
2515 let term = lens.take();
2516 let term = term.traverse(f, order)?;
2517 NickelValue::term(term, pos_idx)
2518 }
2519 ValueContent::Record(lens) => {
2520 let record = lens.take().into_opt().unwrap();
2523
2524 let fields: Result<IndexMap<LocIdent, Field>, E> = record
2527 .fields
2528 .into_iter()
2529 .map(|(id, field)| Ok((id, field.traverse(f, order)?)))
2531 .collect();
2532 NickelValue::record(
2533 RecordData::new_shared_tail(fields?, record.attrs, record.sealed_tail),
2534 pos_idx,
2535 )
2536 }
2537 ValueContent::Array(lens) => {
2538 let ArrayData {
2541 array,
2542 pending_contracts,
2543 } = lens.take().into_opt().unwrap();
2544
2545 let array = array
2546 .into_iter()
2547 .map(|t| t.traverse(f, order))
2548 .collect::<Result<Array, _>>()?;
2549
2550 NickelValue::array(array, pending_contracts, pos_idx)
2552 }
2553 ValueContent::Type(lens) => {
2554 let TypeData { typ, contract } = lens.take();
2555 let typ = typ.traverse(f, order)?;
2556 let contract = contract.traverse(f, order)?;
2557
2558 NickelValue::typ(typ, contract, pos_idx)
2559 }
2560 ValueContent::EnumVariant(lens) => {
2561 let EnumVariantData { tag, arg } = lens.take();
2562 let arg = arg.map(|arg| arg.traverse(f, order)).transpose()?;
2563 NickelValue::enum_variant(tag, arg, pos_idx)
2564 }
2565 ValueContent::CustomContract(lens) => {
2566 let ctr = lens.take();
2567 let ctr = ctr.traverse(f, order)?;
2568 NickelValue::custom_contract(ctr, pos_idx)
2569 }
2570 };
2571
2572 match order {
2573 TraverseOrder::TopDown => Ok(result),
2574 TraverseOrder::BottomUp => f(result),
2575 }
2576 }
2577
2578 fn traverse_ref<S, U>(
2579 &self,
2580 f: &mut dyn FnMut(&NickelValue, &S) -> TraverseControl<S, U>,
2581 scope: &S,
2582 ) -> Option<U> {
2583 let child_scope = match f(self, scope) {
2584 TraverseControl::Continue => None,
2585 TraverseControl::ContinueWithScope(s) => Some(s),
2586 TraverseControl::SkipBranch => {
2587 return None;
2588 }
2589 TraverseControl::Return(ret) => {
2590 return Some(ret);
2591 }
2592 };
2593
2594 let scope = child_scope.as_ref().unwrap_or(scope);
2595
2596 match self.content_ref() {
2597 ValueContentRef::Null
2598 | ValueContentRef::Bool(_)
2599 | ValueContentRef::Array(Container::Empty)
2600 | ValueContentRef::Record(Container::Empty)
2601 | ValueContentRef::Number(_)
2602 | ValueContentRef::String(_)
2603 | ValueContentRef::Label(_)
2604 | ValueContentRef::Thunk(_)
2605 | ValueContentRef::SealingKey(_)
2606 | ValueContentRef::EnumVariant(EnumVariantData { arg: None, .. })
2607 | ValueContentRef::ForeignId(_) => None,
2608 ValueContentRef::EnumVariant(EnumVariantData { arg: Some(v), .. })
2609 | ValueContentRef::CustomContract(v) => v.traverse_ref(f, scope),
2610 ValueContentRef::Array(Container::Alloc(array_data)) => array_data
2611 .array
2612 .iter()
2613 .find_map(|t| t.traverse_ref(f, scope)),
2614 ValueContentRef::Type(TypeData { typ, contract }) => {
2615 typ.traverse_ref(f, scope)?;
2616 contract.traverse_ref(f, scope)
2617 }
2618 ValueContentRef::Record(Container::Alloc(data)) => data
2619 .fields
2620 .values()
2621 .find_map(|field| field.traverse_ref(f, scope)),
2622 ValueContentRef::Term(term) => term.traverse_ref(f, scope),
2623 }
2624 }
2625}
2626
2627impl Traverse<Type> for NickelValue {
2628 fn traverse<F, E>(self, f: &mut F, order: TraverseOrder) -> Result<NickelValue, E>
2629 where
2630 F: FnMut(Type) -> Result<Type, E>,
2631 {
2632 self.traverse(
2633 &mut |value: NickelValue| {
2634 let pos_idx = value.pos_idx();
2635
2636 match value.content() {
2637 ValueContent::Type(lens) => {
2638 let TypeData { typ, contract } = lens.take();
2639 let typ = typ.traverse(f, order)?;
2640 Ok(NickelValue::typ(typ, contract, pos_idx))
2641 }
2642 lens => Ok(lens.restore()),
2643 }
2644 },
2645 order,
2646 )
2647 }
2648
2649 fn traverse_ref<S, U>(
2650 &self,
2651 f: &mut dyn FnMut(&Type, &S) -> TraverseControl<S, U>,
2652 state: &S,
2653 ) -> Option<U> {
2654 self.traverse_ref(
2655 &mut |value: &NickelValue, state: &S| {
2656 if let Some(TypeData { typ, contract: _ }) = value.as_type() {
2657 typ.traverse_ref(f, state).into()
2658 } else {
2659 TraverseControl::Continue
2660 }
2661 },
2662 state,
2663 )
2664 }
2665}
2666
2667impl From<Term> for NickelValue {
2668 fn from(term: Term) -> Self {
2669 NickelValue::term_posless(term)
2670 }
2671}
2672
2673#[cfg(test)]
2674mod tests {
2675 use super::*;
2676 use crate::position::RawSpan;
2677
2678 #[test]
2679 fn inline_values() {
2680 use crate::files::Files;
2681
2682 let inline_null = NickelValue::null();
2683 let inline_true = NickelValue::bool_true();
2684 let inline_false = NickelValue::bool_false();
2685 let inline_empty_array = NickelValue::empty_array();
2686 let inline_empty_record = NickelValue::empty_record();
2687
2688 assert_eq!(inline_null.tag(), ValueTag::Inline);
2689 assert_eq!(inline_true.tag(), ValueTag::Inline);
2690 assert_eq!(inline_false.tag(), ValueTag::Inline);
2691 assert_eq!(inline_empty_array.tag(), ValueTag::Inline);
2692 assert_eq!(inline_empty_record.tag(), ValueTag::Inline);
2693
2694 assert_eq!(inline_null.as_inline(), Some(InlineValue::Null));
2695 assert_eq!(inline_true.as_inline(), Some(InlineValue::True));
2696 assert_eq!(inline_false.as_inline(), Some(InlineValue::False));
2697 assert_eq!(
2698 inline_empty_array.as_inline(),
2699 Some(InlineValue::EmptyArray)
2700 );
2701 assert_eq!(
2702 inline_empty_record.as_inline(),
2703 Some(InlineValue::EmptyRecord)
2704 );
2705
2706 let dummy_pos = TermPos::Original(RawSpan {
2707 src_id: Files::empty().add("<test>", String::from("empty")),
2708 start: 0.into(),
2709 end: 1.into(),
2710 });
2711
2712 let mut pos_table = PosTable::new();
2713
2714 assert!(
2717 inline_null
2718 .clone()
2719 .with_inline_pos_idx(pos_table.push(dummy_pos))
2720 .phys_eq(&NickelValue::null().with_inline_pos_idx(pos_table.push(dummy_pos)))
2721 );
2722 assert!(
2723 inline_true
2724 .with_inline_pos_idx(pos_table.push(dummy_pos))
2725 .phys_eq(&NickelValue::bool_true().with_inline_pos_idx(pos_table.push(dummy_pos)))
2726 );
2727 assert!(
2728 inline_false
2729 .with_inline_pos_idx(pos_table.push(dummy_pos))
2730 .phys_eq(&NickelValue::bool_false().with_inline_pos_idx(pos_table.push(dummy_pos)))
2731 );
2732 assert!(
2733 inline_empty_array
2734 .with_inline_pos_idx(pos_table.push(dummy_pos))
2735 .phys_eq(
2736 &NickelValue::empty_array().with_inline_pos_idx(pos_table.push(dummy_pos))
2737 )
2738 );
2739 assert!(
2740 inline_empty_record
2741 .with_inline_pos_idx(pos_table.push(dummy_pos))
2742 .phys_eq(
2743 &NickelValue::empty_record().with_inline_pos_idx(pos_table.push(dummy_pos))
2744 )
2745 );
2746
2747 assert!(!inline_null.phys_eq(&NickelValue::bool_true()));
2748 }
2749
2750 #[test]
2751 fn basic_value_blocks() {
2752 let number_value = NickelValue::number_posless(42);
2753 let string_value = NickelValue::string_posless("Hello, World!");
2754
2755 assert_eq!(number_value.tag(), ValueTag::Pointer);
2756 assert_eq!(string_value.tag(), ValueTag::Pointer);
2757
2758 assert_eq!(number_value.as_number().unwrap(), &Number::from(42));
2759 assert_eq!(
2760 string_value.as_string().unwrap(),
2761 &NickelString::from("Hello, World!")
2762 );
2763
2764 assert!(number_value.as_string().is_none());
2765 assert!(string_value.as_number().is_none());
2766 }
2767
2768 #[test]
2769 fn ref_counting() {
2770 let number_value = NickelValue::number_posless(42);
2771
2772 let mut copies =
2773 std::array::from_fn::<_, 20, _>(|_| ManuallyDrop::new(number_value.clone()));
2774
2775 let mut as_val = number_value.into_block().unwrap();
2776 assert_eq!(as_val.header().ref_count(), 21);
2777
2778 let mut block_copy = ManuallyDrop::new(as_val.clone());
2779
2780 assert_eq!(as_val.header().ref_count(), 22);
2781
2782 assert!(as_val.try_get_mut::<NumberData>().unwrap().is_none());
2783
2784 for copy in copies.iter_mut().take(10) {
2785 unsafe {
2786 ManuallyDrop::drop(copy);
2787 }
2788 }
2789
2790 assert_eq!(as_val.header().ref_count(), 12);
2791
2792 for copy in copies.iter_mut().skip(10) {
2793 unsafe {
2794 ManuallyDrop::drop(copy);
2795 }
2796 }
2797
2798 let mut cow = as_val.clone();
2799 *cow.make_mut() = Number::from(0);
2800
2801 assert_eq!(as_val.header().ref_count(), 2);
2804 assert_eq!(as_val.decode::<NumberData>(), &Number::from(42));
2805 assert_eq!(cow.header().ref_count(), 1);
2806 assert_eq!(cow.decode::<NumberData>(), &Number::from(0));
2807
2808 unsafe { ManuallyDrop::drop(&mut block_copy) }
2809
2810 *as_val.get_mut() = Number::from(100);
2811 assert_eq!(as_val.header().ref_count(), 1);
2812 assert_eq!(as_val.decode::<NumberData>(), &Number::from(100));
2813 }
2814
2815 #[test]
2816 fn in_place_modification() {
2817 let mut record_data = RecordData::default();
2819 record_data
2820 .fields
2821 .insert(LocIdent::from("hello"), Default::default());
2822 let mut array_data = Array::default();
2823 array_data.push(NickelValue::null());
2824
2825 let record = NickelValue::record_posless(record_data);
2826 let array = NickelValue::array_posless(array_data, Vec::new());
2827
2828 let mut record_value = record.into_block().unwrap();
2829 let mut array_value = array.into_block().unwrap();
2830
2831 assert_eq!(record_value.decode::<RecordData>().fields.len(), 1);
2832 assert_eq!(array_value.decode::<ArrayData>().array.len(), 1);
2833
2834 record_value
2835 .get_mut::<RecordData>()
2836 .fields
2837 .insert(LocIdent::from("world"), Default::default());
2838 array_value
2839 .get_mut::<ArrayData>()
2840 .array
2841 .push(NickelValue::null());
2842
2843 let array_copy = array_value.clone();
2844 let record_copy = record_value.clone();
2845
2846 assert_eq!(record_copy.decode::<RecordData>().fields.len(), 2);
2847 assert_eq!(array_copy.decode::<ArrayData>().array.len(), 2);
2848 }
2849
2850 #[test]
2851 fn in_place_modification_with_content_ref() {
2852 let mut record_data = RecordData::default();
2854 record_data
2855 .fields
2856 .insert(LocIdent::from("hello"), Default::default());
2857 let mut array_data = Array::default();
2858 array_data.push(NickelValue::null());
2859
2860 let mut record = NickelValue::record_posless(record_data);
2861 let mut array = NickelValue::array_posless(array_data, Vec::new());
2862
2863 assert_eq!(record.as_record().unwrap().unwrap_alloc().fields.len(), 1);
2864 assert_eq!(array.as_array().unwrap().unwrap_alloc().array.len(), 1);
2865
2866 if let Some(ValueContentRefMut::Record(Container::Alloc(record))) = record.content_mut() {
2867 record
2868 .fields
2869 .insert(LocIdent::from("world"), Default::default());
2870 } else {
2871 panic!("Expected RecordData");
2872 }
2873
2874 if let Some(ValueContentRefMut::Array(Container::Alloc(array_data))) = array.content_mut() {
2875 array_data.array.push(NickelValue::null());
2876 } else {
2877 panic!("Expected ArrayData");
2878 }
2879
2880 let array_copy = array.clone();
2881 let record_copy = record.clone();
2882
2883 assert_eq!(record_copy.as_record().unwrap().len(), 2);
2884 assert_eq!(array_copy.as_array().unwrap().len(), 2);
2885 }
2886
2887 #[test]
2888 fn content_make_mut() {
2889 let mut record_data = RecordData::default();
2891 record_data
2892 .fields
2893 .insert(LocIdent::from("hello"), Default::default());
2894 let mut array_data = Array::default();
2895 array_data.push(NickelValue::null());
2896
2897 let mut record = NickelValue::record_posless(record_data);
2898 let mut array = NickelValue::array_posless(array_data, Vec::new());
2899 let array_copy = array.clone();
2900
2901 assert_eq!(record.as_record().unwrap().unwrap_alloc().fields.len(), 1);
2902 assert_eq!(array.as_array().unwrap().unwrap_alloc().array.len(), 1);
2903
2904 if let ValueContentRefMut::Record(Container::Alloc(record)) = record.content_make_mut() {
2905 record
2906 .fields
2907 .insert(LocIdent::from("world"), Default::default());
2908 } else {
2909 panic!("Expected RecordData");
2910 }
2911
2912 if let ValueContentRefMut::Array(Container::Alloc(array_data)) = array.content_make_mut() {
2913 array_data.array.push(NickelValue::null());
2914 } else {
2915 panic!("Expected ArrayData");
2916 }
2917
2918 let record_copy = record.clone();
2919
2920 assert_eq!(record.as_record().unwrap().len(), 2);
2921 assert_eq!(record_copy.as_record().unwrap().len(), 2);
2922 assert_eq!(array.as_array().unwrap().len(), 2);
2923 assert_eq!(array_copy.as_array().unwrap().len(), 1);
2925 }
2926
2927 #[test]
2928 fn empty_containers_are_inlined() {
2929 let empty_record = NickelValue::record_posless(RecordData::default());
2930 let empty_array = NickelValue::array_posless(Array::default(), Vec::new());
2931
2932 assert_eq!(empty_record.tag(), ValueTag::Inline);
2933 assert_eq!(empty_array.tag(), ValueTag::Inline);
2934
2935 assert_eq!(empty_record.as_inline(), Some(InlineValue::EmptyRecord));
2936 assert_eq!(empty_array.as_inline(), Some(InlineValue::EmptyArray));
2937 }
2938}