1use std::cmp::Ordering;
2use std::collections::{BTreeMap, HashMap};
3use std::convert::TryFrom;
4use std::fmt::{self, Debug, Formatter};
5use std::hash::Hash;
6use std::hint::unreachable_unchecked;
7use std::mem;
8use std::ops::{Deref, Index, IndexMut};
9use std::ptr::NonNull;
10
11#[cfg(feature = "indexmap")]
12use indexmap::IndexMap;
13
14use super::array::IArray;
15use super::number::INumber;
16use super::object::IObject;
17use super::string::IString;
18
19#[repr(transparent)]
61pub struct IValue {
62 ptr: NonNull<u8>,
63}
64
65#[derive(Debug, Clone, PartialEq, Eq)]
68pub enum Destructured {
69 Null,
71 Bool(bool),
73 Number(INumber),
75 String(IString),
77 Array(IArray),
79 Object(IObject),
81}
82
83impl Destructured {
84 #[must_use]
86 pub fn as_ref<'a>(&'a self) -> DestructuredRef<'a> {
87 use DestructuredRef::{Array, Bool, Null, Number, Object, String};
88 match self {
89 Self::Null => Null,
90 Self::Bool(b) => Bool(*b),
91 Self::Number(v) => Number(v),
92 Self::String(v) => String(v),
93 Self::Array(v) => Array(v),
94 Self::Object(v) => Object(v),
95 }
96 }
97}
98
99#[derive(Debug, Copy, Clone, PartialEq, Eq)]
102pub enum DestructuredRef<'a> {
103 Null,
105 Bool(bool),
109 Number(&'a INumber),
111 String(&'a IString),
113 Array(&'a IArray),
115 Object(&'a IObject),
117}
118
119#[derive(Debug)]
122pub enum DestructuredMut<'a> {
123 Null,
125 Bool(BoolMut<'a>),
130 Number(&'a mut INumber),
132 String(&'a mut IString),
134 Array(&'a mut IArray),
136 Object(&'a mut IObject),
138}
139
140#[derive(Debug)]
142pub struct BoolMut<'a>(&'a mut IValue);
143
144impl BoolMut<'_> {
145 pub fn set(&mut self, value: bool) {
148 *self.0 = value.into();
149 }
150 #[must_use]
153 pub fn get(&self) -> bool {
154 self.0.is_true()
155 }
156}
157
158impl Deref for BoolMut<'_> {
159 type Target = bool;
160 fn deref(&self) -> &bool {
161 if self.get() {
162 &true
163 } else {
164 &false
165 }
166 }
167}
168
169pub(crate) const ALIGNMENT: usize = 4;
170
171#[repr(usize)]
172#[derive(Copy, Clone, Debug, PartialEq, Eq)]
173pub(crate) enum TypeTag {
174 Number = 0,
175 StringOrNull = 1,
176 ArrayOrFalse = 2,
177 ObjectOrTrue = 3,
178}
179
180impl From<usize> for TypeTag {
181 fn from(other: usize) -> Self {
182 unsafe { mem::transmute(other % ALIGNMENT) }
184 }
185}
186
187#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
189pub enum ValueType {
190 Null,
193 Bool,
195
196 Number,
199 String,
201 Array,
203 Object,
205}
206
207unsafe impl Send for IValue {}
208unsafe impl Sync for IValue {}
209
210impl IValue {
211 const unsafe fn new_inline(tag: TypeTag) -> Self {
213 Self {
214 ptr: NonNull::new_unchecked(tag as usize as *mut u8),
215 }
216 }
217 pub(crate) unsafe fn new_ptr(p: NonNull<u8>, tag: TypeTag) -> Self {
219 Self {
220 ptr: p.add(tag as usize),
221 }
222 }
223 pub(crate) unsafe fn new_ref<T>(r: &T, tag: TypeTag) -> Self {
225 Self::new_ptr(NonNull::from_ref(r).cast(), tag)
226 }
227
228 pub const NULL: Self = unsafe { Self::new_inline(TypeTag::StringOrNull) };
230 pub const FALSE: Self = unsafe { Self::new_inline(TypeTag::ArrayOrFalse) };
232 pub const TRUE: Self = unsafe { Self::new_inline(TypeTag::ObjectOrTrue) };
234
235 pub(crate) fn ptr_usize(&self) -> usize {
236 self.ptr.as_ptr() as usize
237 }
238 pub(crate) unsafe fn ptr(&self) -> NonNull<u8> {
240 self.ptr.offset(-((self.ptr_usize() % ALIGNMENT) as isize))
241 }
242 pub(crate) unsafe fn set_ptr(&mut self, ptr: NonNull<u8>) {
244 let tag = self.type_tag();
245 self.ptr = ptr.add(tag as usize);
246 }
247 pub(crate) unsafe fn set_ref<T>(&mut self, r: &T) {
249 self.set_ptr(NonNull::from_ref(r).cast());
250 }
251 pub(crate) unsafe fn raw_copy(&self) -> Self {
252 Self { ptr: self.ptr }
253 }
254 pub(crate) fn raw_eq(&self, other: &Self) -> bool {
255 self.ptr == other.ptr
256 }
257 pub(crate) fn raw_hash<H: std::hash::Hasher>(&self, state: &mut H) {
258 self.ptr.hash(state);
259 }
260 fn is_ptr(&self) -> bool {
261 self.ptr_usize() >= ALIGNMENT
262 }
263 fn type_tag(&self) -> TypeTag {
264 self.ptr_usize().into()
265 }
266
267 #[must_use]
269 pub fn type_(&self) -> ValueType {
270 match (self.type_tag(), self.is_ptr()) {
271 (TypeTag::Number, true) => ValueType::Number,
273 (TypeTag::StringOrNull, true) => ValueType::String,
274 (TypeTag::ArrayOrFalse, true) => ValueType::Array,
275 (TypeTag::ObjectOrTrue, true) => ValueType::Object,
276
277 (TypeTag::StringOrNull, false) => ValueType::Null,
279 (TypeTag::ArrayOrFalse, false) | (TypeTag::ObjectOrTrue, false) => ValueType::Bool,
280
281 _ => unsafe { unreachable_unchecked() },
283 }
284 }
285
286 #[must_use]
288 pub fn destructure(self) -> Destructured {
289 match self.type_() {
290 ValueType::Null => Destructured::Null,
291 ValueType::Bool => Destructured::Bool(self.is_true()),
292 ValueType::Number => Destructured::Number(INumber(self)),
293 ValueType::String => Destructured::String(IString(self)),
294 ValueType::Array => Destructured::Array(IArray(self)),
295 ValueType::Object => Destructured::Object(IObject(self)),
296 }
297 }
298
299 #[must_use]
301 pub fn destructure_ref<'a>(&'a self) -> DestructuredRef<'a> {
302 unsafe {
304 match self.type_() {
305 ValueType::Null => DestructuredRef::Null,
306 ValueType::Bool => DestructuredRef::Bool(self.is_true()),
307 ValueType::Number => DestructuredRef::Number(self.as_number_unchecked()),
308 ValueType::String => DestructuredRef::String(self.as_string_unchecked()),
309 ValueType::Array => DestructuredRef::Array(self.as_array_unchecked()),
310 ValueType::Object => DestructuredRef::Object(self.as_object_unchecked()),
311 }
312 }
313 }
314
315 pub fn destructure_mut<'a>(&'a mut self) -> DestructuredMut<'a> {
317 unsafe {
319 match self.type_() {
320 ValueType::Null => DestructuredMut::Null,
321 ValueType::Bool => DestructuredMut::Bool(BoolMut(self)),
322 ValueType::Number => DestructuredMut::Number(self.as_number_unchecked_mut()),
323 ValueType::String => DestructuredMut::String(self.as_string_unchecked_mut()),
324 ValueType::Array => DestructuredMut::Array(self.as_array_unchecked_mut()),
325 ValueType::Object => DestructuredMut::Object(self.as_object_unchecked_mut()),
326 }
327 }
328 }
329
330 pub fn get(&self, index: impl ValueIndex) -> Option<&IValue> {
337 index.index_into(self)
338 }
339
340 pub fn get_mut(&mut self, index: impl ValueIndex) -> Option<&mut IValue> {
347 index.index_into_mut(self)
348 }
349
350 pub fn remove(&mut self, index: impl ValueIndex) -> Option<IValue> {
357 index.remove(self)
358 }
359
360 pub fn take(&mut self) -> IValue {
362 mem::replace(self, IValue::NULL)
363 }
364
365 #[must_use]
368 pub fn len(&self) -> Option<usize> {
369 match self.type_() {
370 ValueType::Array => Some(unsafe { self.as_array_unchecked().len() }),
372 ValueType::Object => Some(unsafe { self.as_object_unchecked().len() }),
374 _ => None,
375 }
376 }
377
378 #[must_use]
381 pub fn is_empty(&self) -> Option<bool> {
382 match self.type_() {
383 ValueType::Array => Some(unsafe { self.as_array_unchecked().is_empty() }),
385 ValueType::Object => Some(unsafe { self.as_object_unchecked().is_empty() }),
387 _ => None,
388 }
389 }
390
391 #[must_use]
394 pub fn is_null(&self) -> bool {
395 self.ptr == Self::NULL.ptr
396 }
397
398 #[must_use]
401 pub fn is_bool(&self) -> bool {
402 self.ptr == Self::TRUE.ptr || self.ptr == Self::FALSE.ptr
403 }
404
405 #[must_use]
407 pub fn is_true(&self) -> bool {
408 self.ptr == Self::TRUE.ptr
409 }
410
411 #[must_use]
413 pub fn is_false(&self) -> bool {
414 self.ptr == Self::FALSE.ptr
415 }
416
417 #[must_use]
420 pub fn to_bool(&self) -> Option<bool> {
421 if self.is_bool() {
422 Some(self.is_true())
423 } else {
424 None
425 }
426 }
427
428 #[must_use]
431 pub fn is_number(&self) -> bool {
432 self.type_tag() == TypeTag::Number
433 }
434
435 unsafe fn unchecked_cast_ref<T>(&self) -> &T {
436 &*(self as *const Self).cast::<T>()
437 }
438
439 unsafe fn unchecked_cast_mut<T>(&mut self) -> &mut T {
440 &mut *(self as *mut Self).cast::<T>()
441 }
442
443 unsafe fn as_number_unchecked(&self) -> &INumber {
445 self.unchecked_cast_ref()
446 }
447
448 unsafe fn as_number_unchecked_mut(&mut self) -> &mut INumber {
450 self.unchecked_cast_mut()
451 }
452
453 #[must_use]
456 pub fn as_number(&self) -> Option<&INumber> {
457 if self.is_number() {
458 Some(unsafe { self.as_number_unchecked() })
460 } else {
461 None
462 }
463 }
464
465 pub fn as_number_mut(&mut self) -> Option<&mut INumber> {
468 if self.is_number() {
469 Some(unsafe { self.as_number_unchecked_mut() })
471 } else {
472 None
473 }
474 }
475
476 pub fn into_number(self) -> Result<INumber, IValue> {
482 if self.is_number() {
483 Ok(INumber(self))
484 } else {
485 Err(self)
486 }
487 }
488
489 #[must_use]
491 pub fn to_i64(&self) -> Option<i64> {
492 self.as_number()?.to_i64()
493 }
494 #[must_use]
496 pub fn to_u64(&self) -> Option<u64> {
497 self.as_number()?.to_u64()
498 }
499 #[must_use]
501 pub fn to_f64(&self) -> Option<f64> {
502 self.as_number()?.to_f64()
503 }
504 #[must_use]
506 pub fn to_f32(&self) -> Option<f32> {
507 self.as_number()?.to_f32()
508 }
509 #[must_use]
511 pub fn to_i32(&self) -> Option<i32> {
512 self.as_number()?.to_i32()
513 }
514 #[must_use]
516 pub fn to_u32(&self) -> Option<u32> {
517 self.as_number()?.to_u32()
518 }
519 #[must_use]
521 pub fn to_isize(&self) -> Option<isize> {
522 self.as_number()?.to_isize()
523 }
524 #[must_use]
526 pub fn to_usize(&self) -> Option<usize> {
527 self.as_number()?.to_usize()
528 }
529 #[must_use]
532 pub fn to_f64_lossy(&self) -> Option<f64> {
533 Some(self.as_number()?.to_f64_lossy())
534 }
535 #[must_use]
538 pub fn to_f32_lossy(&self) -> Option<f32> {
539 Some(self.as_number()?.to_f32_lossy())
540 }
541
542 #[must_use]
545 pub fn is_string(&self) -> bool {
546 self.type_tag() == TypeTag::StringOrNull && self.is_ptr()
547 }
548
549 unsafe fn as_string_unchecked(&self) -> &IString {
551 self.unchecked_cast_ref()
552 }
553
554 unsafe fn as_string_unchecked_mut(&mut self) -> &mut IString {
556 self.unchecked_cast_mut()
557 }
558
559 #[must_use]
562 pub fn as_string(&self) -> Option<&IString> {
563 if self.is_string() {
564 Some(unsafe { self.as_string_unchecked() })
566 } else {
567 None
568 }
569 }
570
571 pub fn as_string_mut(&mut self) -> Option<&mut IString> {
574 if self.is_string() {
575 Some(unsafe { self.as_string_unchecked_mut() })
577 } else {
578 None
579 }
580 }
581
582 pub fn into_string(self) -> Result<IString, IValue> {
588 if self.is_string() {
589 Ok(IString(self))
590 } else {
591 Err(self)
592 }
593 }
594
595 #[must_use]
598 pub fn is_array(&self) -> bool {
599 self.type_tag() == TypeTag::ArrayOrFalse && self.is_ptr()
600 }
601
602 unsafe fn as_array_unchecked(&self) -> &IArray {
604 self.unchecked_cast_ref()
605 }
606
607 unsafe fn as_array_unchecked_mut(&mut self) -> &mut IArray {
609 self.unchecked_cast_mut()
610 }
611
612 #[must_use]
615 pub fn as_array(&self) -> Option<&IArray> {
616 if self.is_array() {
617 Some(unsafe { self.as_array_unchecked() })
619 } else {
620 None
621 }
622 }
623
624 pub fn as_array_mut(&mut self) -> Option<&mut IArray> {
627 if self.is_array() {
628 Some(unsafe { self.as_array_unchecked_mut() })
630 } else {
631 None
632 }
633 }
634
635 pub fn into_array(self) -> Result<IArray, IValue> {
641 if self.is_array() {
642 Ok(IArray(self))
643 } else {
644 Err(self)
645 }
646 }
647
648 #[must_use]
651 pub fn is_object(&self) -> bool {
652 self.type_tag() == TypeTag::ObjectOrTrue && self.is_ptr()
653 }
654
655 unsafe fn as_object_unchecked(&self) -> &IObject {
657 self.unchecked_cast_ref()
658 }
659
660 unsafe fn as_object_unchecked_mut(&mut self) -> &mut IObject {
662 self.unchecked_cast_mut()
663 }
664
665 #[must_use]
668 pub fn as_object(&self) -> Option<&IObject> {
669 if self.is_object() {
670 Some(unsafe { self.as_object_unchecked() })
672 } else {
673 None
674 }
675 }
676
677 pub fn as_object_mut(&mut self) -> Option<&mut IObject> {
680 if self.is_object() {
681 Some(unsafe { self.as_object_unchecked_mut() })
683 } else {
684 None
685 }
686 }
687
688 pub fn into_object(self) -> Result<IObject, IValue> {
694 if self.is_object() {
695 Ok(IObject(self))
696 } else {
697 Err(self)
698 }
699 }
700}
701
702impl Clone for IValue {
703 fn clone(&self) -> Self {
704 match self.type_() {
705 ValueType::Null | ValueType::Bool => Self { ptr: self.ptr },
707 ValueType::Array => unsafe { self.as_array_unchecked() }.clone_impl(),
709 ValueType::Object => unsafe { self.as_object_unchecked() }.clone_impl(),
710 ValueType::String => unsafe { self.as_string_unchecked() }.clone_impl(),
711 ValueType::Number => unsafe { self.as_number_unchecked() }.clone_impl(),
712 }
713 }
714}
715
716impl Drop for IValue {
717 fn drop(&mut self) {
718 match self.type_() {
719 ValueType::Null | ValueType::Bool => {}
721 ValueType::Array => unsafe { self.as_array_unchecked_mut() }.drop_impl(),
723 ValueType::Object => unsafe { self.as_object_unchecked_mut() }.drop_impl(),
724 ValueType::String => unsafe { self.as_string_unchecked_mut() }.drop_impl(),
725 ValueType::Number => unsafe { self.as_number_unchecked_mut() }.drop_impl(),
726 }
727 }
728}
729
730impl Hash for IValue {
731 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
732 match self.type_() {
733 ValueType::Null | ValueType::Bool | ValueType::String => self.ptr.hash(state),
735 ValueType::Array => unsafe { self.as_array_unchecked() }.hash(state),
737 ValueType::Object => unsafe { self.as_object_unchecked() }.hash(state),
739 ValueType::Number => unsafe { self.as_number_unchecked() }.hash(state),
741 }
742 }
743}
744
745impl PartialEq for IValue {
746 fn eq(&self, other: &Self) -> bool {
747 let (t1, t2) = (self.type_(), other.type_());
748 if t1 == t2 {
749 unsafe {
751 match t1 {
752 ValueType::Null | ValueType::Bool | ValueType::String => self.ptr == other.ptr,
754 ValueType::Number => self.as_number_unchecked() == other.as_number_unchecked(),
755 ValueType::Array => self.as_array_unchecked() == other.as_array_unchecked(),
756 ValueType::Object => self.as_object_unchecked() == other.as_object_unchecked(),
757 }
758 }
759 } else {
760 false
761 }
762 }
763}
764
765impl Eq for IValue {}
766impl PartialOrd for IValue {
767 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
768 let (t1, t2) = (self.type_(), other.type_());
769 if t1 == t2 {
770 unsafe {
772 match t1 {
773 ValueType::Null => Some(Ordering::Equal),
775 ValueType::Bool => self.is_true().partial_cmp(&other.is_true()),
776 ValueType::String => self
777 .as_string_unchecked()
778 .partial_cmp(other.as_string_unchecked()),
779 ValueType::Number => self
780 .as_number_unchecked()
781 .partial_cmp(other.as_number_unchecked()),
782 ValueType::Array => self
783 .as_array_unchecked()
784 .partial_cmp(other.as_array_unchecked()),
785 ValueType::Object => None,
786 }
787 }
788 } else {
789 t1.partial_cmp(&t2)
790 }
791 }
792}
793
794mod private {
795 #[doc(hidden)]
796 pub trait Sealed {}
797 impl Sealed for usize {}
798 impl Sealed for &str {}
799 impl Sealed for &super::IString {}
800 impl<T: Sealed> Sealed for &T {}
801}
802
803pub trait ValueIndex: private::Sealed + Copy {
806 #[doc(hidden)]
807 fn index_into(self, v: &IValue) -> Option<&IValue>;
808
809 #[doc(hidden)]
810 fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue>;
811
812 #[doc(hidden)]
813 fn index_or_insert(self, v: &mut IValue) -> &mut IValue;
814
815 #[doc(hidden)]
816 fn remove(self, v: &mut IValue) -> Option<IValue>;
817}
818
819impl ValueIndex for usize {
820 fn index_into(self, v: &IValue) -> Option<&IValue> {
821 v.as_array().unwrap().get(self)
822 }
823
824 fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
825 v.as_array_mut().unwrap().get_mut(self)
826 }
827
828 fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
829 self.index_into_mut(v).unwrap()
830 }
831
832 fn remove(self, v: &mut IValue) -> Option<IValue> {
833 v.as_array_mut().unwrap().remove(self)
834 }
835}
836
837impl ValueIndex for &str {
838 fn index_into(self, v: &IValue) -> Option<&IValue> {
839 v.as_object().unwrap().get(&IString::intern(self))
840 }
841
842 fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
843 v.as_object_mut().unwrap().get_mut(&IString::intern(self))
844 }
845
846 fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
847 &mut v.as_object_mut().unwrap()[self]
848 }
849
850 fn remove(self, v: &mut IValue) -> Option<IValue> {
851 v.as_object_mut().unwrap().remove(self)
852 }
853}
854
855impl ValueIndex for &IString {
856 fn index_into(self, v: &IValue) -> Option<&IValue> {
857 v.as_object().unwrap().get(self)
858 }
859
860 fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
861 v.as_object_mut().unwrap().get_mut(self)
862 }
863
864 fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
865 &mut v.as_object_mut().unwrap()[self]
866 }
867
868 fn remove(self, v: &mut IValue) -> Option<IValue> {
869 v.as_object_mut().unwrap().remove(self)
870 }
871}
872
873impl<T: ValueIndex> ValueIndex for &T {
874 fn index_into(self, v: &IValue) -> Option<&IValue> {
875 (*self).index_into(v)
876 }
877
878 fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
879 (*self).index_into_mut(v)
880 }
881
882 fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
883 (*self).index_or_insert(v)
884 }
885
886 fn remove(self, v: &mut IValue) -> Option<IValue> {
887 (*self).remove(v)
888 }
889}
890
891impl<I: ValueIndex> Index<I> for IValue {
892 type Output = IValue;
893
894 #[inline]
895 fn index(&self, index: I) -> &IValue {
896 index.index_into(self).unwrap()
897 }
898}
899
900impl<I: ValueIndex> IndexMut<I> for IValue {
901 #[inline]
902 fn index_mut(&mut self, index: I) -> &mut IValue {
903 index.index_or_insert(self)
904 }
905}
906
907impl Debug for IValue {
908 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
909 unsafe {
910 match self.type_() {
911 ValueType::Null => f.write_str("null"),
913 ValueType::Bool => Debug::fmt(&self.is_true(), f),
914 ValueType::String => Debug::fmt(self.as_string_unchecked(), f),
916 ValueType::Array => Debug::fmt(self.as_array_unchecked(), f),
918 ValueType::Object => Debug::fmt(self.as_object_unchecked(), f),
920 ValueType::Number => Debug::fmt(self.as_number_unchecked(), f),
922 }
923 }
924 }
925}
926
927impl<T: Into<IValue>> From<Option<T>> for IValue {
928 fn from(other: Option<T>) -> Self {
929 if let Some(v) = other {
930 v.into()
931 } else {
932 Self::NULL
933 }
934 }
935}
936
937impl From<bool> for IValue {
938 fn from(other: bool) -> Self {
939 if other {
940 Self::TRUE
941 } else {
942 Self::FALSE
943 }
944 }
945}
946
947typed_conversions! {
948 INumber: i8, u8, i16, u16, i32, u32, i64, u64, isize, usize;
949 IString: String, &String, &mut String, &str, &mut str;
950 IArray:
951 Vec<T> where (T: Into<IValue>),
952 &[T] where (T: Into<IValue> + Clone);
953 IObject:
954 HashMap<K, V> where (K: Into<IString>, V: Into<IValue>),
955 BTreeMap<K, V> where (K: Into<IString>, V: Into<IValue>);
956}
957
958#[cfg(feature = "indexmap")]
959typed_conversions! {
960 IObject:
961 IndexMap<K, V> where (K: Into<IString>, V: Into<IValue>);
962}
963
964impl From<f32> for IValue {
965 fn from(v: f32) -> Self {
966 INumber::try_from(v).map(Into::into).unwrap_or(IValue::NULL)
967 }
968}
969
970impl From<f64> for IValue {
971 fn from(v: f64) -> Self {
972 INumber::try_from(v).map(Into::into).unwrap_or(IValue::NULL)
973 }
974}
975
976impl Default for IValue {
977 fn default() -> Self {
978 Self::NULL
979 }
980}
981
982#[cfg(test)]
983mod tests {
984 use super::*;
985
986 #[mockalloc::test]
987 fn can_use_literal() {
988 let x: IValue = ijson!({
989 "foo": "bar",
990 "x": [],
991 "y": ["hi", "there", 1, 2, null, false, true, 63.5],
992 "z": [false, {
993 "a": null
994 }, {}]
995 });
996 let y: IValue = serde_json::from_str(
997 r#"{
998 "foo": "bar",
999 "x": [],
1000 "y": ["hi", "there", 1, 2, null, false, true, 63.5],
1001 "z": [false, {
1002 "a": null
1003 }, {}]
1004 }"#,
1005 )
1006 .unwrap();
1007 assert_eq!(x, y);
1008 }
1009
1010 #[test]
1011 #[allow(clippy::redundant_clone)]
1012 fn test_null() {
1013 let x: IValue = IValue::NULL;
1014 assert!(x.is_null());
1015 assert_eq!(x.type_(), ValueType::Null);
1016 assert!(matches!(x.clone().destructure(), Destructured::Null));
1017 assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Null));
1018 assert!(matches!(x.clone().destructure_mut(), DestructuredMut::Null));
1019 }
1020
1021 #[test]
1022 fn test_bool() {
1023 for v in [true, false].iter().copied() {
1024 let mut x = IValue::from(v);
1025 assert!(x.is_bool());
1026 assert_eq!(x.type_(), ValueType::Bool);
1027 assert_eq!(x.to_bool(), Some(v));
1028 assert!(matches!(x.clone().destructure(), Destructured::Bool(u) if u == v));
1029 assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Bool(u) if u == v));
1030 assert!(
1031 matches!(x.clone().destructure_mut(), DestructuredMut::Bool(u) if u.get() == v)
1032 );
1033
1034 if let DestructuredMut::Bool(mut b) = x.destructure_mut() {
1035 b.set(!v);
1036 }
1037
1038 assert_eq!(x.to_bool(), Some(!v));
1039 }
1040 }
1041
1042 #[mockalloc::test]
1043 fn test_number() {
1044 for v in 300..400 {
1045 let mut x = IValue::from(v);
1046 assert!(x.is_number());
1047 assert_eq!(x.type_(), ValueType::Number);
1048 assert_eq!(x.to_i32(), Some(v));
1049 assert_eq!(x.to_u32(), Some(v as u32));
1050 assert_eq!(x.to_i64(), Some(i64::from(v)));
1051 assert_eq!(x.to_u64(), Some(v as u64));
1052 assert_eq!(x.to_isize(), Some(v as isize));
1053 assert_eq!(x.to_usize(), Some(v as usize));
1054 assert_eq!(x.as_number(), Some(&v.into()));
1055 assert_eq!(x.as_number_mut(), Some(&mut v.into()));
1056 assert!(matches!(x.clone().destructure(), Destructured::Number(u) if u == v.into()));
1057 assert!(
1058 matches!(x.clone().destructure_ref(), DestructuredRef::Number(u) if *u == v.into())
1059 );
1060 assert!(
1061 matches!(x.clone().destructure_mut(), DestructuredMut::Number(u) if *u == v.into())
1062 );
1063 }
1064 }
1065
1066 #[mockalloc::test]
1067 fn test_string() {
1068 for v in 0..10 {
1069 let s = v.to_string();
1070 let mut x = IValue::from(&s);
1071 assert!(x.is_string());
1072 assert_eq!(x.type_(), ValueType::String);
1073 assert_eq!(x.as_string(), Some(&IString::intern(&s)));
1074 assert_eq!(x.as_string_mut(), Some(&mut IString::intern(&s)));
1075 assert!(matches!(x.clone().destructure(), Destructured::String(u) if u == s));
1076 assert!(matches!(x.clone().destructure_ref(), DestructuredRef::String(u) if *u == s));
1077 assert!(matches!(x.clone().destructure_mut(), DestructuredMut::String(u) if *u == s));
1078 }
1079 }
1080
1081 #[mockalloc::test]
1082 fn test_array() {
1083 for v in 0..10 {
1084 let mut a: IArray = (0..v).collect();
1085 let mut x = IValue::from(a.clone());
1086 assert!(x.is_array());
1087 assert_eq!(x.type_(), ValueType::Array);
1088 assert_eq!(x.as_array(), Some(&a));
1089 assert_eq!(x.as_array_mut(), Some(&mut a));
1090 assert!(matches!(x.clone().destructure(), Destructured::Array(u) if u == a));
1091 assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Array(u) if *u == a));
1092 assert!(matches!(x.clone().destructure_mut(), DestructuredMut::Array(u) if *u == a));
1093 }
1094 }
1095
1096 #[mockalloc::test]
1097 fn test_object() {
1098 for v in 0..10 {
1099 let mut o: IObject = (0..v).map(|i| (i.to_string(), i)).collect();
1100 let mut x = IValue::from(o.clone());
1101 assert!(x.is_object());
1102 assert_eq!(x.type_(), ValueType::Object);
1103 assert_eq!(x.as_object(), Some(&o));
1104 assert_eq!(x.as_object_mut(), Some(&mut o));
1105 assert!(matches!(x.clone().destructure(), Destructured::Object(u) if u == o));
1106 assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Object(u) if *u == o));
1107 assert!(matches!(x.clone().destructure_mut(), DestructuredMut::Object(u) if *u == o));
1108 }
1109 }
1110
1111 #[mockalloc::test]
1112 fn test_into_object_for_object() {
1113 let o: IObject = (0..10).map(|i| (i.to_string(), i)).collect();
1114 let x = IValue::from(o.clone());
1115
1116 assert_eq!(x.into_object(), Ok(o));
1117 }
1118}