Skip to main content

feldera_ijson/
object.rs

1//! Functionality relating to the JSON object type
2
3use std::alloc::{alloc, dealloc, Layout, LayoutError};
4use std::cmp::{self, Ordering};
5use std::collections::hash_map::DefaultHasher;
6use std::collections::{BTreeMap, HashMap};
7use std::fmt::{self, Debug, Formatter};
8use std::hash::{Hash, Hasher};
9use std::iter::FromIterator;
10use std::mem;
11use std::ops::{Index, IndexMut};
12
13#[cfg(feature = "indexmap")]
14use indexmap::IndexMap;
15
16use crate::thin::{ThinMut, ThinMutExt, ThinRef, ThinRefExt};
17
18use super::string::IString;
19use super::value::{IValue, TypeTag};
20
21#[repr(C)]
22#[repr(align(4))]
23struct Header {
24    len: usize,
25    cap: usize,
26}
27
28#[repr(C)]
29#[derive(Debug)]
30struct KeyValuePair {
31    key: IString,
32    value: IValue,
33}
34
35fn hash_capacity(cap: usize) -> usize {
36    cap + cap / 4
37}
38
39fn hash_fn(s: &IString) -> usize {
40    let v: &IValue = s.as_ref();
41    // We know the bottom two bits are always the same
42    let mut p = v.ptr_usize() >> 2;
43    p = p.wrapping_mul(202_529);
44    p = p ^ (p >> 13);
45    p.wrapping_mul(202_529)
46}
47
48fn hash_bucket(s: &IString, hash_cap: usize) -> usize {
49    hash_fn(s) % hash_cap
50}
51
52struct SplitHeader<'a> {
53    cap: usize,
54    items: &'a [KeyValuePair],
55    table: &'a [usize],
56}
57
58impl<'a> SplitHeader<'a> {
59    fn find_bucket(&self, key: &IString) -> Result<usize, usize> {
60        let hash_cap = hash_capacity(self.cap);
61        let initial_bucket = hash_bucket(key, hash_cap);
62        unsafe {
63            // Linear search from expected bucket
64            for i in 0..hash_cap {
65                let bucket = (initial_bucket + i) % hash_cap;
66                let index = *self.table.get_unchecked(bucket);
67
68                // If we hit an empty bucket, we know the key is not present
69                if index == usize::MAX {
70                    return Err(bucket);
71                }
72
73                // If the bucket contains our key, we found the bucket
74                let k = &self.items.get_unchecked(index).key;
75                if k == key {
76                    return Ok(bucket);
77                }
78
79                // If the bucket contains a different key, and its probe length is less than
80                // ours, then we know our key is not present or we would have evicted this one.
81                let key_dist = (bucket + hash_cap - hash_bucket(k, hash_cap)) % hash_cap;
82                if key_dist < i {
83                    return Err(bucket);
84                }
85            }
86        }
87        Err(usize::MAX)
88    }
89    // Safety: index must be in bounds
90    unsafe fn find_bucket_from_index(&self, index: usize) -> usize {
91        let hash_cap = hash_capacity(self.cap);
92        let key = &self.items.get_unchecked(index).key;
93        let mut bucket = hash_bucket(key, hash_cap);
94
95        // We don't bother with any early exit conditions, because
96        // we know the item is present.
97        while *self.table.get_unchecked(bucket) != index {
98            bucket = (bucket + 1) % hash_cap;
99        }
100
101        bucket
102    }
103}
104
105struct SplitHeaderMut<'a> {
106    cap: usize,
107    items: &'a mut [KeyValuePair],
108    table: &'a mut [usize],
109}
110
111impl<'a> SplitHeaderMut<'a> {
112    fn as_ref(&self) -> SplitHeader {
113        SplitHeader {
114            cap: self.cap,
115            items: self.items,
116            table: self.table,
117        }
118    }
119    // Safety: Bucket must be valid and empty.
120    //
121    // Shifts elements up to fill the empty space if they are not at their ideal location.
122    unsafe fn unshift(&mut self, initial_bucket: usize) {
123        let hash_cap = hash_capacity(self.cap);
124        let mut prev_bucket = initial_bucket;
125        for i in 1..hash_cap {
126            let bucket = (initial_bucket + i) % hash_cap;
127            let index = *self.table.get_unchecked(bucket);
128
129            // If we hit an empty bucket, we're done
130            if index == usize::MAX {
131                return;
132            }
133
134            // If the probe length is zero, we're done
135            let k = &self.items.get_unchecked(index).key;
136            if hash_bucket(k, hash_cap) == bucket {
137                return;
138            }
139
140            // Shift this element back one
141            self.table.swap(prev_bucket, bucket);
142            prev_bucket = bucket;
143        }
144    }
145    // Safety: item with this index must have just been pushed, and the bucket
146    // index must be correct.
147    //
148    // Inserts an index into the table, shifting existing elements down until
149    // there's an empty slot.
150    unsafe fn shift(&mut self, initial_bucket: usize, mut index: usize) {
151        let hash_cap = hash_capacity(self.cap);
152        for i in 0..hash_cap {
153            // If we hit an empty bucket, we're done
154            if index == usize::MAX {
155                return;
156            }
157
158            let bucket = (initial_bucket + i) % hash_cap;
159            mem::swap(self.table.get_unchecked_mut(bucket), &mut index);
160        }
161    }
162    // Safety: Bucket index must be in range and occupied
163    unsafe fn remove_bucket(&mut self, bucket: usize) {
164        // Remove the entry from the table
165        let index = mem::replace(self.table.get_unchecked_mut(bucket), usize::MAX);
166
167        // Unshift any displaced buckets, so the table is valid again
168        self.unshift(bucket);
169
170        // If the item being removed is not at the end of the array,
171        // we need to do some book-keeping
172        let last_index = self.items.len() - 1;
173        if last_index != index {
174            // Find the bucket containing the last item
175            let bucket_to_update = self.as_ref().find_bucket_from_index(last_index);
176
177            // Update it to point to the location where that item will be
178            // after we swap it.
179            *self.table.get_unchecked_mut(bucket_to_update) = index;
180
181            // Swap the element to be removed to the back
182            self.items.swap(index, last_index);
183        }
184    }
185}
186
187trait HeaderRef<'a>: ThinRefExt<'a, Header> {
188    fn items_ptr(&self) -> *const KeyValuePair {
189        // Safety: pointers to the end of structs are allowed
190        unsafe { self.ptr().add(1).cast() }
191    }
192    fn hashes_ptr(&self) -> *const usize {
193        // Safety: pointers to the end of structs are allowed
194        unsafe { self.items_ptr().add(self.cap).cast() }
195    }
196    fn split(&self) -> SplitHeader<'a> {
197        // Safety: Header `len` and `cap` must be accurate
198        unsafe {
199            SplitHeader {
200                cap: self.cap,
201                items: std::slice::from_raw_parts(self.items_ptr(), self.len),
202                table: std::slice::from_raw_parts(self.hashes_ptr(), hash_capacity(self.cap)),
203            }
204        }
205    }
206}
207
208trait HeaderMut<'a>: ThinMutExt<'a, Header> {
209    fn items_ptr_mut(&mut self) -> *mut KeyValuePair {
210        // Safety: pointers to the end of structs are allowed
211        unsafe { self.ptr_mut().add(1).cast() }
212    }
213    fn hashes_ptr_mut(&mut self) -> *mut usize {
214        // Safety: pointers to the end of structs are allowed
215        unsafe { self.items_ptr_mut().add(self.cap).cast() }
216    }
217    fn split_mut(mut self) -> SplitHeaderMut<'a> {
218        // Safety: Header `len` and `cap` must be accurate
219        let len = self.len;
220        let hash_cap = hash_capacity(self.cap);
221        let item_ptr = self.items_ptr_mut();
222        let hash_ptr = self.hashes_ptr_mut();
223        unsafe {
224            SplitHeaderMut {
225                cap: self.cap,
226                items: std::slice::from_raw_parts_mut(item_ptr as *mut _, len),
227                table: std::slice::from_raw_parts_mut(hash_ptr as *mut _, hash_cap),
228            }
229        }
230    }
231
232    // Safety: Must ensure there's capacity for an extra element
233    unsafe fn entry(self, key: IString) -> Entry<'a>;
234    // Safety: Must ensure there's capacity for an extra element
235    unsafe fn entry_or_clone(self, key: &IString) -> Entry<'a>;
236
237    // Safety: Object must not be empty
238    unsafe fn pop(&mut self) -> (IString, IValue) {
239        self.len -= 1;
240        let item = self.items_ptr_mut().add(self.len).read();
241        (item.key, item.value)
242    }
243    unsafe fn push(&mut self, key: IString, value: IValue) -> usize {
244        self.items_ptr_mut()
245            .add(self.len)
246            .write(KeyValuePair { key, value });
247        let res = self.len;
248        self.len += 1;
249        res
250    }
251    fn clear(&mut self) {
252        // Clear the table
253        for item in self.reborrow().split_mut().table {
254            *item = usize::MAX;
255        }
256        // Drop the items
257        while self.len > 0 {
258            // Safety: not empty
259            unsafe {
260                self.pop();
261            }
262        }
263    }
264}
265
266impl<'a, T: ThinRefExt<'a, Header>> HeaderRef<'a> for T {}
267impl<'a> HeaderMut<'a> for ThinMut<'a, Header> {
268    // Safety: Must ensure there's capacity for an extra element
269    unsafe fn entry(self, key: IString) -> Entry<'a> {
270        match self.split().find_bucket(&key) {
271            Err(bucket) => Entry::Vacant(VacantEntry {
272                header: self,
273                bucket,
274                key,
275            }),
276            Ok(bucket) => Entry::Occupied(OccupiedEntry {
277                header: self,
278                bucket,
279            }),
280        }
281    }
282    // Safety: Must ensure there's capacity for an extra element
283    unsafe fn entry_or_clone(self, key: &IString) -> Entry<'a> {
284        match self.split().find_bucket(key) {
285            Err(bucket) => Entry::Vacant(VacantEntry {
286                header: self,
287                bucket,
288                key: key.clone(),
289            }),
290            Ok(bucket) => Entry::Occupied(OccupiedEntry {
291                header: self,
292                bucket,
293            }),
294        }
295    }
296}
297
298/// A view into an occupied entry in an [`IObject`]. It is part of the [`Entry`] enum.
299pub struct OccupiedEntry<'a> {
300    header: ThinMut<'a, Header>,
301    bucket: usize,
302}
303
304impl<'a> Debug for OccupiedEntry<'a> {
305    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
306        f.debug_struct("OccupiedEntry")
307            .field("key", self.key())
308            .field("value", &self.get())
309            .finish()
310    }
311}
312
313impl<'a> OccupiedEntry<'a> {
314    fn get_key_value(&self) -> (&IString, &IValue) {
315        // Safety: Indices are known to be in range
316        let split = self.header.split();
317        unsafe {
318            let index = *split.table.get_unchecked(self.bucket);
319            let kvp = split.items.get_unchecked(index);
320            (&kvp.key, &kvp.value)
321        }
322    }
323    fn get_key_value_mut(&mut self) -> (&IString, &mut IValue) {
324        // Safety: Indices are known to be in range
325        let split = self.header.reborrow().split_mut();
326        unsafe {
327            let index = *split.table.get_unchecked(self.bucket);
328            let kvp = split.items.get_unchecked_mut(index);
329            (&kvp.key, &mut kvp.value)
330        }
331    }
332    fn into_get_key_value_mut(self) -> (&'a IString, &'a mut IValue) {
333        // Safety: Indices are known to be in range
334        let split = self.header.split_mut();
335        unsafe {
336            let index = *split.table.get_unchecked(self.bucket);
337            let kvp = split.items.get_unchecked_mut(index);
338            (&kvp.key, &mut kvp.value)
339        }
340    }
341    /// Returns a reference to the key at this entry
342    #[must_use]
343    pub fn key(&self) -> &IString {
344        self.get_key_value().0
345    }
346
347    /// Removes and returns the entry as a (key, value) pair.
348    pub fn remove_entry(mut self) -> (IString, IValue) {
349        // Safety: Bucket is known to be correct
350        unsafe {
351            self.header
352                .reborrow()
353                .split_mut()
354                .remove_bucket(self.bucket);
355            self.header.pop()
356        }
357    }
358    /// Returns a reference to the value in this entry
359    #[must_use]
360    pub fn get(&self) -> &IValue {
361        self.get_key_value().1
362    }
363    /// Returns a mutable reference to the value in this entry
364    pub fn get_mut(&mut self) -> &mut IValue {
365        self.get_key_value_mut().1
366    }
367    /// Converts this into a mutable reference to the value in the entry
368    /// with a lifetime bound to the [`IObject`] itself.
369    #[must_use]
370    pub fn into_mut(self) -> &'a mut IValue {
371        self.into_get_key_value_mut().1
372    }
373
374    /// Sets the value in this entry, and returns the previous value.
375    pub fn insert(&mut self, value: impl Into<IValue>) -> IValue {
376        mem::replace(self.get_mut(), value.into())
377    }
378
379    /// Removes this entry and returns its value.
380    pub fn remove(self) -> IValue {
381        self.remove_entry().1
382    }
383}
384
385/// A view into a vacant entry in an [`IObject`]. It is part of the [`Entry`] enum.
386pub struct VacantEntry<'a> {
387    header: ThinMut<'a, Header>,
388    bucket: usize,
389    key: IString,
390}
391
392impl<'a> Debug for VacantEntry<'a> {
393    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
394        f.debug_struct("OccupiedEntry")
395            .field("key", self.key())
396            .finish()
397    }
398}
399
400impl<'a> VacantEntry<'a> {
401    /// Returns a reference to the key at this entry.
402    #[must_use]
403    pub fn key(&self) -> &IString {
404        &self.key
405    }
406    /// Takes ownership of the key.
407    #[must_use]
408    pub fn into_key(self) -> IString {
409        self.key
410    }
411    /// Inserts a value into this entry and returns a mutable reference
412    /// to it.
413    pub fn insert(mut self, value: impl Into<IValue>) -> &'a mut IValue {
414        // Safety: we reserve space when the entry is initially created.
415        // We know the bucket index is correct.
416        unsafe {
417            let index = self.header.push(self.key, value.into());
418            let mut split = self.header.split_mut();
419            split.shift(self.bucket, index);
420            &mut split.items.last_mut().unwrap().value
421        }
422    }
423}
424
425/// A view into a single entry in an [`IObject`], which may be either vacant
426/// or occupied.
427///
428/// Obtained using [`IObject::entry`].
429#[derive(Debug)]
430pub enum Entry<'a> {
431    /// An occupied entry.
432    Occupied(OccupiedEntry<'a>),
433    /// A vacant entry.
434    Vacant(VacantEntry<'a>),
435}
436
437impl<'a> Entry<'a> {
438    /// Fills this entry if it's currently vacant, and then
439    /// returns a mutable reference to the value at this entry.
440    pub fn or_insert(self, default: IValue) -> &'a mut IValue {
441        match self {
442            Entry::Occupied(occ) => occ.into_mut(),
443            Entry::Vacant(vac) => vac.insert(default),
444        }
445    }
446
447    /// Fills this entry by calling the specified function if it's
448    /// currently vacant, and then returns a mutable reference to
449    /// the value at this entry.
450    pub fn or_insert_with(self, default: impl FnOnce() -> IValue) -> &'a mut IValue {
451        match self {
452            Entry::Occupied(occ) => occ.into_mut(),
453            Entry::Vacant(vac) => vac.insert(default()),
454        }
455    }
456
457    /// Returns a reference to the key at this entry.
458    #[must_use]
459    pub fn key(&self) -> &IString {
460        match self {
461            Entry::Occupied(occ) => occ.key(),
462            Entry::Vacant(vac) => vac.key(),
463        }
464    }
465
466    /// Updates the value in this entry by calling the specified mutation
467    /// function if the entry is occupied.
468    pub fn and_modify(mut self, f: impl FnOnce(&mut IValue)) -> Self {
469        if let Entry::Occupied(occ) = &mut self {
470            f(occ.get_mut());
471        }
472        self
473    }
474}
475
476/// Iterator over ([`IString`], [`IValue`]) pairs returned from
477/// [`IObject::into_iter`]
478pub struct IntoIter {
479    reversed_object: IObject,
480}
481
482impl Debug for IntoIter {
483    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
484        f.debug_struct("IntoIter")
485            .field("reversed_object", &self.reversed_object)
486            .finish()
487    }
488}
489
490impl Iterator for IntoIter {
491    type Item = (IString, IValue);
492
493    fn next(&mut self) -> Option<Self::Item> {
494        if self.reversed_object.is_empty() {
495            None
496        } else {
497            Some(unsafe {
498                // Safety: Object is not empty
499                self.reversed_object.header_mut().pop()
500            })
501        }
502    }
503}
504
505impl ExactSizeIterator for IntoIter {
506    fn len(&self) -> usize {
507        self.reversed_object.len()
508    }
509}
510
511/// The `IObject` type is similar to a `HashMap<IString, IValue>`. As with the
512/// [`IArray`], the length and capacity are stored _inside_ the heap allocation.
513/// In addition, `IObject`s preserve the insertion order of their elements, in
514/// case that is important in the original JSON.
515///
516/// Removing from an `IObject` will disrupt the insertion order.
517///
518/// [`IArray`]: super::IArray
519#[repr(transparent)]
520#[derive(Clone, size_of::SizeOf)]
521pub struct IObject(pub(crate) IValue);
522
523value_subtype_impls!(IObject, into_object, as_object, as_object_mut);
524
525static EMPTY_HEADER: Header = Header { len: 0, cap: 0 };
526
527impl IObject {
528    fn layout(cap: usize) -> Result<Layout, LayoutError> {
529        Ok(Layout::new::<Header>()
530            .extend(Layout::array::<KeyValuePair>(cap)?)?
531            .0
532            .extend(Layout::array::<usize>(hash_capacity(cap))?)?
533            .0
534            .pad_to_align())
535    }
536
537    fn alloc(cap: usize) -> *mut Header {
538        unsafe {
539            let hd = alloc(Self::layout(cap).unwrap()).cast::<Header>();
540            std::ptr::write(hd, Header { len: 0, cap });
541            let mut hd_mut = ThinMut::new(hd);
542            let hash_ptr = hd_mut.hashes_ptr_mut();
543            for i in 0..hash_capacity(cap) {
544                hash_ptr.add(i).write(usize::MAX);
545            }
546            hd
547        }
548    }
549
550    fn dealloc(ptr: *mut Header) {
551        unsafe {
552            let layout = Self::layout((*ptr).cap).unwrap();
553            dealloc(ptr.cast(), layout);
554        }
555    }
556
557    /// Constructs a new empty `IObject`. Does not allocate.
558    #[must_use]
559    pub fn new() -> Self {
560        unsafe { Self(IValue::new_ref(&EMPTY_HEADER, TypeTag::ObjectOrTrue)) }
561    }
562
563    /// Constructs a new `IObject` with the specified capacity. At least that many entries
564    /// can be added to the object without reallocating.
565    #[must_use]
566    pub fn with_capacity(cap: usize) -> Self {
567        if cap == 0 {
568            Self::new()
569        } else {
570            Self(unsafe { IValue::new_ptr(Self::alloc(cap).cast(), TypeTag::ObjectOrTrue) })
571        }
572    }
573
574    fn header(&self) -> ThinRef<Header> {
575        unsafe { ThinRef::new(self.0.ptr().cast()) }
576    }
577
578    // Safety: must not be static
579    unsafe fn header_mut(&mut self) -> ThinMut<Header> {
580        ThinMut::new(self.0.ptr().cast())
581    }
582
583    fn is_static(&self) -> bool {
584        self.capacity() == 0
585    }
586    /// Returns the capacity of the object. This is the maximum number of entries the object
587    /// can hold without reallocating.
588    #[must_use]
589    pub fn capacity(&self) -> usize {
590        self.header().cap
591    }
592    /// Returns the number of entries currently stored in the object.
593    #[must_use]
594    pub fn len(&self) -> usize {
595        self.header().len
596    }
597    /// Returns `true` if the object is empty.
598    #[must_use]
599    pub fn is_empty(&self) -> bool {
600        self.len() == 0
601    }
602
603    fn resize_internal(&mut self, cap: usize) {
604        let old_obj = mem::replace(self, Self::with_capacity(cap));
605        if !self.is_static() {
606            unsafe {
607                let mut hd = self.header_mut();
608                for (k, v) in old_obj {
609                    if let Err(bucket) = hd.split().find_bucket(&k) {
610                        let index = hd.push(k, v);
611                        hd.reborrow().split_mut().shift(bucket, index);
612                    }
613                }
614            }
615        }
616    }
617
618    /// Reserves space for at least this many additional entries.
619    pub fn reserve(&mut self, additional: usize) {
620        let hd = self.header();
621        let current_capacity = hd.cap;
622        let desired_capacity = hd.len.checked_add(additional).unwrap();
623        if current_capacity >= desired_capacity {
624            return;
625        }
626        self.resize_internal(cmp::max(current_capacity * 2, desired_capacity.max(4)));
627    }
628
629    /// Returns a view of an entry within this object.
630    pub fn entry(&mut self, key: impl Into<IString>) -> Entry {
631        self.reserve(1);
632        // Safety: cannot be static after reserving space
633        unsafe { self.header_mut().entry(key.into()) }
634    }
635    /// Returns a view of an entry within this object, whilst avoiding
636    /// cloning the key if the entry is already occupied.
637    pub fn entry_or_clone(&mut self, key: &IString) -> Entry {
638        self.reserve(1);
639        // Safety: cannot be static after reserving space
640        unsafe { self.header_mut().entry_or_clone(key) }
641    }
642    /// Returns an iterator over references to the keys in this object.
643    pub fn keys(&self) -> impl Iterator<Item = &IString> {
644        self.iter().map(|x| x.0)
645    }
646    /// Returns an iterator over references to the values in this object.
647    pub fn values(&self) -> impl Iterator<Item = &IValue> {
648        self.iter().map(|x| x.1)
649    }
650    /// Returns an iterator over (&key, &value) pairs in this object.
651    #[must_use]
652    pub fn iter(&self) -> Iter {
653        Iter(self.header().split().items.iter())
654    }
655    /// Returns an iterator over mutable references to the values in
656    /// this object.
657    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut IValue> {
658        self.iter_mut().map(|x| x.1)
659    }
660    /// Returns an iterator over (&key, &mut value) pairs in this object.
661    pub fn iter_mut(&mut self) -> IterMut {
662        IterMut(
663            if self.is_empty() {
664                &mut []
665            } else {
666                // Safety: not static
667                unsafe { self.header_mut().split_mut().items }
668            }
669            .iter_mut(),
670        )
671    }
672
673    /// Removes all entries from the object. The capacity is unchanged.
674    pub fn clear(&mut self) {
675        if !self.is_empty() {
676            // Safety: not static
677            unsafe {
678                self.header_mut().clear();
679            }
680        }
681    }
682    /// Looks up the specified key in this object and returns a (&key, &value) pair
683    /// if found.
684    pub fn get_key_value(&self, k: impl ObjectIndex) -> Option<(&IString, &IValue)> {
685        k.index_into(self)
686    }
687
688    /// Looks up the specified key in this object and returns a (&key, &mut value) pair
689    /// if found.
690    pub fn get_key_value_mut(&mut self, k: impl ObjectIndex) -> Option<(&IString, &mut IValue)> {
691        k.index_into_mut(self)
692    }
693
694    /// Looks up the specified key in this object and returns a reference to the
695    /// corresponding value if found.
696    pub fn get(&self, k: impl ObjectIndex) -> Option<&IValue> {
697        self.get_key_value(k).map(|x| x.1)
698    }
699
700    /// Looks up the specified key in this object and returns a mutable reference to
701    /// the corresponding value if found.
702    pub fn get_mut(&mut self, k: impl ObjectIndex) -> Option<&mut IValue> {
703        self.get_key_value_mut(k).map(|x| x.1)
704    }
705
706    /// Returns `true` if the specified key exists in the object.
707    pub fn contains_key(&self, k: impl ObjectIndex) -> bool {
708        self.get(k).is_some()
709    }
710
711    /// Inserts a new value into this object with the specified key. If a value already
712    /// existed at this key, that value is replaced and returend.
713    pub fn insert(&mut self, k: impl Into<IString>, v: impl Into<IValue>) -> Option<IValue> {
714        match self.entry(k) {
715            Entry::Occupied(mut occ) => Some(occ.insert(v)),
716            Entry::Vacant(vac) => {
717                vac.insert(v);
718                None
719            }
720        }
721    }
722
723    /// Removes the entry at the specified key, returning both the key and value if
724    /// found.
725    pub fn remove_entry(&mut self, k: impl ObjectIndex) -> Option<(IString, IValue)> {
726        k.remove(self)
727    }
728
729    /// Removes the entry at the specified key, returning the value if found.
730    pub fn remove(&mut self, k: impl ObjectIndex) -> Option<IValue> {
731        self.remove_entry(k).map(|x| x.1)
732    }
733
734    /// Shrinks the memory allocation used by the object such that its
735    /// capacity becomes equal to its length.
736    pub fn shrink_to_fit(&mut self) {
737        self.resize_internal(self.len());
738    }
739
740    /// Calls the specified function for each entry in the object. Each entry
741    /// where the function returns `false` is removed from the object.
742    ///
743    /// The function also has the ability to modify the values in-place.
744    pub fn retain(&mut self, mut f: impl FnMut(&IString, &mut IValue) -> bool) {
745        if !self.is_empty() {
746            // Safety: not static
747            let mut hd = unsafe { self.header_mut() };
748            let mut index = 0;
749            while index < hd.len {
750                let mut split = hd.reborrow().split_mut();
751
752                // Safety: Indices are in range
753                unsafe {
754                    let kvp = split.items.get_unchecked_mut(index);
755                    if f(&kvp.key, &mut kvp.value) {
756                        index += 1;
757                    } else {
758                        let bucket = split.as_ref().find_bucket_from_index(index);
759                        split.remove_bucket(bucket);
760                        hd.pop();
761                    }
762                }
763            }
764        }
765    }
766
767    pub(crate) fn clone_impl(&self) -> IValue {
768        let mut res = Self::with_capacity(self.len());
769        for (k, v) in self.iter() {
770            res.insert(k.clone(), v.clone());
771        }
772
773        res.0
774    }
775    pub(crate) fn drop_impl(&mut self) {
776        self.clear();
777        if !self.is_static() {
778            unsafe {
779                Self::dealloc(self.0.ptr().cast());
780                self.0.set_ref(&EMPTY_HEADER);
781            }
782        }
783    }
784}
785
786impl IntoIterator for IObject {
787    type Item = (IString, IValue);
788    type IntoIter = IntoIter;
789
790    fn into_iter(mut self) -> Self::IntoIter {
791        unsafe {
792            let split_header = self.header_mut().split_mut();
793            split_header.items.reverse();
794        }
795        IntoIter {
796            reversed_object: self,
797        }
798    }
799}
800
801impl PartialEq for IObject {
802    fn eq(&self, other: &Self) -> bool {
803        if self.0.raw_eq(&other.0) {
804            return true;
805        }
806        if self.len() != other.len() {
807            return false;
808        }
809        for (k, v) in self.iter() {
810            if other.get(k) != Some(v) {
811                return false;
812            }
813        }
814        true
815    }
816}
817
818impl Eq for IObject {}
819impl PartialOrd for IObject {
820    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
821        if self == other {
822            Some(Ordering::Equal)
823        } else {
824            None
825        }
826    }
827}
828
829impl Hash for IObject {
830    fn hash<H: Hasher>(&self, state: &mut H) {
831        self.len().hash(state);
832
833        let mut total_hash = 0_u64;
834        for item in self.iter() {
835            let mut h = DefaultHasher::new();
836            item.hash(&mut h);
837            total_hash = total_hash.wrapping_add(h.finish());
838        }
839        total_hash.hash(state);
840    }
841}
842
843impl<K: Into<IString>, V: Into<IValue>> Extend<(K, V)> for IObject {
844    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
845        let iter = iter.into_iter();
846        self.reserve(iter.size_hint().0);
847        for (k, v) in iter {
848            self.insert(k, v);
849        }
850    }
851}
852
853impl<K: Into<IString>, V: Into<IValue>> FromIterator<(K, V)> for IObject {
854    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
855        let mut res = IObject::new();
856        res.extend(iter);
857        res
858    }
859}
860
861impl<I: ObjectIndex> Index<I> for IObject {
862    type Output = IValue;
863
864    #[inline]
865    fn index(&self, index: I) -> &IValue {
866        index.index_into(self).unwrap().1
867    }
868}
869
870impl<I: ObjectIndex> IndexMut<I> for IObject {
871    #[inline]
872    fn index_mut(&mut self, index: I) -> &mut IValue {
873        index.index_or_insert(self)
874    }
875}
876
877mod private {
878    #[doc(hidden)]
879    pub trait Sealed {}
880    impl Sealed for usize {}
881    impl Sealed for &str {}
882    impl Sealed for &super::IString {}
883    impl<T: Sealed> Sealed for &T {}
884}
885
886/// Trait which abstracts over the various string types which can be used
887/// to index into an [`IObject`].
888pub trait ObjectIndex: private::Sealed + Copy {
889    #[doc(hidden)]
890    fn index_into(self, v: &IObject) -> Option<(&IString, &IValue)>;
891
892    #[doc(hidden)]
893    fn index_into_mut(self, v: &mut IObject) -> Option<(&IString, &mut IValue)>;
894
895    #[doc(hidden)]
896    fn index_or_insert(self, v: &mut IObject) -> &mut IValue;
897
898    #[doc(hidden)]
899    fn remove(self, v: &mut IObject) -> Option<(IString, IValue)>;
900}
901
902impl ObjectIndex for &str {
903    fn index_into(self, v: &IObject) -> Option<(&IString, &IValue)> {
904        IString::intern(self).index_into(v)
905    }
906
907    fn index_into_mut(self, v: &mut IObject) -> Option<(&IString, &mut IValue)> {
908        IString::intern(self).index_into_mut(v)
909    }
910
911    fn index_or_insert(self, v: &mut IObject) -> &mut IValue {
912        v.entry(IString::intern(self)).or_insert(IValue::NULL)
913    }
914
915    fn remove(self, v: &mut IObject) -> Option<(IString, IValue)> {
916        IString::intern(self).remove(v)
917    }
918}
919
920impl ObjectIndex for &IString {
921    fn index_into(self, v: &IObject) -> Option<(&IString, &IValue)> {
922        if v.is_empty() {
923            return None;
924        }
925        let hd = v.header().split();
926        if let Ok(bucket) = hd.find_bucket(self) {
927            // Safety: Bucket index is valid
928            unsafe {
929                let index = *hd.table.get_unchecked(bucket);
930                let item = hd.items.get_unchecked(index);
931                Some((&item.key, &item.value))
932            }
933        } else {
934            None
935        }
936    }
937
938    fn index_into_mut(self, v: &mut IObject) -> Option<(&IString, &mut IValue)> {
939        if v.is_empty() {
940            None
941        } else {
942            // Safety: not static
943            let hd = unsafe { v.header_mut().split_mut() };
944            if let Ok(bucket) = hd.as_ref().find_bucket(self) {
945                // Safety: Bucket index is valid
946                unsafe {
947                    let index = *hd.table.get_unchecked(bucket);
948                    let item = hd.items.get_unchecked_mut(index);
949                    Some((&item.key, &mut item.value))
950                }
951            } else {
952                None
953            }
954        }
955    }
956
957    fn index_or_insert(self, v: &mut IObject) -> &mut IValue {
958        v.entry_or_clone(self).or_insert(IValue::NULL)
959    }
960
961    fn remove(self, v: &mut IObject) -> Option<(IString, IValue)> {
962        if v.is_empty() {
963            None
964        } else {
965            // Safety: not static
966            let mut hd = unsafe { v.header_mut() };
967            let mut split = hd.reborrow().split_mut();
968            if let Ok(bucket) = split.as_ref().find_bucket(self) {
969                // Safety: Bucket index is valid
970                unsafe {
971                    split.remove_bucket(bucket);
972                    Some(hd.pop())
973                }
974            } else {
975                None
976            }
977        }
978    }
979}
980
981impl<T: ObjectIndex> ObjectIndex for &T {
982    fn index_into(self, v: &IObject) -> Option<(&IString, &IValue)> {
983        (*self).index_into(v)
984    }
985
986    fn index_into_mut(self, v: &mut IObject) -> Option<(&IString, &mut IValue)> {
987        (*self).index_into_mut(v)
988    }
989
990    fn index_or_insert(self, v: &mut IObject) -> &mut IValue {
991        (*self).index_or_insert(v)
992    }
993
994    fn remove(self, v: &mut IObject) -> Option<(IString, IValue)> {
995        (*self).remove(v)
996    }
997}
998
999impl Debug for IObject {
1000    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1001        f.debug_map().entries(self.iter()).finish()
1002    }
1003}
1004
1005/// Iterator over (&[`IString`], &[`IValue`]) pairs returned from
1006/// [`IObject::iter`]
1007#[derive(Debug)]
1008pub struct Iter<'a>(std::slice::Iter<'a, KeyValuePair>);
1009
1010impl<'a> Iterator for Iter<'a> {
1011    type Item = (&'a IString, &'a IValue);
1012
1013    fn next(&mut self) -> Option<Self::Item> {
1014        self.0.next().map(|x| (&x.key, &x.value))
1015    }
1016}
1017
1018impl<'a> ExactSizeIterator for Iter<'a> {
1019    fn len(&self) -> usize {
1020        self.0.len()
1021    }
1022}
1023
1024/// Iterator over (&[`IString`], &mut [`IValue`]) pairs returned from
1025/// [`IObject::iter_mut`]
1026#[derive(Debug)]
1027pub struct IterMut<'a>(std::slice::IterMut<'a, KeyValuePair>);
1028
1029impl<'a> Iterator for IterMut<'a> {
1030    type Item = (&'a IString, &'a mut IValue);
1031
1032    fn next(&mut self) -> Option<Self::Item> {
1033        self.0.next().map(|x| (&x.key, &mut x.value))
1034    }
1035}
1036
1037impl<'a> ExactSizeIterator for IterMut<'a> {
1038    fn len(&self) -> usize {
1039        self.0.len()
1040    }
1041}
1042
1043impl<'a> IntoIterator for &'a IObject {
1044    type Item = (&'a IString, &'a IValue);
1045    type IntoIter = Iter<'a>;
1046
1047    fn into_iter(self) -> Self::IntoIter {
1048        self.iter()
1049    }
1050}
1051
1052impl<'a> IntoIterator for &'a mut IObject {
1053    type Item = (&'a IString, &'a mut IValue);
1054    type IntoIter = IterMut<'a>;
1055
1056    fn into_iter(self) -> Self::IntoIter {
1057        self.iter_mut()
1058    }
1059}
1060
1061impl<K: Into<IString>, V: Into<IValue>> From<HashMap<K, V>> for IObject {
1062    fn from(other: HashMap<K, V>) -> Self {
1063        let mut res = Self::with_capacity(other.len());
1064        res.extend(other.into_iter().map(|(k, v)| (k.into(), v.into())));
1065        res
1066    }
1067}
1068
1069impl<K: Into<IString>, V: Into<IValue>> From<BTreeMap<K, V>> for IObject {
1070    fn from(other: BTreeMap<K, V>) -> Self {
1071        let mut res = Self::with_capacity(other.len());
1072        res.extend(other.into_iter().map(|(k, v)| (k.into(), v.into())));
1073        res
1074    }
1075}
1076
1077#[cfg(feature = "indexmap")]
1078impl<K: Into<IString>, V: Into<IValue>> From<IndexMap<K, V>> for IObject {
1079    fn from(other: IndexMap<K, V>) -> Self {
1080        let mut res = Self::with_capacity(other.len());
1081        res.extend(other.into_iter().map(|(k, v)| (k.into(), v.into())));
1082        res
1083    }
1084}
1085
1086impl Default for IObject {
1087    fn default() -> Self {
1088        Self::new()
1089    }
1090}
1091
1092#[cfg(test)]
1093mod tests {
1094    use super::*;
1095
1096    #[mockalloc::test]
1097    fn can_create() {
1098        let x = IObject::new();
1099        let y = IObject::with_capacity(10);
1100
1101        assert_eq!(x, y);
1102    }
1103
1104    #[mockalloc::test]
1105    fn can_collect() {
1106        let x = vec![
1107            ("a", IValue::NULL),
1108            ("b", IValue::TRUE),
1109            ("c", IValue::FALSE),
1110        ];
1111        let y: IObject = x.into_iter().collect();
1112
1113        assert_eq!(y, y.clone());
1114        assert_eq!(y.len(), 3);
1115        assert_eq!(y["a"], IValue::NULL);
1116        assert_eq!(y["b"], IValue::TRUE);
1117        assert_eq!(y["c"], IValue::FALSE);
1118    }
1119
1120    #[mockalloc::test]
1121    fn can_insert() {
1122        let mut x = IObject::new();
1123        x.insert("a", IValue::NULL);
1124        x.insert("b", IValue::TRUE);
1125        x.insert("c", IValue::FALSE);
1126
1127        assert_eq!(x.len(), 3);
1128        assert_eq!(x["a"], IValue::NULL);
1129        assert_eq!(x["b"], IValue::TRUE);
1130        assert_eq!(x["c"], IValue::FALSE);
1131    }
1132
1133    #[mockalloc::test]
1134    fn can_nest() {
1135        let mut x = IObject::new();
1136        x.insert("a", IValue::NULL);
1137        x.insert("b", x.clone());
1138        x.insert("c", IValue::FALSE);
1139        x.insert("d", x.clone());
1140
1141        assert_eq!(x.len(), 4);
1142        assert_eq!(x["a"], IValue::NULL);
1143        assert_eq!(x["b"].len(), Some(1));
1144        assert_eq!(x["c"], IValue::FALSE);
1145        assert_eq!(x["d"].len(), Some(3));
1146    }
1147
1148    #[mockalloc::test]
1149    fn can_remove_and_shrink() {
1150        let x = vec![
1151            ("a", IValue::NULL),
1152            ("b", IValue::TRUE),
1153            ("c", IValue::FALSE),
1154        ];
1155        let mut y: IObject = x.into_iter().collect();
1156        assert_eq!(y.len(), 3);
1157        assert_eq!(y.capacity(), 4);
1158
1159        assert_eq!(y.remove("b"), Some(IValue::TRUE));
1160        assert_eq!(y.remove("b"), None);
1161        assert_eq!(y.remove("d"), None);
1162
1163        assert_eq!(y.len(), 2);
1164        assert_eq!(y.capacity(), 4);
1165        assert_eq!(y["a"], IValue::NULL);
1166        assert_eq!(y["c"], IValue::FALSE);
1167
1168        y.shrink_to_fit();
1169        assert_eq!(y.len(), 2);
1170        assert_eq!(y.capacity(), 2);
1171        assert_eq!(y["a"], IValue::NULL);
1172        assert_eq!(y["c"], IValue::FALSE);
1173    }
1174
1175    // Too slow for miri
1176    #[cfg(not(miri))]
1177    #[mockalloc::test]
1178    fn stress_test() {
1179        use rand::prelude::*;
1180
1181        for i in 0..10 {
1182            // We want our test to be random but for errors to be reproducible
1183            let mut rng = StdRng::seed_from_u64(i);
1184            let range = 0..10000;
1185            let mut ops: Vec<i32> = range.clone().chain(range).collect();
1186            ops.shuffle(&mut rng);
1187
1188            let mut x = IObject::new();
1189            for op in ops {
1190                let k = IString::intern(&op.to_string());
1191                if x.contains_key(&k) {
1192                    x.remove(&k);
1193                } else {
1194                    x.insert(k, op);
1195                }
1196            }
1197            assert_eq!(x, IObject::new());
1198        }
1199    }
1200}