1use core::fmt::{self, Debug, Formatter};
49use core::hash::{Hash, Hasher};
50use core::mem;
51use core::ptr::{self, NonNull};
52
53use crate::array::VArray;
54use crate::bytes::VBytes;
55use crate::datetime::VDateTime;
56use crate::number::VNumber;
57use crate::object::VObject;
58use crate::other::{OtherKind, VChar, VQName, VUuid, get_other_kind};
59use crate::string::{VSafeString, VString};
60
61pub(crate) const ALIGNMENT: usize = 8;
63
64#[repr(usize)]
66#[derive(Copy, Clone, Debug, PartialEq, Eq)]
67pub(crate) enum TypeTag {
68 Number = 0,
70 StringOrNull = 1,
72 BytesOrFalse = 2,
74 ArrayOrTrue = 3,
76 Object = 4,
78 DateTime = 5,
80 InlineString = 6,
82 Other = 7,
84}
85
86impl From<usize> for TypeTag {
87 fn from(other: usize) -> Self {
88 match other & 0b111 {
90 0 => TypeTag::Number,
91 1 => TypeTag::StringOrNull,
92 2 => TypeTag::BytesOrFalse,
93 3 => TypeTag::ArrayOrTrue,
94 4 => TypeTag::Object,
95 5 => TypeTag::DateTime,
96 6 => TypeTag::InlineString,
97 7 => TypeTag::Other,
98 _ => unreachable!(),
99 }
100 }
101}
102
103#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
105#[non_exhaustive]
106pub enum ValueType {
107 Null,
109 Bool,
111 Number,
113 String,
115 Bytes,
117 Array,
119 Object,
121 DateTime,
123 QName,
125 Uuid,
127 Char,
129}
130
131#[repr(transparent)]
136pub struct Value {
137 ptr: NonNull<u8>,
138}
139
140unsafe impl Send for Value {}
143unsafe impl Sync for Value {}
144
145impl Value {
146 pub const NULL: Self = unsafe { Self::new_inline(TypeTag::StringOrNull) };
150
151 pub const FALSE: Self = unsafe { Self::new_inline(TypeTag::BytesOrFalse) };
153
154 pub const TRUE: Self = unsafe { Self::new_inline(TypeTag::ArrayOrTrue) };
156
157 const unsafe fn new_inline(tag: TypeTag) -> Self {
162 unsafe {
163 Self {
164 ptr: NonNull::new_unchecked(ptr::without_provenance_mut(tag as usize)),
167 }
168 }
169 }
170
171 pub(crate) unsafe fn new_ptr(p: *mut u8, tag: TypeTag) -> Self {
174 debug_assert!(!p.is_null());
175 debug_assert!((p as usize).is_multiple_of(ALIGNMENT));
176 unsafe {
177 Self {
178 ptr: NonNull::new_unchecked(p.wrapping_add(tag as usize)),
179 }
180 }
181 }
182
183 #[allow(dead_code)]
186 pub(crate) unsafe fn new_ref<T>(r: &T, tag: TypeTag) -> Self {
187 unsafe { Self::new_ptr(r as *const T as *mut u8, tag) }
188 }
189
190 pub(crate) unsafe fn from_bits(bits: usize) -> Self {
196 debug_assert!(bits != 0);
197 Self {
198 ptr: unsafe { NonNull::new_unchecked(ptr::without_provenance_mut(bits)) },
201 }
202 }
203
204 pub(crate) fn ptr_usize(&self) -> usize {
205 self.ptr.as_ptr().addr()
206 }
207
208 fn is_inline(&self) -> bool {
209 self.ptr_usize() < ALIGNMENT || self.is_inline_string()
210 }
211
212 fn type_tag(&self) -> TypeTag {
213 TypeTag::from(self.ptr_usize())
214 }
215
216 #[inline]
218 pub(crate) fn is_inline_string(&self) -> bool {
219 matches!(self.type_tag(), TypeTag::InlineString)
220 }
221
222 pub(crate) fn heap_ptr(&self) -> *const u8 {
225 self.ptr.as_ptr().map_addr(|a| a & !(ALIGNMENT - 1)) as *const u8
227 }
228
229 pub(crate) unsafe fn heap_ptr_mut(&mut self) -> *mut u8 {
232 self.ptr.as_ptr().map_addr(|a| a & !(ALIGNMENT - 1))
234 }
235
236 pub(crate) unsafe fn set_ptr(&mut self, ptr: *mut u8) {
239 let tag = self.type_tag();
240 unsafe {
241 self.ptr = NonNull::new_unchecked(ptr.wrapping_add(tag as usize));
242 }
243 }
244
245 #[allow(dead_code)]
247 pub(crate) fn raw_eq(&self, other: &Self) -> bool {
248 self.ptr == other.ptr
249 }
250
251 #[allow(dead_code)]
253 pub(crate) fn raw_hash<H: Hasher>(&self, state: &mut H) {
254 self.ptr.hash(state);
255 }
256
257 #[must_use]
261 pub fn value_type(&self) -> ValueType {
262 match (self.type_tag(), self.is_inline()) {
263 (TypeTag::Number, false) => ValueType::Number,
265 (TypeTag::StringOrNull, false) => ValueType::String,
266 (TypeTag::BytesOrFalse, false) => ValueType::Bytes,
267 (TypeTag::ArrayOrTrue, false) => ValueType::Array,
268 (TypeTag::Object, false) => ValueType::Object,
269 (TypeTag::DateTime, false) => ValueType::DateTime,
270 (TypeTag::InlineString, false) => ValueType::String,
271 (TypeTag::Other, false) => {
272 match unsafe { get_other_kind(self) } {
274 OtherKind::QName => ValueType::QName,
275 OtherKind::Uuid => ValueType::Uuid,
276 OtherKind::Char => ValueType::Char,
277 }
278 }
279
280 (TypeTag::StringOrNull, true) => ValueType::Null,
282 (TypeTag::BytesOrFalse, true) => ValueType::Bool, (TypeTag::ArrayOrTrue, true) => ValueType::Bool, (TypeTag::InlineString, true) => ValueType::String,
285
286 (TypeTag::Number, true)
288 | (TypeTag::Object, true)
289 | (TypeTag::DateTime, true)
290 | (TypeTag::Other, true) => {
291 unreachable!("invalid inline value with Number, Object, DateTime, or Other tag")
293 }
294 }
295 }
296
297 #[must_use]
299 pub fn is_null(&self) -> bool {
300 self.ptr == Self::NULL.ptr
301 }
302
303 #[must_use]
305 pub fn is_bool(&self) -> bool {
306 self.ptr == Self::TRUE.ptr || self.ptr == Self::FALSE.ptr
307 }
308
309 #[must_use]
311 pub fn is_true(&self) -> bool {
312 self.ptr == Self::TRUE.ptr
313 }
314
315 #[must_use]
317 pub fn is_false(&self) -> bool {
318 self.ptr == Self::FALSE.ptr
319 }
320
321 #[must_use]
323 pub fn is_number(&self) -> bool {
324 self.type_tag() == TypeTag::Number && !self.is_inline()
325 }
326
327 #[must_use]
329 pub fn is_string(&self) -> bool {
330 match self.type_tag() {
331 TypeTag::StringOrNull => !self.is_inline(),
332 TypeTag::InlineString => true,
333 _ => false,
334 }
335 }
336
337 #[must_use]
339 pub fn is_bytes(&self) -> bool {
340 self.type_tag() == TypeTag::BytesOrFalse && !self.is_inline()
341 }
342
343 #[must_use]
345 pub fn is_array(&self) -> bool {
346 self.type_tag() == TypeTag::ArrayOrTrue && !self.is_inline()
347 }
348
349 #[must_use]
351 pub fn is_object(&self) -> bool {
352 self.type_tag() == TypeTag::Object && !self.is_inline()
353 }
354
355 #[must_use]
357 pub fn is_datetime(&self) -> bool {
358 self.type_tag() == TypeTag::DateTime && !self.is_inline()
359 }
360
361 #[must_use]
363 pub fn is_qname(&self) -> bool {
364 self.value_type() == ValueType::QName
365 }
366
367 #[must_use]
369 pub fn is_uuid(&self) -> bool {
370 self.value_type() == ValueType::Uuid
371 }
372
373 #[must_use]
375 pub fn is_char(&self) -> bool {
376 self.value_type() == ValueType::Char
377 }
378
379 #[must_use]
383 pub fn as_bool(&self) -> Option<bool> {
384 if self.is_bool() {
385 Some(self.is_true())
386 } else {
387 None
388 }
389 }
390
391 #[must_use]
393 pub fn as_number(&self) -> Option<&VNumber> {
394 if self.is_number() {
395 Some(unsafe { &*(self as *const Value as *const VNumber) })
397 } else {
398 None
399 }
400 }
401
402 pub fn as_number_mut(&mut self) -> Option<&mut VNumber> {
404 if self.is_number() {
405 Some(unsafe { &mut *(self as *mut Value as *mut VNumber) })
406 } else {
407 None
408 }
409 }
410
411 #[must_use]
413 pub fn as_string(&self) -> Option<&VString> {
414 if self.is_string() {
415 Some(unsafe { &*(self as *const Value as *const VString) })
416 } else {
417 None
418 }
419 }
420
421 pub fn as_string_mut(&mut self) -> Option<&mut VString> {
423 if self.is_string() {
424 Some(unsafe { &mut *(self as *mut Value as *mut VString) })
425 } else {
426 None
427 }
428 }
429
430 #[must_use]
434 pub fn is_safe_string(&self) -> bool {
435 self.as_string().is_some_and(|s| s.is_safe())
436 }
437
438 #[must_use]
440 pub fn as_safe_string(&self) -> Option<&VSafeString> {
441 if self.is_safe_string() {
442 Some(unsafe { &*(self as *const Value as *const VSafeString) })
443 } else {
444 None
445 }
446 }
447
448 pub fn as_safe_string_mut(&mut self) -> Option<&mut VSafeString> {
450 if self.is_safe_string() {
451 Some(unsafe { &mut *(self as *mut Value as *mut VSafeString) })
452 } else {
453 None
454 }
455 }
456
457 #[must_use]
459 pub fn as_bytes(&self) -> Option<&VBytes> {
460 if self.is_bytes() {
461 Some(unsafe { &*(self as *const Value as *const VBytes) })
462 } else {
463 None
464 }
465 }
466
467 pub fn as_bytes_mut(&mut self) -> Option<&mut VBytes> {
469 if self.is_bytes() {
470 Some(unsafe { &mut *(self as *mut Value as *mut VBytes) })
471 } else {
472 None
473 }
474 }
475
476 #[must_use]
478 pub fn as_array(&self) -> Option<&VArray> {
479 if self.is_array() {
480 Some(unsafe { &*(self as *const Value as *const VArray) })
481 } else {
482 None
483 }
484 }
485
486 pub fn as_array_mut(&mut self) -> Option<&mut VArray> {
488 if self.is_array() {
489 Some(unsafe { &mut *(self as *mut Value as *mut VArray) })
490 } else {
491 None
492 }
493 }
494
495 #[must_use]
497 pub fn as_object(&self) -> Option<&VObject> {
498 if self.is_object() {
499 Some(unsafe { &*(self as *const Value as *const VObject) })
500 } else {
501 None
502 }
503 }
504
505 pub fn as_object_mut(&mut self) -> Option<&mut VObject> {
507 if self.is_object() {
508 Some(unsafe { &mut *(self as *mut Value as *mut VObject) })
509 } else {
510 None
511 }
512 }
513
514 #[must_use]
516 pub fn as_datetime(&self) -> Option<&VDateTime> {
517 if self.is_datetime() {
518 Some(unsafe { &*(self as *const Value as *const VDateTime) })
519 } else {
520 None
521 }
522 }
523
524 pub fn as_datetime_mut(&mut self) -> Option<&mut VDateTime> {
526 if self.is_datetime() {
527 Some(unsafe { &mut *(self as *mut Value as *mut VDateTime) })
528 } else {
529 None
530 }
531 }
532
533 #[must_use]
535 pub fn as_qname(&self) -> Option<&VQName> {
536 if self.is_qname() {
537 Some(unsafe { &*(self as *const Value as *const VQName) })
538 } else {
539 None
540 }
541 }
542
543 pub fn as_qname_mut(&mut self) -> Option<&mut VQName> {
545 if self.is_qname() {
546 Some(unsafe { &mut *(self as *mut Value as *mut VQName) })
547 } else {
548 None
549 }
550 }
551
552 #[must_use]
554 pub fn as_uuid(&self) -> Option<&VUuid> {
555 if self.is_uuid() {
556 Some(unsafe { &*(self as *const Value as *const VUuid) })
557 } else {
558 None
559 }
560 }
561
562 pub fn as_uuid_mut(&mut self) -> Option<&mut VUuid> {
564 if self.is_uuid() {
565 Some(unsafe { &mut *(self as *mut Value as *mut VUuid) })
566 } else {
567 None
568 }
569 }
570
571 #[must_use]
573 pub fn as_vchar(&self) -> Option<&VChar> {
574 if self.is_char() {
575 Some(unsafe { &*(self as *const Value as *const VChar) })
576 } else {
577 None
578 }
579 }
580
581 pub fn as_vchar_mut(&mut self) -> Option<&mut VChar> {
583 if self.is_char() {
584 Some(unsafe { &mut *(self as *mut Value as *mut VChar) })
585 } else {
586 None
587 }
588 }
589
590 #[must_use]
592 pub fn as_char(&self) -> Option<char> {
593 self.as_vchar().map(VChar::value)
594 }
595
596 pub const fn take(&mut self) -> Value {
598 mem::replace(self, Value::NULL)
599 }
600}
601
602impl Clone for Value {
605 fn clone(&self) -> Self {
606 match self.value_type() {
607 ValueType::Null | ValueType::Bool => {
608 Self { ptr: self.ptr }
610 }
611 ValueType::Number => unsafe { self.as_number().unwrap_unchecked() }.clone_impl(),
612 ValueType::String => unsafe { self.as_string().unwrap_unchecked() }.clone_impl(),
613 ValueType::Bytes => unsafe { self.as_bytes().unwrap_unchecked() }.clone_impl(),
614 ValueType::Array => unsafe { self.as_array().unwrap_unchecked() }.clone_impl(),
615 ValueType::Object => unsafe { self.as_object().unwrap_unchecked() }.clone_impl(),
616 ValueType::DateTime => unsafe { self.as_datetime().unwrap_unchecked() }.clone_impl(),
617 ValueType::QName => unsafe { self.as_qname().unwrap_unchecked() }.clone_impl(),
618 ValueType::Uuid => unsafe { self.as_uuid().unwrap_unchecked() }.clone_impl(),
619 ValueType::Char => unsafe { self.as_vchar().unwrap_unchecked() }.clone_impl(),
620 }
621 }
622}
623
624impl Drop for Value {
627 fn drop(&mut self) {
628 match self.value_type() {
629 ValueType::Null | ValueType::Bool => {
630 }
632 ValueType::Number => unsafe { self.as_number_mut().unwrap_unchecked() }.drop_impl(),
633 ValueType::String => unsafe { self.as_string_mut().unwrap_unchecked() }.drop_impl(),
634 ValueType::Bytes => unsafe { self.as_bytes_mut().unwrap_unchecked() }.drop_impl(),
635 ValueType::Array => unsafe { self.as_array_mut().unwrap_unchecked() }.drop_impl(),
636 ValueType::Object => unsafe { self.as_object_mut().unwrap_unchecked() }.drop_impl(),
637 ValueType::DateTime => unsafe { self.as_datetime_mut().unwrap_unchecked() }.drop_impl(),
638 ValueType::QName => unsafe { self.as_qname_mut().unwrap_unchecked() }.drop_impl(),
639 ValueType::Uuid => unsafe { self.as_uuid_mut().unwrap_unchecked() }.drop_impl(),
640 ValueType::Char => unsafe { self.as_vchar_mut().unwrap_unchecked() }.drop_impl(),
641 }
642 }
643}
644
645impl PartialEq for Value {
648 fn eq(&self, other: &Self) -> bool {
649 let (t1, t2) = (self.value_type(), other.value_type());
650 if t1 != t2 {
651 return false;
652 }
653
654 match t1 {
655 ValueType::Null | ValueType::Bool => self.ptr == other.ptr,
656 ValueType::Number => unsafe {
657 self.as_number().unwrap_unchecked() == other.as_number().unwrap_unchecked()
658 },
659 ValueType::String => unsafe {
660 self.as_string().unwrap_unchecked() == other.as_string().unwrap_unchecked()
661 },
662 ValueType::Bytes => unsafe {
663 self.as_bytes().unwrap_unchecked() == other.as_bytes().unwrap_unchecked()
664 },
665 ValueType::Array => unsafe {
666 self.as_array().unwrap_unchecked() == other.as_array().unwrap_unchecked()
667 },
668 ValueType::Object => unsafe {
669 self.as_object().unwrap_unchecked() == other.as_object().unwrap_unchecked()
670 },
671 ValueType::DateTime => unsafe {
672 self.as_datetime().unwrap_unchecked() == other.as_datetime().unwrap_unchecked()
673 },
674 ValueType::QName => unsafe {
675 self.as_qname().unwrap_unchecked() == other.as_qname().unwrap_unchecked()
676 },
677 ValueType::Uuid => unsafe {
678 self.as_uuid().unwrap_unchecked() == other.as_uuid().unwrap_unchecked()
679 },
680 ValueType::Char => unsafe {
681 self.as_vchar().unwrap_unchecked() == other.as_vchar().unwrap_unchecked()
682 },
683 }
684 }
685}
686
687impl Eq for Value {}
688
689impl PartialOrd for Value {
692 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
693 use core::cmp::Ordering;
694
695 let (t1, t2) = (self.value_type(), other.value_type());
696
697 if t1 != t2 {
699 return t1.partial_cmp(&t2);
700 }
701
702 match t1 {
704 ValueType::Null => Some(Ordering::Equal),
705 ValueType::Bool => self.is_true().partial_cmp(&other.is_true()),
706 ValueType::Number => unsafe {
707 self.as_number()
708 .unwrap_unchecked()
709 .partial_cmp(other.as_number().unwrap_unchecked())
710 },
711 ValueType::String => unsafe {
712 self.as_string()
713 .unwrap_unchecked()
714 .partial_cmp(other.as_string().unwrap_unchecked())
715 },
716 ValueType::Bytes => unsafe {
717 self.as_bytes()
718 .unwrap_unchecked()
719 .partial_cmp(other.as_bytes().unwrap_unchecked())
720 },
721 ValueType::Array => unsafe {
722 self.as_array()
723 .unwrap_unchecked()
724 .partial_cmp(other.as_array().unwrap_unchecked())
725 },
726 ValueType::Object => None,
728 ValueType::DateTime => unsafe {
730 self.as_datetime()
731 .unwrap_unchecked()
732 .partial_cmp(other.as_datetime().unwrap_unchecked())
733 },
734 ValueType::QName => None,
736 ValueType::Uuid => unsafe {
738 self.as_uuid()
739 .unwrap_unchecked()
740 .as_bytes()
741 .partial_cmp(other.as_uuid().unwrap_unchecked().as_bytes())
742 },
743 ValueType::Char => unsafe {
745 self.as_char()
746 .unwrap_unchecked()
747 .partial_cmp(&other.as_char().unwrap_unchecked())
748 },
749 }
750 }
751}
752
753impl Hash for Value {
756 fn hash<H: Hasher>(&self, state: &mut H) {
757 self.value_type().hash(state);
759
760 match self.value_type() {
761 ValueType::Null => {}
762 ValueType::Bool => self.is_true().hash(state),
763 ValueType::Number => unsafe { self.as_number().unwrap_unchecked() }.hash(state),
764 ValueType::String => unsafe { self.as_string().unwrap_unchecked() }.hash(state),
765 ValueType::Bytes => unsafe { self.as_bytes().unwrap_unchecked() }.hash(state),
766 ValueType::Array => unsafe { self.as_array().unwrap_unchecked() }.hash(state),
767 ValueType::Object => unsafe { self.as_object().unwrap_unchecked() }.hash(state),
768 ValueType::DateTime => unsafe { self.as_datetime().unwrap_unchecked() }.hash(state),
769 ValueType::QName => unsafe { self.as_qname().unwrap_unchecked() }.hash(state),
770 ValueType::Uuid => unsafe { self.as_uuid().unwrap_unchecked() }.hash(state),
771 ValueType::Char => unsafe { self.as_vchar().unwrap_unchecked() }.hash(state),
772 }
773 }
774}
775
776impl Debug for Value {
779 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
780 match self.value_type() {
781 ValueType::Null => f.write_str("null"),
782 ValueType::Bool => Debug::fmt(&self.is_true(), f),
783 ValueType::Number => Debug::fmt(unsafe { self.as_number().unwrap_unchecked() }, f),
784 ValueType::String => Debug::fmt(unsafe { self.as_string().unwrap_unchecked() }, f),
785 ValueType::Bytes => Debug::fmt(unsafe { self.as_bytes().unwrap_unchecked() }, f),
786 ValueType::Array => Debug::fmt(unsafe { self.as_array().unwrap_unchecked() }, f),
787 ValueType::Object => Debug::fmt(unsafe { self.as_object().unwrap_unchecked() }, f),
788 ValueType::DateTime => Debug::fmt(unsafe { self.as_datetime().unwrap_unchecked() }, f),
789 ValueType::QName => Debug::fmt(unsafe { self.as_qname().unwrap_unchecked() }, f),
790 ValueType::Uuid => Debug::fmt(unsafe { self.as_uuid().unwrap_unchecked() }, f),
791 ValueType::Char => Debug::fmt(unsafe { self.as_vchar().unwrap_unchecked() }, f),
792 }
793 }
794}
795
796impl Default for Value {
799 fn default() -> Self {
800 Self::NULL
801 }
802}
803
804impl From<bool> for Value {
807 fn from(b: bool) -> Self {
808 if b { Self::TRUE } else { Self::FALSE }
809 }
810}
811
812impl<T: Into<Value>> From<Option<T>> for Value {
813 fn from(opt: Option<T>) -> Self {
814 match opt {
815 Some(v) => v.into(),
816 None => Self::NULL,
817 }
818 }
819}
820
821#[cfg(feature = "alloc")]
824impl<T: Into<Value>> core::iter::FromIterator<T> for Value {
825 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
827 VArray::from_iter(iter).into()
828 }
829}
830
831#[cfg(feature = "alloc")]
832impl<K: Into<VString>, V: Into<Value>> core::iter::FromIterator<(K, V)> for Value {
833 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
835 VObject::from_iter(iter).into()
836 }
837}
838
839#[derive(Debug, Clone, PartialEq)]
841#[non_exhaustive]
842pub enum Destructured {
843 Null,
845 Bool(bool),
847 Number(VNumber),
849 String(VString),
851 Bytes(VBytes),
853 Array(VArray),
855 Object(VObject),
857 DateTime(VDateTime),
859 QName(VQName),
861 Uuid(VUuid),
863 Char(char),
865}
866
867#[derive(Debug, Copy, Clone, PartialEq)]
869#[non_exhaustive]
870pub enum DestructuredRef<'a> {
871 Null,
873 Bool(bool),
875 Number(&'a VNumber),
877 String(&'a VString),
879 Bytes(&'a VBytes),
881 Array(&'a VArray),
883 Object(&'a VObject),
885 DateTime(&'a VDateTime),
887 QName(&'a VQName),
889 Uuid(&'a VUuid),
891 Char(char),
893}
894
895#[derive(Debug)]
897#[non_exhaustive]
898pub enum DestructuredMut<'a> {
899 Null,
901 Bool(bool),
903 Number(&'a mut VNumber),
905 String(&'a mut VString),
907 Bytes(&'a mut VBytes),
909 Array(&'a mut VArray),
911 Object(&'a mut VObject),
913 DateTime(&'a mut VDateTime),
915 QName(&'a mut VQName),
917 Uuid(&'a mut VUuid),
919 Char(char),
921}
922
923impl Value {
924 #[must_use]
926 pub fn destructure(self) -> Destructured {
927 match self.value_type() {
928 ValueType::Null => Destructured::Null,
929 ValueType::Bool => Destructured::Bool(self.is_true()),
930 ValueType::Number => Destructured::Number(VNumber(self)),
931 ValueType::String => Destructured::String(VString(self)),
932 ValueType::Bytes => Destructured::Bytes(VBytes(self)),
933 ValueType::Array => Destructured::Array(VArray(self)),
934 ValueType::Object => Destructured::Object(VObject(self)),
935 ValueType::DateTime => Destructured::DateTime(VDateTime(self)),
936 ValueType::QName => Destructured::QName(VQName(self)),
937 ValueType::Uuid => Destructured::Uuid(VUuid(self)),
938 ValueType::Char => {
939 let c = unsafe { self.as_vchar().unwrap_unchecked() }.value();
940 Destructured::Char(c)
941 }
942 }
943 }
944
945 #[must_use]
947 pub fn destructure_ref(&self) -> DestructuredRef<'_> {
948 match self.value_type() {
949 ValueType::Null => DestructuredRef::Null,
950 ValueType::Bool => DestructuredRef::Bool(self.is_true()),
951 ValueType::Number => {
952 DestructuredRef::Number(unsafe { self.as_number().unwrap_unchecked() })
953 }
954 ValueType::String => {
955 DestructuredRef::String(unsafe { self.as_string().unwrap_unchecked() })
956 }
957 ValueType::Bytes => {
958 DestructuredRef::Bytes(unsafe { self.as_bytes().unwrap_unchecked() })
959 }
960 ValueType::Array => {
961 DestructuredRef::Array(unsafe { self.as_array().unwrap_unchecked() })
962 }
963 ValueType::Object => {
964 DestructuredRef::Object(unsafe { self.as_object().unwrap_unchecked() })
965 }
966 ValueType::DateTime => {
967 DestructuredRef::DateTime(unsafe { self.as_datetime().unwrap_unchecked() })
968 }
969 ValueType::QName => {
970 DestructuredRef::QName(unsafe { self.as_qname().unwrap_unchecked() })
971 }
972 ValueType::Uuid => DestructuredRef::Uuid(unsafe { self.as_uuid().unwrap_unchecked() }),
973 ValueType::Char => {
974 DestructuredRef::Char(unsafe { self.as_vchar().unwrap_unchecked() }.value())
975 }
976 }
977 }
978
979 pub fn destructure_mut(&mut self) -> DestructuredMut<'_> {
981 match self.value_type() {
982 ValueType::Null => DestructuredMut::Null,
983 ValueType::Bool => DestructuredMut::Bool(self.is_true()),
984 ValueType::Number => {
985 DestructuredMut::Number(unsafe { self.as_number_mut().unwrap_unchecked() })
986 }
987 ValueType::String => {
988 DestructuredMut::String(unsafe { self.as_string_mut().unwrap_unchecked() })
989 }
990 ValueType::Bytes => {
991 DestructuredMut::Bytes(unsafe { self.as_bytes_mut().unwrap_unchecked() })
992 }
993 ValueType::Array => {
994 DestructuredMut::Array(unsafe { self.as_array_mut().unwrap_unchecked() })
995 }
996 ValueType::Object => {
997 DestructuredMut::Object(unsafe { self.as_object_mut().unwrap_unchecked() })
998 }
999 ValueType::DateTime => {
1000 DestructuredMut::DateTime(unsafe { self.as_datetime_mut().unwrap_unchecked() })
1001 }
1002 ValueType::QName => {
1003 DestructuredMut::QName(unsafe { self.as_qname_mut().unwrap_unchecked() })
1004 }
1005 ValueType::Uuid => {
1006 DestructuredMut::Uuid(unsafe { self.as_uuid_mut().unwrap_unchecked() })
1007 }
1008 ValueType::Char => {
1009 DestructuredMut::Char(unsafe { self.as_vchar().unwrap_unchecked() }.value())
1010 }
1011 }
1012 }
1013}
1014
1015#[cfg(test)]
1016mod tests {
1017 use super::*;
1018 use crate::string::VString;
1019
1020 #[test]
1021 fn test_size() {
1022 assert_eq!(
1023 core::mem::size_of::<Value>(),
1024 core::mem::size_of::<usize>(),
1025 "Value should be pointer-sized"
1026 );
1027 assert_eq!(
1028 core::mem::size_of::<Option<Value>>(),
1029 core::mem::size_of::<usize>(),
1030 "Option<Value> should be pointer-sized (niche optimization)"
1031 );
1032 }
1033
1034 #[test]
1035 fn test_null() {
1036 let v = Value::NULL;
1037 assert!(v.is_null());
1038 assert_eq!(v.value_type(), ValueType::Null);
1039 assert!(!v.is_bool());
1040 assert!(!v.is_number());
1041 }
1042
1043 #[test]
1044 fn test_bool() {
1045 let t = Value::TRUE;
1046 let f = Value::FALSE;
1047
1048 assert!(t.is_bool());
1049 assert!(t.is_true());
1050 assert!(!t.is_false());
1051 assert_eq!(t.as_bool(), Some(true));
1052
1053 assert!(f.is_bool());
1054 assert!(f.is_false());
1055 assert!(!f.is_true());
1056 assert_eq!(f.as_bool(), Some(false));
1057
1058 assert_eq!(Value::from(true), Value::TRUE);
1059 assert_eq!(Value::from(false), Value::FALSE);
1060 }
1061
1062 #[test]
1063 fn test_clone_inline() {
1064 let v = Value::TRUE;
1065 let v2 = v.clone();
1066 assert_eq!(v, v2);
1067 }
1068
1069 #[test]
1070 fn test_char_value() {
1071 let v = Value::from('λ');
1072 assert_eq!(v.value_type(), ValueType::Char);
1073 assert!(v.is_char());
1074 assert_eq!(v.as_char(), Some('λ'));
1075
1076 assert_eq!(v.clone().destructure(), Destructured::Char('λ'));
1078 assert_eq!(v.destructure_ref(), DestructuredRef::Char('λ'));
1080
1081 let cloned = v.clone();
1083 assert_eq!(cloned.as_char(), Some('λ'));
1084 assert_eq!(v, cloned);
1085 }
1086
1087 #[test]
1088 fn test_inline_short_string() {
1089 let v: Value = VString::new("inline").into();
1090 assert_eq!(v.value_type(), ValueType::String);
1091 assert!(v.is_string());
1092 assert!(v.is_inline());
1093 }
1094
1095 #[test]
1096 fn short_strings_are_stored_inline() {
1097 for len in 0..=VString::INLINE_LEN_MAX {
1098 let data = "s".repeat(len);
1099 let v = Value::from(data.as_str());
1100 assert!(
1101 v.is_inline_string(),
1102 "expected inline string for length {len}, ptr={:#x}",
1103 v.ptr_usize()
1104 );
1105 assert!(
1106 v.is_inline(),
1107 "inline flag should be true for strings of length {len}"
1108 );
1109 assert_eq!(
1110 v.as_string().unwrap().as_str(),
1111 data,
1112 "round-trip mismatch for inline string"
1113 );
1114 }
1115 }
1116
1117 #[test]
1118 fn long_strings_force_heap_storage() {
1119 let long = "l".repeat(VString::INLINE_LEN_MAX + 16);
1120 let v = Value::from(long.as_str());
1121 assert!(
1122 !v.is_inline_string(),
1123 "expected heap storage for long string ptr={:#x}",
1124 v.ptr_usize()
1125 );
1126 assert_eq!(
1127 v.as_string().unwrap().as_str(),
1128 long,
1129 "heap string should round-trip"
1130 );
1131 }
1132
1133 #[test]
1134 fn clone_preserves_inline_string_representation() {
1135 let original = Value::from("inline");
1136 assert!(original.is_inline_string());
1137 let clone = original.clone();
1138 assert!(
1139 clone.is_inline_string(),
1140 "clone lost inline tag for ptr={:#x}",
1141 clone.ptr_usize()
1142 );
1143 assert_eq!(
1144 clone.as_string().unwrap().as_str(),
1145 "inline",
1146 "clone should preserve payload"
1147 );
1148 }
1149
1150 #[test]
1151 fn string_mutations_transition_inline_and_heap() {
1152 let mut value = Value::from("seed");
1153 assert!(value.is_inline_string());
1154
1155 {
1157 let slot = value.as_string_mut().expect("string value");
1158 let mut owned = slot.to_string();
1159 while owned.len() <= VString::INLINE_LEN_MAX {
1160 owned.push('g');
1161 }
1162 owned.push_str("OVERFLOW");
1164 *slot = VString::new(&owned);
1165 }
1166 assert!(
1167 !value.is_inline_string(),
1168 "string expected to spill to heap after grow"
1169 );
1170
1171 {
1173 let slot = value.as_string_mut().expect("string value");
1174 let mut owned = slot.to_string();
1175 owned.truncate(VString::INLINE_LEN_MAX);
1176 *slot = VString::new(&owned);
1177 }
1178 assert!(
1179 value.is_inline_string(),
1180 "string should return to inline storage after shrink"
1181 );
1182 }
1183}