Skip to main content

feldera_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)]
61#[derive(size_of::SizeOf)]
62pub struct IValue {
63    ptr: NonNull<u8>,
64}
65
66impl Ord for IValue {
67    fn cmp(&self, other: &Self) -> Ordering {
68        self.partial_cmp(other).unwrap_or(Ordering::Equal)
69    }
70}
71
72/// Enum returned by [`IValue::destructure`] to allow matching on the type of
73/// an owned [`IValue`].
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub enum Destructured {
76    /// Null.
77    Null,
78    /// Boolean.
79    Bool(bool),
80    /// Number.
81    Number(INumber),
82    /// String.
83    String(IString),
84    /// Array.
85    Array(IArray),
86    /// Object.
87    Object(IObject),
88}
89
90impl Destructured {
91    /// Convert to the borrowed form of thie enum.
92    #[must_use]
93    pub fn as_ref(&self) -> DestructuredRef {
94        use DestructuredRef::{Array, Bool, Null, Number, Object, String};
95        match self {
96            Self::Null => Null,
97            Self::Bool(b) => Bool(*b),
98            Self::Number(v) => Number(v),
99            Self::String(v) => String(v),
100            Self::Array(v) => Array(v),
101            Self::Object(v) => Object(v),
102        }
103    }
104}
105
106/// Enum returned by [`IValue::destructure_ref`] to allow matching on the type of
107/// a reference to an [`IValue`].
108#[derive(Debug, Copy, Clone, PartialEq, Eq)]
109pub enum DestructuredRef<'a> {
110    /// Null.
111    Null,
112    /// Boolean.
113    /// [`IValue`]s do not directly contain booleans, so the value is returned
114    /// directly instead of as a reference.
115    Bool(bool),
116    /// Number.
117    Number(&'a INumber),
118    /// String.
119    String(&'a IString),
120    /// Array.
121    Array(&'a IArray),
122    /// Object.
123    Object(&'a IObject),
124}
125
126/// Enum returned by [`IValue::destructure_mut`] to allow matching on the type of
127/// a mutable reference to an [`IValue`].
128#[derive(Debug)]
129pub enum DestructuredMut<'a> {
130    /// Null.
131    Null,
132    /// Boolean.
133    /// [`IValue`]s do not directly contain booleans, so this variant contains
134    /// a proxy type which allows getting and setting the original [`IValue`]
135    /// as a `bool`.
136    Bool(BoolMut<'a>),
137    /// Number.
138    Number(&'a mut INumber),
139    /// String.
140    String(&'a mut IString),
141    /// Array.
142    Array(&'a mut IArray),
143    /// Object.
144    Object(&'a mut IObject),
145}
146
147/// A proxy type which imitates a `&mut bool`.
148#[derive(Debug)]
149pub struct BoolMut<'a>(&'a mut IValue);
150
151impl<'a> BoolMut<'a> {
152    /// Set the [`IValue`] referenced by this proxy type to either
153    /// `true` or `false`.
154    pub fn set(&mut self, value: bool) {
155        *self.0 = value.into();
156    }
157    /// Get the boolean value stored in the [`IValue`] from which
158    /// this proxy was obtained.
159    #[must_use]
160    pub fn get(&self) -> bool {
161        self.0.is_true()
162    }
163}
164
165impl<'a> Deref for BoolMut<'a> {
166    type Target = bool;
167    fn deref(&self) -> &bool {
168        if self.get() {
169            &true
170        } else {
171            &false
172        }
173    }
174}
175
176pub(crate) const ALIGNMENT: usize = 4;
177
178#[repr(usize)]
179#[derive(Copy, Clone, Debug, PartialEq, Eq)]
180pub(crate) enum TypeTag {
181    Number = 0,
182    StringOrNull = 1,
183    ArrayOrFalse = 2,
184    ObjectOrTrue = 3,
185}
186
187impl From<usize> for TypeTag {
188    fn from(other: usize) -> Self {
189        // Safety: `% ALIGNMENT` can only return valid variants
190        unsafe { mem::transmute(other % ALIGNMENT) }
191    }
192}
193
194/// Enum which distinguishes the six JSON types.
195#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
196pub enum ValueType {
197    // Stored inline
198    /// Null.
199    Null,
200    /// Boolean.
201    Bool,
202
203    // Stored behind pointer
204    /// Number.
205    Number,
206    /// String.
207    String,
208    /// Array.
209    Array,
210    /// Object.
211    Object,
212}
213
214unsafe impl Send for IValue {}
215unsafe impl Sync for IValue {}
216
217impl IValue {
218    // Safety: Tag must not be `Number`
219    const unsafe fn new_inline(tag: TypeTag) -> Self {
220        Self {
221            ptr: NonNull::new_unchecked(tag as usize as *mut u8),
222        }
223    }
224    // Safety: Pointer must be non-null and aligned to at least ALIGNMENT
225    pub(crate) unsafe fn new_ptr(p: *mut u8, tag: TypeTag) -> Self {
226        Self {
227            ptr: NonNull::new_unchecked(p.add(tag as usize)),
228        }
229    }
230    // Safety: Reference must be aligned to at least ALIGNMENT
231    pub(crate) unsafe fn new_ref<T>(r: &T, tag: TypeTag) -> Self {
232        Self::new_ptr(r as *const _ as *mut u8, tag)
233    }
234
235    /// JSON `null`.
236    pub const NULL: Self = unsafe { Self::new_inline(TypeTag::StringOrNull) };
237    /// JSON `false`.
238    pub const FALSE: Self = unsafe { Self::new_inline(TypeTag::ArrayOrFalse) };
239    /// JSON `true`.
240    pub const TRUE: Self = unsafe { Self::new_inline(TypeTag::ObjectOrTrue) };
241
242    pub(crate) fn ptr_usize(&self) -> usize {
243        self.ptr.as_ptr() as usize
244    }
245    // Safety: Must only be called on non-inline types
246    pub(crate) unsafe fn ptr(&self) -> *mut u8 {
247        self.ptr
248            .as_ptr()
249            .wrapping_offset(-((self.ptr_usize() % ALIGNMENT) as isize))
250    }
251    // Safety: Pointer must be non-null and aligned to at least ALIGNMENT
252    pub(crate) unsafe fn set_ptr(&mut self, ptr: *mut u8) {
253        let tag = self.type_tag();
254        self.ptr = NonNull::new_unchecked(ptr.add(tag as usize));
255    }
256    // Safety: Reference must be aligned to at least ALIGNMENT
257    pub(crate) unsafe fn set_ref<T>(&mut self, r: &T) {
258        self.set_ptr(r as *const T as *mut u8);
259    }
260    pub(crate) unsafe fn raw_copy(&self) -> Self {
261        Self { ptr: self.ptr }
262    }
263    pub(crate) fn raw_eq(&self, other: &Self) -> bool {
264        self.ptr == other.ptr
265    }
266    pub(crate) fn raw_hash<H: std::hash::Hasher>(&self, state: &mut H) {
267        self.ptr.hash(state);
268    }
269    fn is_ptr(&self) -> bool {
270        self.ptr_usize() >= ALIGNMENT
271    }
272    fn type_tag(&self) -> TypeTag {
273        self.ptr_usize().into()
274    }
275
276    /// Returns the type of this value.
277    #[must_use]
278    pub fn type_(&self) -> ValueType {
279        match (self.type_tag(), self.is_ptr()) {
280            // Pointers
281            (TypeTag::Number, true) => ValueType::Number,
282            (TypeTag::StringOrNull, true) => ValueType::String,
283            (TypeTag::ArrayOrFalse, true) => ValueType::Array,
284            (TypeTag::ObjectOrTrue, true) => ValueType::Object,
285
286            // Non-pointers
287            (TypeTag::StringOrNull, false) => ValueType::Null,
288            (TypeTag::ArrayOrFalse, false) | (TypeTag::ObjectOrTrue, false) => ValueType::Bool,
289
290            // Safety: due to invariants on IValue
291            _ => unsafe { unreachable_unchecked() },
292        }
293    }
294
295    /// Destructures this value into an enum which can be `match`ed on.
296    #[must_use]
297    pub fn destructure(self) -> Destructured {
298        match self.type_() {
299            ValueType::Null => Destructured::Null,
300            ValueType::Bool => Destructured::Bool(self.is_true()),
301            ValueType::Number => Destructured::Number(INumber(self)),
302            ValueType::String => Destructured::String(IString(self)),
303            ValueType::Array => Destructured::Array(IArray(self)),
304            ValueType::Object => Destructured::Object(IObject(self)),
305        }
306    }
307
308    /// Destructures a reference to this value into an enum which can be `match`ed on.
309    #[must_use]
310    pub fn destructure_ref(&self) -> DestructuredRef {
311        // Safety: we check the type
312        unsafe {
313            match self.type_() {
314                ValueType::Null => DestructuredRef::Null,
315                ValueType::Bool => DestructuredRef::Bool(self.is_true()),
316                ValueType::Number => DestructuredRef::Number(self.as_number_unchecked()),
317                ValueType::String => DestructuredRef::String(self.as_string_unchecked()),
318                ValueType::Array => DestructuredRef::Array(self.as_array_unchecked()),
319                ValueType::Object => DestructuredRef::Object(self.as_object_unchecked()),
320            }
321        }
322    }
323
324    /// Destructures a mutable reference to this value into an enum which can be `match`ed on.
325    pub fn destructure_mut(&mut self) -> DestructuredMut {
326        // Safety: we check the type
327        unsafe {
328            match self.type_() {
329                ValueType::Null => DestructuredMut::Null,
330                ValueType::Bool => DestructuredMut::Bool(BoolMut(self)),
331                ValueType::Number => DestructuredMut::Number(self.as_number_unchecked_mut()),
332                ValueType::String => DestructuredMut::String(self.as_string_unchecked_mut()),
333                ValueType::Array => DestructuredMut::Array(self.as_array_unchecked_mut()),
334                ValueType::Object => DestructuredMut::Object(self.as_object_unchecked_mut()),
335            }
336        }
337    }
338
339    /// Indexes into this value with a number or string.
340    /// Panics if the value is not an array or object.
341    /// Panics if attempting to index an array with a string.
342    /// Panics if attempting to index an object with a number.
343    /// Returns `None` if the index type is correct, but there is
344    /// no value at this index.
345    pub fn get(&self, index: impl ValueIndex) -> Option<&IValue> {
346        index.index_into(self)
347    }
348
349    /// Mutably indexes into this value with a number or string.
350    /// Panics if the value is not an array or object.
351    /// Panics if attempting to index an array with a string.
352    /// Panics if attempting to index an object with a number.
353    /// Returns `None` if the index type is correct, but there is
354    /// no value at this index.
355    pub fn get_mut(&mut self, index: impl ValueIndex) -> Option<&mut IValue> {
356        index.index_into_mut(self)
357    }
358
359    /// Removes a value at the specified numberic or string index.
360    /// Panics if this is not an array or object.
361    /// Panics if attempting to index an array with a string.
362    /// Panics if attempting to index an object with a number.
363    /// Returns `None` if the index type is correct, but there is
364    /// no value at this index.
365    pub fn remove(&mut self, index: impl ValueIndex) -> Option<IValue> {
366        index.remove(self)
367    }
368
369    /// Takes this value, replacing it with [`IValue::NULL`].
370    pub fn take(&mut self) -> IValue {
371        mem::replace(self, IValue::NULL)
372    }
373
374    /// Returns the length of this value if it is an array or object.
375    /// Returns `None` for other types.
376    #[must_use]
377    pub fn len(&self) -> Option<usize> {
378        match self.type_() {
379            // Safety: checked type
380            ValueType::Array => Some(unsafe { self.as_array_unchecked().len() }),
381            // Safety: checked type
382            ValueType::Object => Some(unsafe { self.as_object_unchecked().len() }),
383            _ => None,
384        }
385    }
386
387    /// Returns whether this value is empty if it is an array or object.
388    /// Returns `None` for other types.
389    #[must_use]
390    pub fn is_empty(&self) -> Option<bool> {
391        match self.type_() {
392            // Safety: checked type
393            ValueType::Array => Some(unsafe { self.as_array_unchecked().is_empty() }),
394            // Safety: checked type
395            ValueType::Object => Some(unsafe { self.as_object_unchecked().is_empty() }),
396            _ => None,
397        }
398    }
399
400    // # Null methods
401    /// Returns `true` if this is the `null` value.
402    #[must_use]
403    pub fn is_null(&self) -> bool {
404        self.ptr == Self::NULL.ptr
405    }
406
407    // # Bool methods
408    /// Returns `true` if this is a boolean.
409    #[must_use]
410    pub fn is_bool(&self) -> bool {
411        self.ptr == Self::TRUE.ptr || self.ptr == Self::FALSE.ptr
412    }
413
414    /// Returns `true` if this is the `true` value.
415    #[must_use]
416    pub fn is_true(&self) -> bool {
417        self.ptr == Self::TRUE.ptr
418    }
419
420    /// Returns `true` if this is the `false` value.
421    #[must_use]
422    pub fn is_false(&self) -> bool {
423        self.ptr == Self::FALSE.ptr
424    }
425
426    /// Converts this value to a `bool`.
427    /// Returns `None` if it's not a boolean.
428    #[must_use]
429    pub fn to_bool(&self) -> Option<bool> {
430        if self.is_bool() {
431            Some(self.is_true())
432        } else {
433            None
434        }
435    }
436
437    // # Number methods
438    /// Returns `true` if this is a number.
439    #[must_use]
440    pub fn is_number(&self) -> bool {
441        self.type_tag() == TypeTag::Number
442    }
443
444    unsafe fn unchecked_cast_ref<T>(&self) -> &T {
445        &*(self as *const Self).cast::<T>()
446    }
447
448    unsafe fn unchecked_cast_mut<T>(&mut self) -> &mut T {
449        &mut *(self as *mut Self).cast::<T>()
450    }
451
452    // Safety: Must be a string
453    unsafe fn as_number_unchecked(&self) -> &INumber {
454        self.unchecked_cast_ref()
455    }
456
457    // Safety: Must be a string
458    unsafe fn as_number_unchecked_mut(&mut self) -> &mut INumber {
459        self.unchecked_cast_mut()
460    }
461
462    /// Gets a reference to this value as an [`INumber`].
463    /// Returns `None` if it's not a number.
464    #[must_use]
465    pub fn as_number(&self) -> Option<&INumber> {
466        if self.is_number() {
467            // Safety: INumber is a `#[repr(transparent)]` wrapper around IValue
468            Some(unsafe { self.as_number_unchecked() })
469        } else {
470            None
471        }
472    }
473
474    /// Gets a mutable reference to this value as an [`INumber`].
475    /// Returns `None` if it's not a number.
476    pub fn as_number_mut(&mut self) -> Option<&mut INumber> {
477        if self.is_number() {
478            // Safety: INumber is a `#[repr(transparent)]` wrapper around IValue
479            Some(unsafe { self.as_number_unchecked_mut() })
480        } else {
481            None
482        }
483    }
484
485    /// Converts this value to an [`INumber`].
486    ///
487    /// # Errors
488    ///
489    /// Returns `Err(self)` if it's not a number.
490    pub fn into_number(self) -> Result<INumber, IValue> {
491        if self.is_number() {
492            Ok(INumber(self))
493        } else {
494            Err(self)
495        }
496    }
497
498    /// Converts this value to an i64 if it is a number that can be represented exactly.
499    #[must_use]
500    pub fn to_i64(&self) -> Option<i64> {
501        self.as_number()?.to_i64()
502    }
503    /// Converts this value to a u64 if it is a number that can be represented exactly.
504    #[must_use]
505    pub fn to_u64(&self) -> Option<u64> {
506        self.as_number()?.to_u64()
507    }
508    /// Converts this value to an f64 if it is a number that can be represented exactly.
509    #[must_use]
510    pub fn to_f64(&self) -> Option<f64> {
511        self.as_number()?.to_f64()
512    }
513    /// Converts this value to an f32 if it is a number that can be represented exactly.
514    #[must_use]
515    pub fn to_f32(&self) -> Option<f32> {
516        self.as_number()?.to_f32()
517    }
518    /// Converts this value to an i32 if it is a number that can be represented exactly.
519    #[must_use]
520    pub fn to_i32(&self) -> Option<i32> {
521        self.as_number()?.to_i32()
522    }
523    /// Converts this value to a u32 if it is a number that can be represented exactly.
524    #[must_use]
525    pub fn to_u32(&self) -> Option<u32> {
526        self.as_number()?.to_u32()
527    }
528    /// Converts this value to an isize if it is a number that can be represented exactly.
529    #[must_use]
530    pub fn to_isize(&self) -> Option<isize> {
531        self.as_number()?.to_isize()
532    }
533    /// Converts this value to a usize if it is a number that can be represented exactly.
534    #[must_use]
535    pub fn to_usize(&self) -> Option<usize> {
536        self.as_number()?.to_usize()
537    }
538    /// Converts this value to an f64 if it is a number, potentially losing precision
539    /// in the process.
540    #[must_use]
541    pub fn to_f64_lossy(&self) -> Option<f64> {
542        Some(self.as_number()?.to_f64_lossy())
543    }
544    /// Converts this value to an f32 if it is a number, potentially losing precision
545    /// in the process.
546    #[must_use]
547    pub fn to_f32_lossy(&self) -> Option<f32> {
548        Some(self.as_number()?.to_f32_lossy())
549    }
550
551    // # String methods
552    /// Returns `true` if this is a string.
553    #[must_use]
554    pub fn is_string(&self) -> bool {
555        self.type_tag() == TypeTag::StringOrNull && self.is_ptr()
556    }
557
558    // Safety: Must be a string
559    unsafe fn as_string_unchecked(&self) -> &IString {
560        self.unchecked_cast_ref()
561    }
562
563    // Safety: Must be a string
564    unsafe fn as_string_unchecked_mut(&mut self) -> &mut IString {
565        self.unchecked_cast_mut()
566    }
567
568    /// Gets a reference to this value as an [`IString`].
569    /// Returns `None` if it's not a string.
570    #[must_use]
571    pub fn as_string(&self) -> Option<&IString> {
572        if self.is_string() {
573            // Safety: IString is a `#[repr(transparent)]` wrapper around IValue
574            Some(unsafe { self.as_string_unchecked() })
575        } else {
576            None
577        }
578    }
579
580    /// Gets a mutable reference to this value as an [`IString`].
581    /// Returns `None` if it's not a string.
582    pub fn as_string_mut(&mut self) -> Option<&mut IString> {
583        if self.is_string() {
584            // Safety: IString is a `#[repr(transparent)]` wrapper around IValue
585            Some(unsafe { self.as_string_unchecked_mut() })
586        } else {
587            None
588        }
589    }
590
591    /// Converts this value to an [`IString`].
592    ///
593    /// # Errors
594    ///
595    /// Returns `Err(self)` if it's not a string.
596    pub fn into_string(self) -> Result<IString, IValue> {
597        if self.is_string() {
598            Ok(IString(self))
599        } else {
600            Err(self)
601        }
602    }
603
604    // # Array methods
605    /// Returns `true` if this is an array.
606    #[must_use]
607    pub fn is_array(&self) -> bool {
608        self.type_tag() == TypeTag::ArrayOrFalse && self.is_ptr()
609    }
610
611    // Safety: Must be an array
612    unsafe fn as_array_unchecked(&self) -> &IArray {
613        self.unchecked_cast_ref()
614    }
615
616    // Safety: Must be an array
617    unsafe fn as_array_unchecked_mut(&mut self) -> &mut IArray {
618        self.unchecked_cast_mut()
619    }
620
621    /// Gets a reference to this value as an [`IArray`].
622    /// Returns `None` if it's not an array.
623    #[must_use]
624    pub fn as_array(&self) -> Option<&IArray> {
625        if self.is_array() {
626            // Safety: IArray is a `#[repr(transparent)]` wrapper around IValue
627            Some(unsafe { self.as_array_unchecked() })
628        } else {
629            None
630        }
631    }
632
633    /// Gets a mutable reference to this value as an [`IArray`].
634    /// Returns `None` if it's not an array.
635    pub fn as_array_mut(&mut self) -> Option<&mut IArray> {
636        if self.is_array() {
637            // Safety: IArray is a `#[repr(transparent)]` wrapper around IValue
638            Some(unsafe { self.as_array_unchecked_mut() })
639        } else {
640            None
641        }
642    }
643
644    /// Converts this value to an [`IArray`].
645    ///
646    /// # Errors
647    ///
648    /// Returns `Err(self)` if it's not an array.
649    pub fn into_array(self) -> Result<IArray, IValue> {
650        if self.is_array() {
651            Ok(IArray(self))
652        } else {
653            Err(self)
654        }
655    }
656
657    // # Object methods
658    /// Returns `true` if this is an object.
659    #[must_use]
660    pub fn is_object(&self) -> bool {
661        self.type_tag() == TypeTag::ObjectOrTrue && self.is_ptr()
662    }
663
664    // Safety: Must be an array
665    unsafe fn as_object_unchecked(&self) -> &IObject {
666        self.unchecked_cast_ref()
667    }
668
669    // Safety: Must be an array
670    unsafe fn as_object_unchecked_mut(&mut self) -> &mut IObject {
671        self.unchecked_cast_mut()
672    }
673
674    /// Gets a reference to this value as an [`IObject`].
675    /// Returns `None` if it's not an object.
676    #[must_use]
677    pub fn as_object(&self) -> Option<&IObject> {
678        if self.is_object() {
679            // Safety: IObject is a `#[repr(transparent)]` wrapper around IValue
680            Some(unsafe { self.as_object_unchecked() })
681        } else {
682            None
683        }
684    }
685
686    /// Gets a mutable reference to this value as an [`IObject`].
687    /// Returns `None` if it's not an object.
688    pub fn as_object_mut(&mut self) -> Option<&mut IObject> {
689        if self.is_object() {
690            // Safety: IObject is a `#[repr(transparent)]` wrapper around IValue
691            Some(unsafe { self.as_object_unchecked_mut() })
692        } else {
693            None
694        }
695    }
696
697    /// Converts this value to an [`IObject`].
698    ///
699    /// # Errors
700    ///
701    /// Returns `Err(self)` if it's not an object.
702    pub fn into_object(self) -> Result<IObject, IValue> {
703        if self.is_object() {
704            Ok(IObject(self))
705        } else {
706            Err(self)
707        }
708    }
709}
710
711impl Clone for IValue {
712    fn clone(&self) -> Self {
713        match self.type_() {
714            // Inline types can be trivially copied
715            ValueType::Null | ValueType::Bool => Self { ptr: self.ptr },
716            // Safety: We checked the type
717            ValueType::Array => unsafe { self.as_array_unchecked() }.clone_impl(),
718            ValueType::Object => unsafe { self.as_object_unchecked() }.clone_impl(),
719            ValueType::String => unsafe { self.as_string_unchecked() }.clone_impl(),
720            ValueType::Number => unsafe { self.as_number_unchecked() }.clone_impl(),
721        }
722    }
723}
724
725impl Drop for IValue {
726    fn drop(&mut self) {
727        match self.type_() {
728            // Inline types can be trivially dropped
729            ValueType::Null | ValueType::Bool => {}
730            // Safety: We checked the type
731            ValueType::Array => unsafe { self.as_array_unchecked_mut() }.drop_impl(),
732            ValueType::Object => unsafe { self.as_object_unchecked_mut() }.drop_impl(),
733            ValueType::String => unsafe { self.as_string_unchecked_mut() }.drop_impl(),
734            ValueType::Number => unsafe { self.as_number_unchecked_mut() }.drop_impl(),
735        }
736    }
737}
738
739impl Hash for IValue {
740    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
741        match self.type_() {
742            // Inline and interned types can be trivially hashed
743            ValueType::Null | ValueType::Bool | ValueType::String => self.ptr.hash(state),
744            // Safety: We checked the type
745            ValueType::Array => unsafe { self.as_array_unchecked() }.hash(state),
746            // Safety: We checked the type
747            ValueType::Object => unsafe { self.as_object_unchecked() }.hash(state),
748            // Safety: We checked the type
749            ValueType::Number => unsafe { self.as_number_unchecked() }.hash(state),
750        }
751    }
752}
753
754impl PartialEq for IValue {
755    fn eq(&self, other: &Self) -> bool {
756        let (t1, t2) = (self.type_(), other.type_());
757        if t1 == t2 {
758            // Safety: Only methods for the appropriate type are called
759            unsafe {
760                match t1 {
761                    // Inline and interned types can be trivially compared
762                    ValueType::Null | ValueType::Bool | ValueType::String => self.ptr == other.ptr,
763                    ValueType::Number => self.as_number_unchecked() == other.as_number_unchecked(),
764                    ValueType::Array => self.as_array_unchecked() == other.as_array_unchecked(),
765                    ValueType::Object => self.as_object_unchecked() == other.as_object_unchecked(),
766                }
767            }
768        } else {
769            false
770        }
771    }
772}
773
774impl Eq for IValue {}
775impl PartialOrd for IValue {
776    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
777        let (t1, t2) = (self.type_(), other.type_());
778        if t1 == t2 {
779            // Safety: Only methods for the appropriate type are called
780            unsafe {
781                match t1 {
782                    // Inline and interned types can be trivially compared
783                    ValueType::Null => Some(Ordering::Equal),
784                    ValueType::Bool => self.is_true().partial_cmp(&other.is_true()),
785                    ValueType::String => self
786                        .as_string_unchecked()
787                        .partial_cmp(other.as_string_unchecked()),
788                    ValueType::Number => self
789                        .as_number_unchecked()
790                        .partial_cmp(other.as_number_unchecked()),
791                    ValueType::Array => self
792                        .as_array_unchecked()
793                        .partial_cmp(other.as_array_unchecked()),
794                    ValueType::Object => None,
795                }
796            }
797        } else {
798            t1.partial_cmp(&t2)
799        }
800    }
801}
802
803mod private {
804    #[doc(hidden)]
805    pub trait Sealed {}
806    impl Sealed for usize {}
807    impl Sealed for &str {}
808    impl Sealed for &super::IString {}
809    impl<T: Sealed> Sealed for &T {}
810}
811
812/// Trait which abstracts over the various number and string types
813/// which can be used to index into an [`IValue`].
814pub trait ValueIndex: private::Sealed + Copy {
815    #[doc(hidden)]
816    fn index_into(self, v: &IValue) -> Option<&IValue>;
817
818    #[doc(hidden)]
819    fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue>;
820
821    #[doc(hidden)]
822    fn index_or_insert(self, v: &mut IValue) -> &mut IValue;
823
824    #[doc(hidden)]
825    fn remove(self, v: &mut IValue) -> Option<IValue>;
826}
827
828impl ValueIndex for usize {
829    fn index_into(self, v: &IValue) -> Option<&IValue> {
830        v.as_array().unwrap().get(self)
831    }
832
833    fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
834        v.as_array_mut().unwrap().get_mut(self)
835    }
836
837    fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
838        self.index_into_mut(v).unwrap()
839    }
840
841    fn remove(self, v: &mut IValue) -> Option<IValue> {
842        v.as_array_mut().unwrap().remove(self)
843    }
844}
845
846impl ValueIndex for &str {
847    fn index_into(self, v: &IValue) -> Option<&IValue> {
848        v.as_object().unwrap().get(&IString::intern(self))
849    }
850
851    fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
852        v.as_object_mut().unwrap().get_mut(&IString::intern(self))
853    }
854
855    fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
856        &mut v.as_object_mut().unwrap()[self]
857    }
858
859    fn remove(self, v: &mut IValue) -> Option<IValue> {
860        v.as_object_mut().unwrap().remove(self)
861    }
862}
863
864impl ValueIndex for &IString {
865    fn index_into(self, v: &IValue) -> Option<&IValue> {
866        v.as_object().unwrap().get(self)
867    }
868
869    fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
870        v.as_object_mut().unwrap().get_mut(self)
871    }
872
873    fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
874        &mut v.as_object_mut().unwrap()[self]
875    }
876
877    fn remove(self, v: &mut IValue) -> Option<IValue> {
878        v.as_object_mut().unwrap().remove(self)
879    }
880}
881
882impl<T: ValueIndex> ValueIndex for &T {
883    fn index_into(self, v: &IValue) -> Option<&IValue> {
884        (*self).index_into(v)
885    }
886
887    fn index_into_mut(self, v: &mut IValue) -> Option<&mut IValue> {
888        (*self).index_into_mut(v)
889    }
890
891    fn index_or_insert(self, v: &mut IValue) -> &mut IValue {
892        (*self).index_or_insert(v)
893    }
894
895    fn remove(self, v: &mut IValue) -> Option<IValue> {
896        (*self).remove(v)
897    }
898}
899
900impl<I: ValueIndex> Index<I> for IValue {
901    type Output = IValue;
902
903    #[inline]
904    fn index(&self, index: I) -> &IValue {
905        index.index_into(self).unwrap()
906    }
907}
908
909impl<I: ValueIndex> IndexMut<I> for IValue {
910    #[inline]
911    fn index_mut(&mut self, index: I) -> &mut IValue {
912        index.index_or_insert(self)
913    }
914}
915
916impl Debug for IValue {
917    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
918        unsafe {
919            match self.type_() {
920                // Inline and interned types can be trivially hashed
921                ValueType::Null => f.write_str("null"),
922                ValueType::Bool => Debug::fmt(&self.is_true(), f),
923                // Safety: We checked the type
924                ValueType::String => Debug::fmt(self.as_string_unchecked(), f),
925                // Safety: We checked the type
926                ValueType::Array => Debug::fmt(self.as_array_unchecked(), f),
927                // Safety: We checked the type
928                ValueType::Object => Debug::fmt(self.as_object_unchecked(), f),
929                // Safety: We checked the type
930                ValueType::Number => Debug::fmt(self.as_number_unchecked(), f),
931            }
932        }
933    }
934}
935
936impl<T: Into<IValue>> From<Option<T>> for IValue {
937    fn from(other: Option<T>) -> Self {
938        if let Some(v) = other {
939            v.into()
940        } else {
941            Self::NULL
942        }
943    }
944}
945
946impl From<bool> for IValue {
947    fn from(other: bool) -> Self {
948        if other {
949            Self::TRUE
950        } else {
951            Self::FALSE
952        }
953    }
954}
955
956typed_conversions! {
957    INumber: i8, u8, i16, u16, i32, u32, i64, u64, isize, usize;
958    IString: String, &String, &mut String, &str, &mut str;
959    IArray:
960        Vec<T> where (T: Into<IValue>),
961        &[T] where (T: Into<IValue> + Clone);
962    IObject:
963        HashMap<K, V> where (K: Into<IString>, V: Into<IValue>),
964        BTreeMap<K, V> where (K: Into<IString>, V: Into<IValue>);
965}
966
967#[cfg(feature = "indexmap")]
968typed_conversions! {
969    IObject:
970        IndexMap<K, V> where (K: Into<IString>, V: Into<IValue>);
971}
972
973impl From<f32> for IValue {
974    fn from(v: f32) -> Self {
975        INumber::try_from(v).map(Into::into).unwrap_or(IValue::NULL)
976    }
977}
978
979impl From<f64> for IValue {
980    fn from(v: f64) -> Self {
981        INumber::try_from(v).map(Into::into).unwrap_or(IValue::NULL)
982    }
983}
984
985impl Default for IValue {
986    fn default() -> Self {
987        Self::NULL
988    }
989}
990
991#[cfg(test)]
992mod tests {
993    use super::*;
994
995    #[mockalloc::test]
996    fn can_use_literal() {
997        let x: IValue = ijson!({
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        let y: IValue = serde_json::from_str(
1006            r#"{
1007                "foo": "bar",
1008                "x": [],
1009                "y": ["hi", "there", 1, 2, null, false, true, 63.5],
1010                "z": [false, {
1011                    "a": null
1012                }, {}]
1013            }"#,
1014        )
1015        .unwrap();
1016        assert_eq!(x, y);
1017    }
1018
1019    #[test]
1020    #[allow(clippy::redundant_clone)]
1021    fn test_null() {
1022        let x: IValue = IValue::NULL;
1023        assert!(x.is_null());
1024        assert_eq!(x.type_(), ValueType::Null);
1025        assert!(matches!(x.clone().destructure(), Destructured::Null));
1026        assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Null));
1027        assert!(matches!(x.clone().destructure_mut(), DestructuredMut::Null));
1028    }
1029
1030    #[test]
1031    fn test_bool() {
1032        for v in [true, false].iter().copied() {
1033            let mut x = IValue::from(v);
1034            assert!(x.is_bool());
1035            assert_eq!(x.type_(), ValueType::Bool);
1036            assert_eq!(x.to_bool(), Some(v));
1037            assert!(matches!(x.clone().destructure(), Destructured::Bool(u) if u == v));
1038            assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Bool(u) if u == v));
1039            assert!(
1040                matches!(x.clone().destructure_mut(), DestructuredMut::Bool(u) if u.get() == v)
1041            );
1042
1043            if let DestructuredMut::Bool(mut b) = x.destructure_mut() {
1044                b.set(!v);
1045            }
1046
1047            assert_eq!(x.to_bool(), Some(!v));
1048        }
1049    }
1050
1051    #[mockalloc::test]
1052    fn test_number() {
1053        for v in 300..400 {
1054            let mut x = IValue::from(v);
1055            assert!(x.is_number());
1056            assert_eq!(x.type_(), ValueType::Number);
1057            assert_eq!(x.to_i32(), Some(v));
1058            assert_eq!(x.to_u32(), Some(v as u32));
1059            assert_eq!(x.to_i64(), Some(i64::from(v)));
1060            assert_eq!(x.to_u64(), Some(v as u64));
1061            assert_eq!(x.to_isize(), Some(v as isize));
1062            assert_eq!(x.to_usize(), Some(v as usize));
1063            assert_eq!(x.as_number(), Some(&v.into()));
1064            assert_eq!(x.as_number_mut(), Some(&mut v.into()));
1065            assert!(matches!(x.clone().destructure(), Destructured::Number(u) if u == v.into()));
1066            assert!(
1067                matches!(x.clone().destructure_ref(), DestructuredRef::Number(u) if *u == v.into())
1068            );
1069            assert!(
1070                matches!(x.clone().destructure_mut(), DestructuredMut::Number(u) if *u == v.into())
1071            );
1072        }
1073    }
1074
1075    #[mockalloc::test]
1076    fn test_string() {
1077        for v in 0..10 {
1078            let s = v.to_string();
1079            let mut x = IValue::from(&s);
1080            assert!(x.is_string());
1081            assert_eq!(x.type_(), ValueType::String);
1082            assert_eq!(x.as_string(), Some(&IString::intern(&s)));
1083            assert_eq!(x.as_string_mut(), Some(&mut IString::intern(&s)));
1084            assert!(matches!(x.clone().destructure(), Destructured::String(u) if u == s));
1085            assert!(matches!(x.clone().destructure_ref(), DestructuredRef::String(u) if *u == s));
1086            assert!(matches!(x.clone().destructure_mut(), DestructuredMut::String(u) if *u == s));
1087        }
1088    }
1089
1090    #[mockalloc::test]
1091    fn test_array() {
1092        for v in 0..10 {
1093            let mut a: IArray = (0..v).collect();
1094            let mut x = IValue::from(a.clone());
1095            assert!(x.is_array());
1096            assert_eq!(x.type_(), ValueType::Array);
1097            assert_eq!(x.as_array(), Some(&a));
1098            assert_eq!(x.as_array_mut(), Some(&mut a));
1099            assert!(matches!(x.clone().destructure(), Destructured::Array(u) if u == a));
1100            assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Array(u) if *u == a));
1101            assert!(matches!(x.clone().destructure_mut(), DestructuredMut::Array(u) if *u == a));
1102        }
1103    }
1104
1105    #[mockalloc::test]
1106    fn test_object() {
1107        for v in 0..10 {
1108            let mut o: IObject = (0..v).map(|i| (i.to_string(), i)).collect();
1109            let mut x = IValue::from(o.clone());
1110            assert!(x.is_object());
1111            assert_eq!(x.type_(), ValueType::Object);
1112            assert_eq!(x.as_object(), Some(&o));
1113            assert_eq!(x.as_object_mut(), Some(&mut o));
1114            assert!(matches!(x.clone().destructure(), Destructured::Object(u) if u == o));
1115            assert!(matches!(x.clone().destructure_ref(), DestructuredRef::Object(u) if *u == o));
1116            assert!(matches!(x.clone().destructure_mut(), DestructuredMut::Object(u) if *u == o));
1117        }
1118    }
1119
1120    #[mockalloc::test]
1121    fn test_into_object_for_object() {
1122        let o: IObject = (0..10).map(|i| (i.to_string(), i)).collect();
1123        let x = IValue::from(o.clone());
1124
1125        assert_eq!(x.into_object(), Ok(o));
1126    }
1127}