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, 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)]
105pub enum ValueType {
106 Null,
108 Bool,
110 Number,
112 String,
114 Bytes,
116 Array,
118 Object,
120 DateTime,
122 QName,
124 Uuid,
126}
127
128#[repr(transparent)]
133pub struct Value {
134 ptr: NonNull<u8>,
135}
136
137unsafe impl Send for Value {}
140unsafe impl Sync for Value {}
141
142impl Value {
143 pub const NULL: Self = unsafe { Self::new_inline(TypeTag::StringOrNull) };
147
148 pub const FALSE: Self = unsafe { Self::new_inline(TypeTag::BytesOrFalse) };
150
151 pub const TRUE: Self = unsafe { Self::new_inline(TypeTag::ArrayOrTrue) };
153
154 const unsafe fn new_inline(tag: TypeTag) -> Self {
159 unsafe {
160 Self {
161 ptr: NonNull::new_unchecked(ptr::without_provenance_mut(tag as usize)),
164 }
165 }
166 }
167
168 pub(crate) unsafe fn new_ptr(p: *mut u8, tag: TypeTag) -> Self {
171 debug_assert!(!p.is_null());
172 debug_assert!((p as usize).is_multiple_of(ALIGNMENT));
173 unsafe {
174 Self {
175 ptr: NonNull::new_unchecked(p.wrapping_add(tag as usize)),
176 }
177 }
178 }
179
180 #[allow(dead_code)]
183 pub(crate) unsafe fn new_ref<T>(r: &T, tag: TypeTag) -> Self {
184 unsafe { Self::new_ptr(r as *const T as *mut u8, tag) }
185 }
186
187 pub(crate) unsafe fn from_bits(bits: usize) -> Self {
193 debug_assert!(bits != 0);
194 Self {
195 ptr: unsafe { NonNull::new_unchecked(ptr::without_provenance_mut(bits)) },
198 }
199 }
200
201 pub(crate) fn ptr_usize(&self) -> usize {
202 self.ptr.as_ptr().addr()
203 }
204
205 fn is_inline(&self) -> bool {
206 self.ptr_usize() < ALIGNMENT || self.is_inline_string()
207 }
208
209 fn type_tag(&self) -> TypeTag {
210 TypeTag::from(self.ptr_usize())
211 }
212
213 #[inline]
215 pub(crate) fn is_inline_string(&self) -> bool {
216 matches!(self.type_tag(), TypeTag::InlineString)
217 }
218
219 pub(crate) fn heap_ptr(&self) -> *const u8 {
222 self.ptr.as_ptr().map_addr(|a| a & !(ALIGNMENT - 1)) as *const u8
224 }
225
226 pub(crate) unsafe fn heap_ptr_mut(&mut self) -> *mut u8 {
229 self.ptr.as_ptr().map_addr(|a| a & !(ALIGNMENT - 1))
231 }
232
233 pub(crate) unsafe fn set_ptr(&mut self, ptr: *mut u8) {
236 let tag = self.type_tag();
237 unsafe {
238 self.ptr = NonNull::new_unchecked(ptr.wrapping_add(tag as usize));
239 }
240 }
241
242 #[allow(dead_code)]
244 pub(crate) fn raw_eq(&self, other: &Self) -> bool {
245 self.ptr == other.ptr
246 }
247
248 #[allow(dead_code)]
250 pub(crate) fn raw_hash<H: Hasher>(&self, state: &mut H) {
251 self.ptr.hash(state);
252 }
253
254 #[must_use]
258 pub fn value_type(&self) -> ValueType {
259 match (self.type_tag(), self.is_inline()) {
260 (TypeTag::Number, false) => ValueType::Number,
262 (TypeTag::StringOrNull, false) => ValueType::String,
263 (TypeTag::BytesOrFalse, false) => ValueType::Bytes,
264 (TypeTag::ArrayOrTrue, false) => ValueType::Array,
265 (TypeTag::Object, false) => ValueType::Object,
266 (TypeTag::DateTime, false) => ValueType::DateTime,
267 (TypeTag::InlineString, false) => ValueType::String,
268 (TypeTag::Other, false) => {
269 match unsafe { get_other_kind(self) } {
271 OtherKind::QName => ValueType::QName,
272 OtherKind::Uuid => ValueType::Uuid,
273 }
274 }
275
276 (TypeTag::StringOrNull, true) => ValueType::Null,
278 (TypeTag::BytesOrFalse, true) => ValueType::Bool, (TypeTag::ArrayOrTrue, true) => ValueType::Bool, (TypeTag::InlineString, true) => ValueType::String,
281
282 (TypeTag::Number, true)
284 | (TypeTag::Object, true)
285 | (TypeTag::DateTime, true)
286 | (TypeTag::Other, true) => {
287 unreachable!("invalid inline value with Number, Object, DateTime, or Other tag")
289 }
290 }
291 }
292
293 #[must_use]
295 pub fn is_null(&self) -> bool {
296 self.ptr == Self::NULL.ptr
297 }
298
299 #[must_use]
301 pub fn is_bool(&self) -> bool {
302 self.ptr == Self::TRUE.ptr || self.ptr == Self::FALSE.ptr
303 }
304
305 #[must_use]
307 pub fn is_true(&self) -> bool {
308 self.ptr == Self::TRUE.ptr
309 }
310
311 #[must_use]
313 pub fn is_false(&self) -> bool {
314 self.ptr == Self::FALSE.ptr
315 }
316
317 #[must_use]
319 pub fn is_number(&self) -> bool {
320 self.type_tag() == TypeTag::Number && !self.is_inline()
321 }
322
323 #[must_use]
325 pub fn is_string(&self) -> bool {
326 match self.type_tag() {
327 TypeTag::StringOrNull => !self.is_inline(),
328 TypeTag::InlineString => true,
329 _ => false,
330 }
331 }
332
333 #[must_use]
335 pub fn is_bytes(&self) -> bool {
336 self.type_tag() == TypeTag::BytesOrFalse && !self.is_inline()
337 }
338
339 #[must_use]
341 pub fn is_array(&self) -> bool {
342 self.type_tag() == TypeTag::ArrayOrTrue && !self.is_inline()
343 }
344
345 #[must_use]
347 pub fn is_object(&self) -> bool {
348 self.type_tag() == TypeTag::Object && !self.is_inline()
349 }
350
351 #[must_use]
353 pub fn is_datetime(&self) -> bool {
354 self.type_tag() == TypeTag::DateTime && !self.is_inline()
355 }
356
357 #[must_use]
359 pub fn is_qname(&self) -> bool {
360 self.value_type() == ValueType::QName
361 }
362
363 #[must_use]
365 pub fn is_uuid(&self) -> bool {
366 self.value_type() == ValueType::Uuid
367 }
368
369 #[must_use]
373 pub fn as_bool(&self) -> Option<bool> {
374 if self.is_bool() {
375 Some(self.is_true())
376 } else {
377 None
378 }
379 }
380
381 #[must_use]
383 pub fn as_number(&self) -> Option<&VNumber> {
384 if self.is_number() {
385 Some(unsafe { &*(self as *const Value as *const VNumber) })
387 } else {
388 None
389 }
390 }
391
392 pub fn as_number_mut(&mut self) -> Option<&mut VNumber> {
394 if self.is_number() {
395 Some(unsafe { &mut *(self as *mut Value as *mut VNumber) })
396 } else {
397 None
398 }
399 }
400
401 #[must_use]
403 pub fn as_string(&self) -> Option<&VString> {
404 if self.is_string() {
405 Some(unsafe { &*(self as *const Value as *const VString) })
406 } else {
407 None
408 }
409 }
410
411 pub fn as_string_mut(&mut self) -> Option<&mut VString> {
413 if self.is_string() {
414 Some(unsafe { &mut *(self as *mut Value as *mut VString) })
415 } else {
416 None
417 }
418 }
419
420 #[must_use]
424 pub fn is_safe_string(&self) -> bool {
425 self.as_string().is_some_and(|s| s.is_safe())
426 }
427
428 #[must_use]
430 pub fn as_safe_string(&self) -> Option<&VSafeString> {
431 if self.is_safe_string() {
432 Some(unsafe { &*(self as *const Value as *const VSafeString) })
433 } else {
434 None
435 }
436 }
437
438 pub fn as_safe_string_mut(&mut self) -> Option<&mut VSafeString> {
440 if self.is_safe_string() {
441 Some(unsafe { &mut *(self as *mut Value as *mut VSafeString) })
442 } else {
443 None
444 }
445 }
446
447 #[must_use]
449 pub fn as_bytes(&self) -> Option<&VBytes> {
450 if self.is_bytes() {
451 Some(unsafe { &*(self as *const Value as *const VBytes) })
452 } else {
453 None
454 }
455 }
456
457 pub fn as_bytes_mut(&mut self) -> Option<&mut VBytes> {
459 if self.is_bytes() {
460 Some(unsafe { &mut *(self as *mut Value as *mut VBytes) })
461 } else {
462 None
463 }
464 }
465
466 #[must_use]
468 pub fn as_array(&self) -> Option<&VArray> {
469 if self.is_array() {
470 Some(unsafe { &*(self as *const Value as *const VArray) })
471 } else {
472 None
473 }
474 }
475
476 pub fn as_array_mut(&mut self) -> Option<&mut VArray> {
478 if self.is_array() {
479 Some(unsafe { &mut *(self as *mut Value as *mut VArray) })
480 } else {
481 None
482 }
483 }
484
485 #[must_use]
487 pub fn as_object(&self) -> Option<&VObject> {
488 if self.is_object() {
489 Some(unsafe { &*(self as *const Value as *const VObject) })
490 } else {
491 None
492 }
493 }
494
495 pub fn as_object_mut(&mut self) -> Option<&mut VObject> {
497 if self.is_object() {
498 Some(unsafe { &mut *(self as *mut Value as *mut VObject) })
499 } else {
500 None
501 }
502 }
503
504 #[must_use]
506 pub fn as_datetime(&self) -> Option<&VDateTime> {
507 if self.is_datetime() {
508 Some(unsafe { &*(self as *const Value as *const VDateTime) })
509 } else {
510 None
511 }
512 }
513
514 pub fn as_datetime_mut(&mut self) -> Option<&mut VDateTime> {
516 if self.is_datetime() {
517 Some(unsafe { &mut *(self as *mut Value as *mut VDateTime) })
518 } else {
519 None
520 }
521 }
522
523 #[must_use]
525 pub fn as_qname(&self) -> Option<&VQName> {
526 if self.is_qname() {
527 Some(unsafe { &*(self as *const Value as *const VQName) })
528 } else {
529 None
530 }
531 }
532
533 pub fn as_qname_mut(&mut self) -> Option<&mut VQName> {
535 if self.is_qname() {
536 Some(unsafe { &mut *(self as *mut Value as *mut VQName) })
537 } else {
538 None
539 }
540 }
541
542 #[must_use]
544 pub fn as_uuid(&self) -> Option<&VUuid> {
545 if self.is_uuid() {
546 Some(unsafe { &*(self as *const Value as *const VUuid) })
547 } else {
548 None
549 }
550 }
551
552 pub fn as_uuid_mut(&mut self) -> Option<&mut VUuid> {
554 if self.is_uuid() {
555 Some(unsafe { &mut *(self as *mut Value as *mut VUuid) })
556 } else {
557 None
558 }
559 }
560
561 pub fn take(&mut self) -> Value {
563 mem::replace(self, Value::NULL)
564 }
565}
566
567impl Clone for Value {
570 fn clone(&self) -> Self {
571 match self.value_type() {
572 ValueType::Null | ValueType::Bool => {
573 Self { ptr: self.ptr }
575 }
576 ValueType::Number => unsafe { self.as_number().unwrap_unchecked() }.clone_impl(),
577 ValueType::String => unsafe { self.as_string().unwrap_unchecked() }.clone_impl(),
578 ValueType::Bytes => unsafe { self.as_bytes().unwrap_unchecked() }.clone_impl(),
579 ValueType::Array => unsafe { self.as_array().unwrap_unchecked() }.clone_impl(),
580 ValueType::Object => unsafe { self.as_object().unwrap_unchecked() }.clone_impl(),
581 ValueType::DateTime => unsafe { self.as_datetime().unwrap_unchecked() }.clone_impl(),
582 ValueType::QName => unsafe { self.as_qname().unwrap_unchecked() }.clone_impl(),
583 ValueType::Uuid => unsafe { self.as_uuid().unwrap_unchecked() }.clone_impl(),
584 }
585 }
586}
587
588impl Drop for Value {
591 fn drop(&mut self) {
592 match self.value_type() {
593 ValueType::Null | ValueType::Bool => {
594 }
596 ValueType::Number => unsafe { self.as_number_mut().unwrap_unchecked() }.drop_impl(),
597 ValueType::String => unsafe { self.as_string_mut().unwrap_unchecked() }.drop_impl(),
598 ValueType::Bytes => unsafe { self.as_bytes_mut().unwrap_unchecked() }.drop_impl(),
599 ValueType::Array => unsafe { self.as_array_mut().unwrap_unchecked() }.drop_impl(),
600 ValueType::Object => unsafe { self.as_object_mut().unwrap_unchecked() }.drop_impl(),
601 ValueType::DateTime => unsafe { self.as_datetime_mut().unwrap_unchecked() }.drop_impl(),
602 ValueType::QName => unsafe { self.as_qname_mut().unwrap_unchecked() }.drop_impl(),
603 ValueType::Uuid => unsafe { self.as_uuid_mut().unwrap_unchecked() }.drop_impl(),
604 }
605 }
606}
607
608impl PartialEq for Value {
611 fn eq(&self, other: &Self) -> bool {
612 let (t1, t2) = (self.value_type(), other.value_type());
613 if t1 != t2 {
614 return false;
615 }
616
617 match t1 {
618 ValueType::Null | ValueType::Bool => self.ptr == other.ptr,
619 ValueType::Number => unsafe {
620 self.as_number().unwrap_unchecked() == other.as_number().unwrap_unchecked()
621 },
622 ValueType::String => unsafe {
623 self.as_string().unwrap_unchecked() == other.as_string().unwrap_unchecked()
624 },
625 ValueType::Bytes => unsafe {
626 self.as_bytes().unwrap_unchecked() == other.as_bytes().unwrap_unchecked()
627 },
628 ValueType::Array => unsafe {
629 self.as_array().unwrap_unchecked() == other.as_array().unwrap_unchecked()
630 },
631 ValueType::Object => unsafe {
632 self.as_object().unwrap_unchecked() == other.as_object().unwrap_unchecked()
633 },
634 ValueType::DateTime => unsafe {
635 self.as_datetime().unwrap_unchecked() == other.as_datetime().unwrap_unchecked()
636 },
637 ValueType::QName => unsafe {
638 self.as_qname().unwrap_unchecked() == other.as_qname().unwrap_unchecked()
639 },
640 ValueType::Uuid => unsafe {
641 self.as_uuid().unwrap_unchecked() == other.as_uuid().unwrap_unchecked()
642 },
643 }
644 }
645}
646
647impl Eq for Value {}
648
649impl PartialOrd for Value {
652 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
653 use core::cmp::Ordering;
654
655 let (t1, t2) = (self.value_type(), other.value_type());
656
657 if t1 != t2 {
659 return t1.partial_cmp(&t2);
660 }
661
662 match t1 {
664 ValueType::Null => Some(Ordering::Equal),
665 ValueType::Bool => self.is_true().partial_cmp(&other.is_true()),
666 ValueType::Number => unsafe {
667 self.as_number()
668 .unwrap_unchecked()
669 .partial_cmp(other.as_number().unwrap_unchecked())
670 },
671 ValueType::String => unsafe {
672 self.as_string()
673 .unwrap_unchecked()
674 .partial_cmp(other.as_string().unwrap_unchecked())
675 },
676 ValueType::Bytes => unsafe {
677 self.as_bytes()
678 .unwrap_unchecked()
679 .partial_cmp(other.as_bytes().unwrap_unchecked())
680 },
681 ValueType::Array => unsafe {
682 self.as_array()
683 .unwrap_unchecked()
684 .partial_cmp(other.as_array().unwrap_unchecked())
685 },
686 ValueType::Object => None,
688 ValueType::DateTime => unsafe {
690 self.as_datetime()
691 .unwrap_unchecked()
692 .partial_cmp(other.as_datetime().unwrap_unchecked())
693 },
694 ValueType::QName => None,
696 ValueType::Uuid => unsafe {
698 self.as_uuid()
699 .unwrap_unchecked()
700 .as_bytes()
701 .partial_cmp(other.as_uuid().unwrap_unchecked().as_bytes())
702 },
703 }
704 }
705}
706
707impl Hash for Value {
710 fn hash<H: Hasher>(&self, state: &mut H) {
711 self.value_type().hash(state);
713
714 match self.value_type() {
715 ValueType::Null => {}
716 ValueType::Bool => self.is_true().hash(state),
717 ValueType::Number => unsafe { self.as_number().unwrap_unchecked() }.hash(state),
718 ValueType::String => unsafe { self.as_string().unwrap_unchecked() }.hash(state),
719 ValueType::Bytes => unsafe { self.as_bytes().unwrap_unchecked() }.hash(state),
720 ValueType::Array => unsafe { self.as_array().unwrap_unchecked() }.hash(state),
721 ValueType::Object => unsafe { self.as_object().unwrap_unchecked() }.hash(state),
722 ValueType::DateTime => unsafe { self.as_datetime().unwrap_unchecked() }.hash(state),
723 ValueType::QName => unsafe { self.as_qname().unwrap_unchecked() }.hash(state),
724 ValueType::Uuid => unsafe { self.as_uuid().unwrap_unchecked() }.hash(state),
725 }
726 }
727}
728
729impl Debug for Value {
732 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
733 match self.value_type() {
734 ValueType::Null => f.write_str("null"),
735 ValueType::Bool => Debug::fmt(&self.is_true(), f),
736 ValueType::Number => Debug::fmt(unsafe { self.as_number().unwrap_unchecked() }, f),
737 ValueType::String => Debug::fmt(unsafe { self.as_string().unwrap_unchecked() }, f),
738 ValueType::Bytes => Debug::fmt(unsafe { self.as_bytes().unwrap_unchecked() }, f),
739 ValueType::Array => Debug::fmt(unsafe { self.as_array().unwrap_unchecked() }, f),
740 ValueType::Object => Debug::fmt(unsafe { self.as_object().unwrap_unchecked() }, f),
741 ValueType::DateTime => Debug::fmt(unsafe { self.as_datetime().unwrap_unchecked() }, f),
742 ValueType::QName => Debug::fmt(unsafe { self.as_qname().unwrap_unchecked() }, f),
743 ValueType::Uuid => Debug::fmt(unsafe { self.as_uuid().unwrap_unchecked() }, f),
744 }
745 }
746}
747
748impl Default for Value {
751 fn default() -> Self {
752 Self::NULL
753 }
754}
755
756impl From<bool> for Value {
759 fn from(b: bool) -> Self {
760 if b { Self::TRUE } else { Self::FALSE }
761 }
762}
763
764impl<T: Into<Value>> From<Option<T>> for Value {
765 fn from(opt: Option<T>) -> Self {
766 match opt {
767 Some(v) => v.into(),
768 None => Self::NULL,
769 }
770 }
771}
772
773#[cfg(feature = "alloc")]
776impl<T: Into<Value>> core::iter::FromIterator<T> for Value {
777 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
779 VArray::from_iter(iter).into()
780 }
781}
782
783#[cfg(feature = "alloc")]
784impl<K: Into<VString>, V: Into<Value>> core::iter::FromIterator<(K, V)> for Value {
785 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
787 VObject::from_iter(iter).into()
788 }
789}
790
791#[derive(Debug, Clone, PartialEq)]
793pub enum Destructured {
794 Null,
796 Bool(bool),
798 Number(VNumber),
800 String(VString),
802 Bytes(VBytes),
804 Array(VArray),
806 Object(VObject),
808 DateTime(VDateTime),
810 QName(VQName),
812 Uuid(VUuid),
814}
815
816#[derive(Debug, Copy, Clone, PartialEq)]
818pub enum DestructuredRef<'a> {
819 Null,
821 Bool(bool),
823 Number(&'a VNumber),
825 String(&'a VString),
827 Bytes(&'a VBytes),
829 Array(&'a VArray),
831 Object(&'a VObject),
833 DateTime(&'a VDateTime),
835 QName(&'a VQName),
837 Uuid(&'a VUuid),
839}
840
841#[derive(Debug)]
843pub enum DestructuredMut<'a> {
844 Null,
846 Bool(bool),
848 Number(&'a mut VNumber),
850 String(&'a mut VString),
852 Bytes(&'a mut VBytes),
854 Array(&'a mut VArray),
856 Object(&'a mut VObject),
858 DateTime(&'a mut VDateTime),
860 QName(&'a mut VQName),
862 Uuid(&'a mut VUuid),
864}
865
866impl Value {
867 #[must_use]
869 pub fn destructure(self) -> Destructured {
870 match self.value_type() {
871 ValueType::Null => Destructured::Null,
872 ValueType::Bool => Destructured::Bool(self.is_true()),
873 ValueType::Number => Destructured::Number(VNumber(self)),
874 ValueType::String => Destructured::String(VString(self)),
875 ValueType::Bytes => Destructured::Bytes(VBytes(self)),
876 ValueType::Array => Destructured::Array(VArray(self)),
877 ValueType::Object => Destructured::Object(VObject(self)),
878 ValueType::DateTime => Destructured::DateTime(VDateTime(self)),
879 ValueType::QName => Destructured::QName(VQName(self)),
880 ValueType::Uuid => Destructured::Uuid(VUuid(self)),
881 }
882 }
883
884 #[must_use]
886 pub fn destructure_ref(&self) -> DestructuredRef<'_> {
887 match self.value_type() {
888 ValueType::Null => DestructuredRef::Null,
889 ValueType::Bool => DestructuredRef::Bool(self.is_true()),
890 ValueType::Number => {
891 DestructuredRef::Number(unsafe { self.as_number().unwrap_unchecked() })
892 }
893 ValueType::String => {
894 DestructuredRef::String(unsafe { self.as_string().unwrap_unchecked() })
895 }
896 ValueType::Bytes => {
897 DestructuredRef::Bytes(unsafe { self.as_bytes().unwrap_unchecked() })
898 }
899 ValueType::Array => {
900 DestructuredRef::Array(unsafe { self.as_array().unwrap_unchecked() })
901 }
902 ValueType::Object => {
903 DestructuredRef::Object(unsafe { self.as_object().unwrap_unchecked() })
904 }
905 ValueType::DateTime => {
906 DestructuredRef::DateTime(unsafe { self.as_datetime().unwrap_unchecked() })
907 }
908 ValueType::QName => {
909 DestructuredRef::QName(unsafe { self.as_qname().unwrap_unchecked() })
910 }
911 ValueType::Uuid => DestructuredRef::Uuid(unsafe { self.as_uuid().unwrap_unchecked() }),
912 }
913 }
914
915 pub fn destructure_mut(&mut self) -> DestructuredMut<'_> {
917 match self.value_type() {
918 ValueType::Null => DestructuredMut::Null,
919 ValueType::Bool => DestructuredMut::Bool(self.is_true()),
920 ValueType::Number => {
921 DestructuredMut::Number(unsafe { self.as_number_mut().unwrap_unchecked() })
922 }
923 ValueType::String => {
924 DestructuredMut::String(unsafe { self.as_string_mut().unwrap_unchecked() })
925 }
926 ValueType::Bytes => {
927 DestructuredMut::Bytes(unsafe { self.as_bytes_mut().unwrap_unchecked() })
928 }
929 ValueType::Array => {
930 DestructuredMut::Array(unsafe { self.as_array_mut().unwrap_unchecked() })
931 }
932 ValueType::Object => {
933 DestructuredMut::Object(unsafe { self.as_object_mut().unwrap_unchecked() })
934 }
935 ValueType::DateTime => {
936 DestructuredMut::DateTime(unsafe { self.as_datetime_mut().unwrap_unchecked() })
937 }
938 ValueType::QName => {
939 DestructuredMut::QName(unsafe { self.as_qname_mut().unwrap_unchecked() })
940 }
941 ValueType::Uuid => {
942 DestructuredMut::Uuid(unsafe { self.as_uuid_mut().unwrap_unchecked() })
943 }
944 }
945 }
946}
947
948#[cfg(test)]
949mod tests {
950 use super::*;
951 use crate::string::VString;
952
953 #[test]
954 fn test_size() {
955 assert_eq!(
956 core::mem::size_of::<Value>(),
957 core::mem::size_of::<usize>(),
958 "Value should be pointer-sized"
959 );
960 assert_eq!(
961 core::mem::size_of::<Option<Value>>(),
962 core::mem::size_of::<usize>(),
963 "Option<Value> should be pointer-sized (niche optimization)"
964 );
965 }
966
967 #[test]
968 fn test_null() {
969 let v = Value::NULL;
970 assert!(v.is_null());
971 assert_eq!(v.value_type(), ValueType::Null);
972 assert!(!v.is_bool());
973 assert!(!v.is_number());
974 }
975
976 #[test]
977 fn test_bool() {
978 let t = Value::TRUE;
979 let f = Value::FALSE;
980
981 assert!(t.is_bool());
982 assert!(t.is_true());
983 assert!(!t.is_false());
984 assert_eq!(t.as_bool(), Some(true));
985
986 assert!(f.is_bool());
987 assert!(f.is_false());
988 assert!(!f.is_true());
989 assert_eq!(f.as_bool(), Some(false));
990
991 assert_eq!(Value::from(true), Value::TRUE);
992 assert_eq!(Value::from(false), Value::FALSE);
993 }
994
995 #[test]
996 fn test_clone_inline() {
997 let v = Value::TRUE;
998 let v2 = v.clone();
999 assert_eq!(v, v2);
1000 }
1001
1002 #[test]
1003 fn test_inline_short_string() {
1004 let v: Value = VString::new("inline").into();
1005 assert_eq!(v.value_type(), ValueType::String);
1006 assert!(v.is_string());
1007 assert!(v.is_inline());
1008 }
1009
1010 #[test]
1011 fn short_strings_are_stored_inline() {
1012 for len in 0..=VString::INLINE_LEN_MAX {
1013 let data = "s".repeat(len);
1014 let v = Value::from(data.as_str());
1015 assert!(
1016 v.is_inline_string(),
1017 "expected inline string for length {len}, ptr={:#x}",
1018 v.ptr_usize()
1019 );
1020 assert!(
1021 v.is_inline(),
1022 "inline flag should be true for strings of length {len}"
1023 );
1024 assert_eq!(
1025 v.as_string().unwrap().as_str(),
1026 data,
1027 "round-trip mismatch for inline string"
1028 );
1029 }
1030 }
1031
1032 #[test]
1033 fn long_strings_force_heap_storage() {
1034 let long = "l".repeat(VString::INLINE_LEN_MAX + 16);
1035 let v = Value::from(long.as_str());
1036 assert!(
1037 !v.is_inline_string(),
1038 "expected heap storage for long string ptr={:#x}",
1039 v.ptr_usize()
1040 );
1041 assert_eq!(
1042 v.as_string().unwrap().as_str(),
1043 long,
1044 "heap string should round-trip"
1045 );
1046 }
1047
1048 #[test]
1049 fn clone_preserves_inline_string_representation() {
1050 let original = Value::from("inline");
1051 assert!(original.is_inline_string());
1052 let clone = original.clone();
1053 assert!(
1054 clone.is_inline_string(),
1055 "clone lost inline tag for ptr={:#x}",
1056 clone.ptr_usize()
1057 );
1058 assert_eq!(
1059 clone.as_string().unwrap().as_str(),
1060 "inline",
1061 "clone should preserve payload"
1062 );
1063 }
1064
1065 #[test]
1066 fn string_mutations_transition_inline_and_heap() {
1067 let mut value = Value::from("seed");
1068 assert!(value.is_inline_string());
1069
1070 {
1072 let slot = value.as_string_mut().expect("string value");
1073 let mut owned = slot.to_string();
1074 while owned.len() <= VString::INLINE_LEN_MAX {
1075 owned.push('g');
1076 }
1077 owned.push_str("OVERFLOW");
1079 *slot = VString::new(&owned);
1080 }
1081 assert!(
1082 !value.is_inline_string(),
1083 "string expected to spill to heap after grow"
1084 );
1085
1086 {
1088 let slot = value.as_string_mut().expect("string value");
1089 let mut owned = slot.to_string();
1090 owned.truncate(VString::INLINE_LEN_MAX);
1091 *slot = VString::new(&owned);
1092 }
1093 assert!(
1094 value.is_inline_string(),
1095 "string should return to inline storage after shrink"
1096 );
1097 }
1098}