Skip to main content

ijson/
value.rs

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/// Stores an arbitrary JSON value.
20///
21/// Compared to [`serde_json::Value`] this type is a struct rather than an enum, as
22/// this is necessary to achieve the important size reductions. This means that
23/// you cannot directly `match` on an `IValue` to determine its type.
24///
25/// Instead, an `IValue` offers several ways to get at the inner type:
26///
27/// - Destructuring using `IValue::destructure[{_ref,_mut}]()`
28///
29///   These methods return wrapper enums which you _can_ directly match on, so
30///   these methods are the most direct replacement for matching on a `Value`.
31///
32/// - Borrowing using `IValue::as_{array,object,string,number}[_mut]()`
33///
34///   These methods return an `Option` of the corresponding reference if the
35///   type matches the one expected. These methods exist for the variants
36///   which are not `Copy`.
37///
38/// - Converting using `IValue::into_{array,object,string,number}()`
39///
40///   These methods return a `Result` of the corresponding type (or the
41///   original `IValue` if the type is not the one expected). These methods
42///   also exist for the variants which are not `Copy`.
43///
44/// - Getting using `IValue::to_{bool,{i,u,f}{32,64}}[_lossy]}()`
45///
46///   These methods return an `Option` of the corresponding type. These
47///   methods exist for types where the return value would be `Copy`.
48///
49/// You can also check the type of the inner value without specifically
50/// accessing it using one of these methods:
51///
52/// - Checking using `IValue::is_{null,bool,number,string,array,object,true,false}()`
53///
54///   These methods exist for all types.
55///
56/// - Getting the type with [`IValue::type_`]
57///
58///   This method returns the [`ValueType`] enum, which has a variant for each of the
59///   six JSON types.
60#[repr(transparent)]
61pub struct IValue {
62    ptr: NonNull<u8>,
63}
64
65/// Enum returned by [`IValue::destructure`] to allow matching on the type of
66/// an owned [`IValue`].
67#[derive(Debug, Clone, PartialEq, Eq)]
68pub enum Destructured {
69    /// Null.
70    Null,
71    /// Boolean.
72    Bool(bool),
73    /// Number.
74    Number(INumber),
75    /// String.
76    String(IString),
77    /// Array.
78    Array(IArray),
79    /// Object.
80    Object(IObject),
81}
82
83impl Destructured {
84    /// Convert to the borrowed form of thie enum.
85    #[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/// Enum returned by [`IValue::destructure_ref`] to allow matching on the type of
100/// a reference to an [`IValue`].
101#[derive(Debug, Copy, Clone, PartialEq, Eq)]
102pub enum DestructuredRef<'a> {
103    /// Null.
104    Null,
105    /// Boolean.
106    /// [`IValue`]s do not directly contain booleans, so the value is returned
107    /// directly instead of as a reference.
108    Bool(bool),
109    /// Number.
110    Number(&'a INumber),
111    /// String.
112    String(&'a IString),
113    /// Array.
114    Array(&'a IArray),
115    /// Object.
116    Object(&'a IObject),
117}
118
119/// Enum returned by [`IValue::destructure_mut`] to allow matching on the type of
120/// a mutable reference to an [`IValue`].
121#[derive(Debug)]
122pub enum DestructuredMut<'a> {
123    /// Null.
124    Null,
125    /// Boolean.
126    /// [`IValue`]s do not directly contain booleans, so this variant contains
127    /// a proxy type which allows getting and setting the original [`IValue`]
128    /// as a `bool`.
129    Bool(BoolMut<'a>),
130    /// Number.
131    Number(&'a mut INumber),
132    /// String.
133    String(&'a mut IString),
134    /// Array.
135    Array(&'a mut IArray),
136    /// Object.
137    Object(&'a mut IObject),
138}
139
140/// A proxy type which imitates a `&mut bool`.
141#[derive(Debug)]
142pub struct BoolMut<'a>(&'a mut IValue);
143
144impl BoolMut<'_> {
145    /// Set the [`IValue`] referenced by this proxy type to either
146    /// `true` or `false`.
147    pub fn set(&mut self, value: bool) {
148        *self.0 = value.into();
149    }
150    /// Get the boolean value stored in the [`IValue`] from which
151    /// this proxy was obtained.
152    #[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        // Safety: `% ALIGNMENT` can only return valid variants
183        unsafe { mem::transmute(other % ALIGNMENT) }
184    }
185}
186
187/// Enum which distinguishes the six JSON types.
188#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
189pub enum ValueType {
190    // Stored inline
191    /// Null.
192    Null,
193    /// Boolean.
194    Bool,
195
196    // Stored behind pointer
197    /// Number.
198    Number,
199    /// String.
200    String,
201    /// Array.
202    Array,
203    /// Object.
204    Object,
205}
206
207unsafe impl Send for IValue {}
208unsafe impl Sync for IValue {}
209
210impl IValue {
211    // Safety: Tag must not be `Number`
212    const unsafe fn new_inline(tag: TypeTag) -> Self {
213        Self {
214            ptr: NonNull::new_unchecked(tag as usize as *mut u8),
215        }
216    }
217    // Safety: Pointer must be non-null and aligned to at least ALIGNMENT
218    pub(crate) unsafe fn new_ptr(p: NonNull<u8>, tag: TypeTag) -> Self {
219        Self {
220            ptr: p.add(tag as usize),
221        }
222    }
223    // Safety: Reference must be aligned to at least ALIGNMENT
224    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    /// JSON `null`.
229    pub const NULL: Self = unsafe { Self::new_inline(TypeTag::StringOrNull) };
230    /// JSON `false`.
231    pub const FALSE: Self = unsafe { Self::new_inline(TypeTag::ArrayOrFalse) };
232    /// JSON `true`.
233    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    // Safety: Must only be called on non-inline types
239    pub(crate) unsafe fn ptr(&self) -> NonNull<u8> {
240        self.ptr.offset(-((self.ptr_usize() % ALIGNMENT) as isize))
241    }
242    // Safety: Pointer must be non-null and aligned to at least ALIGNMENT
243    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    // Safety: Reference must be aligned to at least ALIGNMENT
248    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    /// Returns the type of this value.
268    #[must_use]
269    pub fn type_(&self) -> ValueType {
270        match (self.type_tag(), self.is_ptr()) {
271            // Pointers
272            (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            // Non-pointers
278            (TypeTag::StringOrNull, false) => ValueType::Null,
279            (TypeTag::ArrayOrFalse, false) | (TypeTag::ObjectOrTrue, false) => ValueType::Bool,
280
281            // Safety: due to invariants on IValue
282            _ => unsafe { unreachable_unchecked() },
283        }
284    }
285
286    /// Destructures this value into an enum which can be `match`ed on.
287    #[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    /// Destructures a reference to this value into an enum which can be `match`ed on.
300    #[must_use]
301    pub fn destructure_ref<'a>(&'a self) -> DestructuredRef<'a> {
302        // Safety: we check the type
303        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    /// Destructures a mutable reference to this value into an enum which can be `match`ed on.
316    pub fn destructure_mut<'a>(&'a mut self) -> DestructuredMut<'a> {
317        // Safety: we check the type
318        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    /// Indexes into this value with a number or string.
331    /// Panics if the value is not an array or object.
332    /// Panics if attempting to index an array with a string.
333    /// Panics if attempting to index an object with a number.
334    /// Returns `None` if the index type is correct, but there is
335    /// no value at this index.
336    pub fn get(&self, index: impl ValueIndex) -> Option<&IValue> {
337        index.index_into(self)
338    }
339
340    /// Mutably indexes into this value with a number or string.
341    /// Panics if the value is not an array or object.
342    /// Panics if attempting to index an array with a string.
343    /// Panics if attempting to index an object with a number.
344    /// Returns `None` if the index type is correct, but there is
345    /// no value at this index.
346    pub fn get_mut(&mut self, index: impl ValueIndex) -> Option<&mut IValue> {
347        index.index_into_mut(self)
348    }
349
350    /// Removes a value at the specified numberic or string index.
351    /// Panics if this is not an array or object.
352    /// Panics if attempting to index an array with a string.
353    /// Panics if attempting to index an object with a number.
354    /// Returns `None` if the index type is correct, but there is
355    /// no value at this index.
356    pub fn remove(&mut self, index: impl ValueIndex) -> Option<IValue> {
357        index.remove(self)
358    }
359
360    /// Takes this value, replacing it with [`IValue::NULL`].
361    pub fn take(&mut self) -> IValue {
362        mem::replace(self, IValue::NULL)
363    }
364
365    /// Returns the length of this value if it is an array or object.
366    /// Returns `None` for other types.
367    #[must_use]
368    pub fn len(&self) -> Option<usize> {
369        match self.type_() {
370            // Safety: checked type
371            ValueType::Array => Some(unsafe { self.as_array_unchecked().len() }),
372            // Safety: checked type
373            ValueType::Object => Some(unsafe { self.as_object_unchecked().len() }),
374            _ => None,
375        }
376    }
377
378    /// Returns whether this value is empty if it is an array or object.
379    /// Returns `None` for other types.
380    #[must_use]
381    pub fn is_empty(&self) -> Option<bool> {
382        match self.type_() {
383            // Safety: checked type
384            ValueType::Array => Some(unsafe { self.as_array_unchecked().is_empty() }),
385            // Safety: checked type
386            ValueType::Object => Some(unsafe { self.as_object_unchecked().is_empty() }),
387            _ => None,
388        }
389    }
390
391    // # Null methods
392    /// Returns `true` if this is the `null` value.
393    #[must_use]
394    pub fn is_null(&self) -> bool {
395        self.ptr == Self::NULL.ptr
396    }
397
398    // # Bool methods
399    /// Returns `true` if this is a boolean.
400    #[must_use]
401    pub fn is_bool(&self) -> bool {
402        self.ptr == Self::TRUE.ptr || self.ptr == Self::FALSE.ptr
403    }
404
405    /// Returns `true` if this is the `true` value.
406    #[must_use]
407    pub fn is_true(&self) -> bool {
408        self.ptr == Self::TRUE.ptr
409    }
410
411    /// Returns `true` if this is the `false` value.
412    #[must_use]
413    pub fn is_false(&self) -> bool {
414        self.ptr == Self::FALSE.ptr
415    }
416
417    /// Converts this value to a `bool`.
418    /// Returns `None` if it's not a boolean.
419    #[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    // # Number methods
429    /// Returns `true` if this is a number.
430    #[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    // Safety: Must be a string
444    unsafe fn as_number_unchecked(&self) -> &INumber {
445        self.unchecked_cast_ref()
446    }
447
448    // Safety: Must be a string
449    unsafe fn as_number_unchecked_mut(&mut self) -> &mut INumber {
450        self.unchecked_cast_mut()
451    }
452
453    /// Gets a reference to this value as an [`INumber`].
454    /// Returns `None` if it's not a number.
455    #[must_use]
456    pub fn as_number(&self) -> Option<&INumber> {
457        if self.is_number() {
458            // Safety: INumber is a `#[repr(transparent)]` wrapper around IValue
459            Some(unsafe { self.as_number_unchecked() })
460        } else {
461            None
462        }
463    }
464
465    /// Gets a mutable reference to this value as an [`INumber`].
466    /// Returns `None` if it's not a number.
467    pub fn as_number_mut(&mut self) -> Option<&mut INumber> {
468        if self.is_number() {
469            // Safety: INumber is a `#[repr(transparent)]` wrapper around IValue
470            Some(unsafe { self.as_number_unchecked_mut() })
471        } else {
472            None
473        }
474    }
475
476    /// Converts this value to an [`INumber`].
477    ///
478    /// # Errors
479    ///
480    /// Returns `Err(self)` if it's not a number.
481    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    /// Converts this value to an i64 if it is a number that can be represented exactly.
490    #[must_use]
491    pub fn to_i64(&self) -> Option<i64> {
492        self.as_number()?.to_i64()
493    }
494    /// Converts this value to a u64 if it is a number that can be represented exactly.
495    #[must_use]
496    pub fn to_u64(&self) -> Option<u64> {
497        self.as_number()?.to_u64()
498    }
499    /// Converts this value to an f64 if it is a number that can be represented exactly.
500    #[must_use]
501    pub fn to_f64(&self) -> Option<f64> {
502        self.as_number()?.to_f64()
503    }
504    /// Converts this value to an f32 if it is a number that can be represented exactly.
505    #[must_use]
506    pub fn to_f32(&self) -> Option<f32> {
507        self.as_number()?.to_f32()
508    }
509    /// Converts this value to an i32 if it is a number that can be represented exactly.
510    #[must_use]
511    pub fn to_i32(&self) -> Option<i32> {
512        self.as_number()?.to_i32()
513    }
514    /// Converts this value to a u32 if it is a number that can be represented exactly.
515    #[must_use]
516    pub fn to_u32(&self) -> Option<u32> {
517        self.as_number()?.to_u32()
518    }
519    /// Converts this value to an isize if it is a number that can be represented exactly.
520    #[must_use]
521    pub fn to_isize(&self) -> Option<isize> {
522        self.as_number()?.to_isize()
523    }
524    /// Converts this value to a usize if it is a number that can be represented exactly.
525    #[must_use]
526    pub fn to_usize(&self) -> Option<usize> {
527        self.as_number()?.to_usize()
528    }
529    /// Converts this value to an f64 if it is a number, potentially losing precision
530    /// in the process.
531    #[must_use]
532    pub fn to_f64_lossy(&self) -> Option<f64> {
533        Some(self.as_number()?.to_f64_lossy())
534    }
535    /// Converts this value to an f32 if it is a number, potentially losing precision
536    /// in the process.
537    #[must_use]
538    pub fn to_f32_lossy(&self) -> Option<f32> {
539        Some(self.as_number()?.to_f32_lossy())
540    }
541
542    // # String methods
543    /// Returns `true` if this is a string.
544    #[must_use]
545    pub fn is_string(&self) -> bool {
546        self.type_tag() == TypeTag::StringOrNull && self.is_ptr()
547    }
548
549    // Safety: Must be a string
550    unsafe fn as_string_unchecked(&self) -> &IString {
551        self.unchecked_cast_ref()
552    }
553
554    // Safety: Must be a string
555    unsafe fn as_string_unchecked_mut(&mut self) -> &mut IString {
556        self.unchecked_cast_mut()
557    }
558
559    /// Gets a reference to this value as an [`IString`].
560    /// Returns `None` if it's not a string.
561    #[must_use]
562    pub fn as_string(&self) -> Option<&IString> {
563        if self.is_string() {
564            // Safety: IString is a `#[repr(transparent)]` wrapper around IValue
565            Some(unsafe { self.as_string_unchecked() })
566        } else {
567            None
568        }
569    }
570
571    /// Gets a mutable reference to this value as an [`IString`].
572    /// Returns `None` if it's not a string.
573    pub fn as_string_mut(&mut self) -> Option<&mut IString> {
574        if self.is_string() {
575            // Safety: IString is a `#[repr(transparent)]` wrapper around IValue
576            Some(unsafe { self.as_string_unchecked_mut() })
577        } else {
578            None
579        }
580    }
581
582    /// Converts this value to an [`IString`].
583    ///
584    /// # Errors
585    ///
586    /// Returns `Err(self)` if it's not a string.
587    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    // # Array methods
596    /// Returns `true` if this is an array.
597    #[must_use]
598    pub fn is_array(&self) -> bool {
599        self.type_tag() == TypeTag::ArrayOrFalse && self.is_ptr()
600    }
601
602    // Safety: Must be an array
603    unsafe fn as_array_unchecked(&self) -> &IArray {
604        self.unchecked_cast_ref()
605    }
606
607    // Safety: Must be an array
608    unsafe fn as_array_unchecked_mut(&mut self) -> &mut IArray {
609        self.unchecked_cast_mut()
610    }
611
612    /// Gets a reference to this value as an [`IArray`].
613    /// Returns `None` if it's not an array.
614    #[must_use]
615    pub fn as_array(&self) -> Option<&IArray> {
616        if self.is_array() {
617            // Safety: IArray is a `#[repr(transparent)]` wrapper around IValue
618            Some(unsafe { self.as_array_unchecked() })
619        } else {
620            None
621        }
622    }
623
624    /// Gets a mutable reference to this value as an [`IArray`].
625    /// Returns `None` if it's not an array.
626    pub fn as_array_mut(&mut self) -> Option<&mut IArray> {
627        if self.is_array() {
628            // Safety: IArray is a `#[repr(transparent)]` wrapper around IValue
629            Some(unsafe { self.as_array_unchecked_mut() })
630        } else {
631            None
632        }
633    }
634
635    /// Converts this value to an [`IArray`].
636    ///
637    /// # Errors
638    ///
639    /// Returns `Err(self)` if it's not an array.
640    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    // # Object methods
649    /// Returns `true` if this is an object.
650    #[must_use]
651    pub fn is_object(&self) -> bool {
652        self.type_tag() == TypeTag::ObjectOrTrue && self.is_ptr()
653    }
654
655    // Safety: Must be an array
656    unsafe fn as_object_unchecked(&self) -> &IObject {
657        self.unchecked_cast_ref()
658    }
659
660    // Safety: Must be an array
661    unsafe fn as_object_unchecked_mut(&mut self) -> &mut IObject {
662        self.unchecked_cast_mut()
663    }
664
665    /// Gets a reference to this value as an [`IObject`].
666    /// Returns `None` if it's not an object.
667    #[must_use]
668    pub fn as_object(&self) -> Option<&IObject> {
669        if self.is_object() {
670            // Safety: IObject is a `#[repr(transparent)]` wrapper around IValue
671            Some(unsafe { self.as_object_unchecked() })
672        } else {
673            None
674        }
675    }
676
677    /// Gets a mutable reference to this value as an [`IObject`].
678    /// Returns `None` if it's not an object.
679    pub fn as_object_mut(&mut self) -> Option<&mut IObject> {
680        if self.is_object() {
681            // Safety: IObject is a `#[repr(transparent)]` wrapper around IValue
682            Some(unsafe { self.as_object_unchecked_mut() })
683        } else {
684            None
685        }
686    }
687
688    /// Converts this value to an [`IObject`].
689    ///
690    /// # Errors
691    ///
692    /// Returns `Err(self)` if it's not an object.
693    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            // Inline types can be trivially copied
706            ValueType::Null | ValueType::Bool => Self { ptr: self.ptr },
707            // Safety: We checked the type
708            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            // Inline types can be trivially dropped
720            ValueType::Null | ValueType::Bool => {}
721            // Safety: We checked the type
722            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            // Inline and interned types can be trivially hashed
734            ValueType::Null | ValueType::Bool | ValueType::String => self.ptr.hash(state),
735            // Safety: We checked the type
736            ValueType::Array => unsafe { self.as_array_unchecked() }.hash(state),
737            // Safety: We checked the type
738            ValueType::Object => unsafe { self.as_object_unchecked() }.hash(state),
739            // Safety: We checked the type
740            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            // Safety: Only methods for the appropriate type are called
750            unsafe {
751                match t1 {
752                    // Inline and interned types can be trivially compared
753                    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            // Safety: Only methods for the appropriate type are called
771            unsafe {
772                match t1 {
773                    // Inline and interned types can be trivially compared
774                    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
803/// Trait which abstracts over the various number and string types
804/// which can be used to index into an [`IValue`].
805pub 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                // Inline and interned types can be trivially hashed
912                ValueType::Null => f.write_str("null"),
913                ValueType::Bool => Debug::fmt(&self.is_true(), f),
914                // Safety: We checked the type
915                ValueType::String => Debug::fmt(self.as_string_unchecked(), f),
916                // Safety: We checked the type
917                ValueType::Array => Debug::fmt(self.as_array_unchecked(), f),
918                // Safety: We checked the type
919                ValueType::Object => Debug::fmt(self.as_object_unchecked(), f),
920                // Safety: We checked the type
921                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}