feldera_ijson/
array.rs

1//! Functionality relating to the JSON array type
2
3use std::alloc::{alloc, dealloc, realloc, Layout, LayoutError};
4use std::borrow::{Borrow, BorrowMut};
5use std::cmp::{self, Ordering};
6use std::fmt::{self, Debug, Formatter};
7use std::hash::Hash;
8use std::iter::FromIterator;
9use std::ops::{Deref, DerefMut, Index, IndexMut};
10use std::slice::SliceIndex;
11
12use crate::thin::{ThinMut, ThinMutExt, ThinRef, ThinRefExt};
13
14use super::value::{IValue, TypeTag};
15
16#[repr(C)]
17#[repr(align(4))]
18struct Header {
19    len: usize,
20    cap: usize,
21}
22
23trait HeaderRef<'a>: ThinRefExt<'a, Header> {
24    fn array_ptr(&self) -> *const IValue {
25        // Safety: pointers to the end of structs are allowed
26        unsafe { self.ptr().add(1).cast::<IValue>() }
27    }
28    fn items_slice(&self) -> &'a [IValue] {
29        // Safety: Header `len` must be accurate
30        unsafe { std::slice::from_raw_parts(self.array_ptr(), self.len) }
31    }
32}
33
34trait HeaderMut<'a>: ThinMutExt<'a, Header> {
35    fn array_ptr_mut(mut self) -> *mut IValue {
36        // Safety: pointers to the end of structs are allowed
37        unsafe { self.ptr_mut().add(1).cast::<IValue>() }
38    }
39    fn items_slice_mut(self) -> &'a mut [IValue] {
40        // Safety: Header `len` must be accurate
41        let len = self.len;
42        unsafe { std::slice::from_raw_parts_mut(self.array_ptr_mut(), len) }
43    }
44    // Safety: Space must already be allocated for the item
45    unsafe fn push(&mut self, item: IValue) {
46        let index = self.len;
47        self.reborrow().array_ptr_mut().add(index).write(item);
48        self.len += 1;
49    }
50    fn pop(&mut self) -> Option<IValue> {
51        if self.len == 0 {
52            None
53        } else {
54            self.len -= 1;
55            let index = self.len;
56
57            // Safety: We just checked that an item exists
58            unsafe { Some(self.reborrow().array_ptr_mut().add(index).read()) }
59        }
60    }
61}
62
63impl<'a, T: ThinRefExt<'a, Header>> HeaderRef<'a> for T {}
64impl<'a, T: ThinMutExt<'a, Header>> HeaderMut<'a> for T {}
65
66/// Iterator over [`IValue`]s returned from [`IArray::into_iter`]
67pub struct IntoIter {
68    reversed_array: IArray,
69}
70
71impl Iterator for IntoIter {
72    type Item = IValue;
73
74    fn next(&mut self) -> Option<Self::Item> {
75        self.reversed_array.pop()
76    }
77}
78
79impl ExactSizeIterator for IntoIter {
80    fn len(&self) -> usize {
81        self.reversed_array.len()
82    }
83}
84
85impl Debug for IntoIter {
86    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
87        f.debug_struct("IntoIter")
88            .field("reversed_array", &self.reversed_array)
89            .finish()
90    }
91}
92
93/// The `IArray` type is similar to a `Vec<IValue>`. The primary difference is
94/// that the length and capacity are stored _inside_ the heap allocation, so that
95/// the `IArray` itself can be a single pointer.
96#[repr(transparent)]
97#[derive(Clone, size_of::SizeOf, Ord)]
98pub struct IArray(pub(crate) IValue);
99
100value_subtype_impls!(IArray, into_array, as_array, as_array_mut);
101
102static EMPTY_HEADER: Header = Header { len: 0, cap: 0 };
103
104impl IArray {
105    fn layout(cap: usize) -> Result<Layout, LayoutError> {
106        Ok(Layout::new::<Header>()
107            .extend(Layout::array::<usize>(cap)?)?
108            .0
109            .pad_to_align())
110    }
111
112    fn alloc(cap: usize) -> *mut Header {
113        unsafe {
114            let ptr = alloc(Self::layout(cap).unwrap()).cast::<Header>();
115            ptr.write(Header { len: 0, cap });
116            ptr
117        }
118    }
119
120    fn realloc(ptr: *mut Header, new_cap: usize) -> *mut Header {
121        unsafe {
122            let old_layout = Self::layout((*ptr).cap).unwrap();
123            let new_layout = Self::layout(new_cap).unwrap();
124            let ptr = realloc(ptr.cast::<u8>(), old_layout, new_layout.size()).cast::<Header>();
125            (*ptr).cap = new_cap;
126            ptr
127        }
128    }
129
130    fn dealloc(ptr: *mut Header) {
131        unsafe {
132            let layout = Self::layout((*ptr).cap).unwrap();
133            dealloc(ptr.cast(), layout);
134        }
135    }
136
137    /// Constructs a new empty `IArray`. Does not allocate.
138    #[must_use]
139    pub fn new() -> Self {
140        unsafe { IArray(IValue::new_ref(&EMPTY_HEADER, TypeTag::ArrayOrFalse)) }
141    }
142
143    /// Constructs a new `IArray` with the specified capacity. At least that many items
144    /// can be added to the array without reallocating.
145    #[must_use]
146    pub fn with_capacity(cap: usize) -> Self {
147        if cap == 0 {
148            Self::new()
149        } else {
150            IArray(unsafe { IValue::new_ptr(Self::alloc(cap).cast(), TypeTag::ArrayOrFalse) })
151        }
152    }
153
154    fn header(&self) -> ThinRef<Header> {
155        unsafe { ThinRef::new(self.0.ptr().cast()) }
156    }
157
158    // Safety: must not be static
159    unsafe fn header_mut(&mut self) -> ThinMut<Header> {
160        ThinMut::new(self.0.ptr().cast())
161    }
162
163    fn is_static(&self) -> bool {
164        self.capacity() == 0
165    }
166    /// Returns the capacity of the array. This is the maximum number of items the array
167    /// can hold without reallocating.
168    #[must_use]
169    pub fn capacity(&self) -> usize {
170        self.header().cap
171    }
172
173    /// Returns the number of items currently stored in the array.
174    #[must_use]
175    pub fn len(&self) -> usize {
176        self.header().len
177    }
178
179    /// Returns `true` if the array is empty.
180    #[must_use]
181    pub fn is_empty(&self) -> bool {
182        self.len() == 0
183    }
184
185    /// Borrows a slice of [`IValue`]s from the array
186    #[must_use]
187    pub fn as_slice(&self) -> &[IValue] {
188        self.header().items_slice()
189    }
190
191    /// Borrows a mutable slice of [`IValue`]s from the array
192    pub fn as_mut_slice(&mut self) -> &mut [IValue] {
193        if self.is_static() {
194            &mut []
195        } else {
196            unsafe { self.header_mut().items_slice_mut() }
197        }
198    }
199    fn resize_internal(&mut self, cap: usize) {
200        if self.is_static() || cap == 0 {
201            *self = Self::with_capacity(cap);
202        } else {
203            unsafe {
204                let new_ptr = Self::realloc(self.0.ptr().cast(), cap);
205                self.0.set_ptr(new_ptr.cast());
206            }
207        }
208    }
209
210    /// Reserves space for at least this many additional items.
211    pub fn reserve(&mut self, additional: usize) {
212        let hd = self.header();
213        let current_capacity = hd.cap;
214        let desired_capacity = hd.len.checked_add(additional).unwrap();
215        if current_capacity >= desired_capacity {
216            return;
217        }
218        self.resize_internal(cmp::max(current_capacity * 2, desired_capacity.max(4)));
219    }
220
221    /// Truncates the array by removing items until it is no longer than the specified
222    /// length. The capacity is unchanged.
223    pub fn truncate(&mut self, len: usize) {
224        if self.is_static() {
225            return;
226        }
227        unsafe {
228            let mut hd = self.header_mut();
229            while hd.len > len {
230                hd.pop();
231            }
232        }
233    }
234
235    /// Removes all items from the array. The capacity is unchanged.
236    pub fn clear(&mut self) {
237        self.truncate(0);
238    }
239
240    /// Inserts a new item into the array at the specified index. Any existing items
241    /// on or after this index will be shifted down to accomodate this. For large
242    /// arrays, insertions near the front will be slow as it will require shifting
243    /// a large number of items.
244    pub fn insert(&mut self, index: usize, item: impl Into<IValue>) {
245        self.reserve(1);
246
247        unsafe {
248            // Safety: cannot be static after calling `reserve`
249            let mut hd = self.header_mut();
250            assert!(index <= hd.len);
251
252            // Safety: We just reserved enough space for at least one extra item
253            hd.push(item.into());
254            if index < hd.len {
255                hd.items_slice_mut()[index..].rotate_right(1);
256            }
257        }
258    }
259
260    /// Removes and returns the item at the specified index from the array. Any
261    /// items after this index will be shifted back up to close the gap. For large
262    /// arrays, removals from near the front will be slow as it will require shifting
263    /// a large number of items.
264    ///
265    /// If the order of the array is unimporant, consider using [`IArray::swap_remove`].
266    ///
267    /// If the index is outside the array bounds, `None` is returned.
268    pub fn remove(&mut self, index: usize) -> Option<IValue> {
269        if index < self.len() {
270            // Safety: cannot be static if index <= len
271            unsafe {
272                let mut hd = self.header_mut();
273                hd.reborrow().items_slice_mut()[index..].rotate_left(1);
274                hd.pop()
275            }
276        } else {
277            None
278        }
279    }
280
281    /// Removes and returns the item at the specified index from the array by
282    /// first swapping it with the item currently at the end of the array, and
283    /// then popping that last item.
284    ///
285    /// This can be more efficient than [`IArray::remove`] for large arrays,
286    /// but will change the ordering of items within the array.
287    ///
288    /// If the index is outside the array bounds, `None` is returned.
289    pub fn swap_remove(&mut self, index: usize) -> Option<IValue> {
290        if index < self.len() {
291            // Safety: cannot be static if index <= len
292            unsafe {
293                let mut hd = self.header_mut();
294                let last_index = hd.len - 1;
295                hd.reborrow().items_slice_mut().swap(index, last_index);
296                hd.pop()
297            }
298        } else {
299            None
300        }
301    }
302
303    /// Pushes a new item onto the back of the array.
304    pub fn push(&mut self, item: impl Into<IValue>) {
305        self.reserve(1);
306        // Safety: We just reserved enough space for at least one extra item
307        unsafe {
308            self.header_mut().push(item.into());
309        }
310    }
311
312    /// Pops the last item from the array and returns it. If the array is
313    /// empty, `None` is returned.
314    pub fn pop(&mut self) -> Option<IValue> {
315        if self.is_static() {
316            None
317        } else {
318            // Safety: not static
319            unsafe { self.header_mut().pop() }
320        }
321    }
322
323    /// Shrinks the memory allocation used by the array such that its
324    /// capacity becomes equal to its length.
325    pub fn shrink_to_fit(&mut self) {
326        self.resize_internal(self.len());
327    }
328
329    pub(crate) fn clone_impl(&self) -> IValue {
330        let src = self.header().items_slice();
331        let l = src.len();
332        let mut res = Self::with_capacity(l);
333
334        if l > 0 {
335            unsafe {
336                // Safety: we cannot be static if len > 0
337                let mut hd = res.header_mut();
338                for v in src {
339                    // Safety: we reserved enough space at the start
340                    hd.push(v.clone());
341                }
342            }
343        }
344        res.0
345    }
346    pub(crate) fn drop_impl(&mut self) {
347        self.clear();
348        if !self.is_static() {
349            unsafe {
350                Self::dealloc(self.0.ptr().cast());
351                self.0.set_ref(&EMPTY_HEADER);
352            }
353        }
354    }
355}
356
357impl IntoIterator for IArray {
358    type Item = IValue;
359    type IntoIter = IntoIter;
360
361    fn into_iter(mut self) -> Self::IntoIter {
362        self.reverse();
363        IntoIter {
364            reversed_array: self,
365        }
366    }
367}
368
369impl Deref for IArray {
370    type Target = [IValue];
371
372    fn deref(&self) -> &Self::Target {
373        self.as_slice()
374    }
375}
376
377impl DerefMut for IArray {
378    fn deref_mut(&mut self) -> &mut Self::Target {
379        self.as_mut_slice()
380    }
381}
382
383impl Borrow<[IValue]> for IArray {
384    fn borrow(&self) -> &[IValue] {
385        self.as_slice()
386    }
387}
388
389impl BorrowMut<[IValue]> for IArray {
390    fn borrow_mut(&mut self) -> &mut [IValue] {
391        self.as_mut_slice()
392    }
393}
394
395impl Hash for IArray {
396    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
397        self.as_slice().hash(state);
398    }
399}
400
401impl<U: Into<IValue>> Extend<U> for IArray {
402    fn extend<T: IntoIterator<Item = U>>(&mut self, iter: T) {
403        let iter = iter.into_iter();
404        self.reserve(iter.size_hint().0);
405        for v in iter {
406            self.push(v);
407        }
408    }
409}
410
411impl<U: Into<IValue>> FromIterator<U> for IArray {
412    fn from_iter<T: IntoIterator<Item = U>>(iter: T) -> Self {
413        let mut res = IArray::new();
414        res.extend(iter);
415        res
416    }
417}
418
419impl AsRef<[IValue]> for IArray {
420    fn as_ref(&self) -> &[IValue] {
421        self.as_slice()
422    }
423}
424
425impl PartialEq for IArray {
426    fn eq(&self, other: &Self) -> bool {
427        if self.0.raw_eq(&other.0) {
428            true
429        } else {
430            self.as_slice() == other.as_slice()
431        }
432    }
433}
434
435impl Eq for IArray {}
436impl PartialOrd for IArray {
437    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
438        if self.0.raw_eq(&other.0) {
439            Some(Ordering::Equal)
440        } else {
441            self.as_slice().partial_cmp(other.as_slice())
442        }
443    }
444}
445
446impl<I: SliceIndex<[IValue]>> Index<I> for IArray {
447    type Output = I::Output;
448
449    #[inline]
450    fn index(&self, index: I) -> &Self::Output {
451        Index::index(self.as_slice(), index)
452    }
453}
454
455impl<I: SliceIndex<[IValue]>> IndexMut<I> for IArray {
456    #[inline]
457    fn index_mut(&mut self, index: I) -> &mut Self::Output {
458        IndexMut::index_mut(self.as_mut_slice(), index)
459    }
460}
461
462impl Debug for IArray {
463    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
464        Debug::fmt(self.as_slice(), f)
465    }
466}
467
468impl<T: Into<IValue>> From<Vec<T>> for IArray {
469    fn from(other: Vec<T>) -> Self {
470        let mut res = IArray::with_capacity(other.len());
471        res.extend(other.into_iter().map(Into::into));
472        res
473    }
474}
475
476impl<T: Into<IValue> + Clone> From<&[T]> for IArray {
477    fn from(other: &[T]) -> Self {
478        let mut res = IArray::with_capacity(other.len());
479        res.extend(other.iter().cloned().map(Into::into));
480        res
481    }
482}
483
484impl<'a> IntoIterator for &'a IArray {
485    type Item = &'a IValue;
486    type IntoIter = std::slice::Iter<'a, IValue>;
487
488    fn into_iter(self) -> Self::IntoIter {
489        self.iter()
490    }
491}
492
493impl<'a> IntoIterator for &'a mut IArray {
494    type Item = &'a mut IValue;
495    type IntoIter = std::slice::IterMut<'a, IValue>;
496
497    fn into_iter(self) -> Self::IntoIter {
498        self.iter_mut()
499    }
500}
501
502impl Default for IArray {
503    fn default() -> Self {
504        Self::new()
505    }
506}
507
508#[cfg(test)]
509mod tests {
510    use super::*;
511
512    #[mockalloc::test]
513    fn can_create() {
514        let x = IArray::new();
515        let y = IArray::with_capacity(10);
516
517        assert_eq!(x, y);
518    }
519
520    #[mockalloc::test]
521    fn can_collect() {
522        let x = vec![IValue::NULL, IValue::TRUE, IValue::FALSE];
523        let y: IArray = x.iter().cloned().collect();
524
525        assert_eq!(x.as_slice(), y.as_slice());
526    }
527
528    #[mockalloc::test]
529    fn can_push_insert() {
530        let mut x = IArray::new();
531        x.insert(0, IValue::NULL);
532        x.push(IValue::TRUE);
533        x.insert(1, IValue::FALSE);
534
535        assert_eq!(x.as_slice(), &[IValue::NULL, IValue::FALSE, IValue::TRUE]);
536    }
537
538    #[mockalloc::test]
539    fn can_nest() {
540        let x: IArray = vec![IValue::NULL, IValue::TRUE, IValue::FALSE].into();
541        let y: IArray = vec![
542            IValue::NULL,
543            x.clone().into(),
544            IValue::FALSE,
545            x.clone().into(),
546        ]
547        .into();
548
549        assert_eq!(&y[1], x.as_ref());
550    }
551
552    #[mockalloc::test]
553    fn can_pop_remove() {
554        let mut x: IArray = vec![IValue::NULL, IValue::TRUE, IValue::FALSE].into();
555        assert_eq!(x.remove(1), Some(IValue::TRUE));
556        assert_eq!(x.pop(), Some(IValue::FALSE));
557
558        assert_eq!(x.as_slice(), &[IValue::NULL]);
559    }
560
561    #[mockalloc::test]
562    fn can_swap_remove() {
563        let mut x: IArray = vec![IValue::NULL, IValue::TRUE, IValue::FALSE].into();
564        assert_eq!(x.swap_remove(0), Some(IValue::NULL));
565
566        assert_eq!(x.as_slice(), &[IValue::FALSE, IValue::TRUE]);
567    }
568
569    #[mockalloc::test]
570    fn can_index() {
571        let mut x: IArray = vec![IValue::NULL, IValue::TRUE, IValue::FALSE].into();
572        assert_eq!(x[1], IValue::TRUE);
573        x[1] = IValue::FALSE;
574        assert_eq!(x[1], IValue::FALSE);
575    }
576
577    #[mockalloc::test]
578    fn can_truncate_and_shrink() {
579        let mut x: IArray =
580            vec![IValue::NULL, IValue::TRUE, IArray::with_capacity(10).into()].into();
581        x.truncate(2);
582        assert_eq!(x.len(), 2);
583        assert_eq!(x.capacity(), 3);
584        x.shrink_to_fit();
585        assert_eq!(x.len(), 2);
586        assert_eq!(x.capacity(), 2);
587    }
588
589    // Too slow for miri
590    #[cfg(not(miri))]
591    #[mockalloc::test]
592    fn stress_test() {
593        use rand::prelude::*;
594
595        for i in 0..10 {
596            // We want our test to be random but for errors to be reproducible
597            let mut rng = StdRng::seed_from_u64(i);
598            let mut arr = IArray::new();
599
600            for j in 0..1000 {
601                let index = rng.gen_range(0..arr.len() + 1);
602                if rng.gen() {
603                    arr.insert(index, j);
604                } else {
605                    arr.remove(index);
606                }
607            }
608        }
609    }
610}