Skip to main content

toml_spanner/
array.rs

1#[cfg(test)]
2#[path = "./array_tests.rs"]
3mod tests;
4
5use crate::MaybeItem;
6use crate::arena::Arena;
7use crate::value::Item;
8use std::mem::size_of;
9use std::ptr::NonNull;
10
11const MIN_CAP: u32 = 4;
12
13/// A growable array of TOML [`Item`]s.
14///
15/// Arrays support indexing with `usize` via the `[]` operator, which returns
16/// a [`MaybeItem`] — out-of-bounds access returns a `None` variant instead of
17/// panicking. Use [`get`](Self::get) / [`get_mut`](Self::get_mut) for
18/// `Option`-based access, or iterate with a `for` loop.
19///
20/// Mutation methods ([`push`](Self::push), [`with_capacity`](Self::with_capacity))
21/// require an [`Arena`] because array storage is arena-allocated.
22pub struct Array<'de> {
23    len: u32,
24    cap: u32,
25    ptr: NonNull<Item<'de>>,
26}
27
28impl<'de> Default for Array<'de> {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl<'de> Array<'de> {
35    /// Creates an empty array.
36    #[inline]
37    pub fn new() -> Self {
38        Self {
39            len: 0,
40            cap: 0,
41            ptr: NonNull::dangling(),
42        }
43    }
44
45    /// Creates an array with pre-allocated capacity.
46    pub fn with_capacity(cap: u32, arena: &'de Arena) -> Self {
47        let mut arr = Self::new();
48        if cap > 0 {
49            arr.grow_to(cap, arena);
50        }
51        arr
52    }
53
54    /// Creates an array containing a single value.
55    pub fn with_single(value: Item<'de>, arena: &'de Arena) -> Self {
56        let mut arr = Self::with_capacity(MIN_CAP, arena);
57        // SAFETY: with_capacity allocated space for at least MIN_CAP items,
58        // so writing at index 0 is within bounds.
59        unsafe {
60            arr.ptr.as_ptr().write(value);
61        }
62        arr.len = 1;
63        arr
64    }
65
66    /// Appends a value to the end of the array.
67    #[inline]
68    pub fn push(&mut self, value: Item<'de>, arena: &'de Arena) {
69        let len = self.len;
70        if len == self.cap {
71            self.grow(arena);
72        }
73        // SAFETY: grow() ensures len < cap, so ptr.add(len) is within the allocation.
74        unsafe {
75            self.ptr.as_ptr().add(len as usize).write(value);
76        }
77        self.len = len + 1;
78    }
79
80    /// Returns the number of elements.
81    #[inline]
82    pub fn len(&self) -> usize {
83        self.len as usize
84    }
85
86    /// Returns `true` if the array contains no elements.
87    #[inline]
88    pub fn is_empty(&self) -> bool {
89        self.len == 0
90    }
91
92    /// Returns a reference to the element at the given index.
93    #[inline]
94    pub fn get(&self, index: usize) -> Option<&Item<'de>> {
95        if index < self.len as usize {
96            // SAFETY: index < len is checked above, so the pointer is within
97            // initialized elements.
98            Some(unsafe { &*self.ptr.as_ptr().add(index) })
99        } else {
100            None
101        }
102    }
103
104    /// Returns a mutable reference to the element at the given index.
105    #[inline]
106    pub fn get_mut(&mut self, index: usize) -> Option<&mut Item<'de>> {
107        if index < self.len as usize {
108            // SAFETY: index < len is checked above.
109            Some(unsafe { &mut *self.ptr.as_ptr().add(index) })
110        } else {
111            None
112        }
113    }
114
115    /// Removes and returns the last element, or `None` if empty.
116    #[inline]
117    pub fn pop(&mut self) -> Option<Item<'de>> {
118        if self.len == 0 {
119            None
120        } else {
121            self.len -= 1;
122            // SAFETY: len was > 0 and was just decremented, so ptr.add(len)
123            // points to the last initialized element.
124            Some(unsafe { self.ptr.as_ptr().add(self.len as usize).read() })
125        }
126    }
127
128    /// Returns a mutable reference to the last element.
129    #[inline]
130    pub fn last_mut(&mut self) -> Option<&mut Item<'de>> {
131        if self.len == 0 {
132            None
133        } else {
134            // SAFETY: len > 0 is checked above, so ptr.add(len - 1) is within bounds.
135            Some(unsafe { &mut *self.ptr.as_ptr().add(self.len as usize - 1) })
136        }
137    }
138
139    /// Returns an iterator over references to the elements.
140    #[inline]
141    pub fn iter(&self) -> std::slice::Iter<'_, Item<'de>> {
142        self.as_slice().iter()
143    }
144
145    /// Returns the contents as a slice.
146    #[inline]
147    pub fn as_slice(&self) -> &[Item<'de>] {
148        if self.len == 0 {
149            &[]
150        } else {
151            // SAFETY: len > 0 is checked above. ptr points to arena-allocated
152            // memory with at least len initialized items.
153            unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len as usize) }
154        }
155    }
156
157    /// Returns the contents as a mutable slice.
158    #[inline]
159    pub fn as_mut_slice(&mut self) -> &mut [Item<'de>] {
160        if self.len == 0 {
161            &mut []
162        } else {
163            // SAFETY: same as as_slice() — ptr is valid for len initialized items.
164            unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len as usize) }
165        }
166    }
167
168    #[cold]
169    fn grow(&mut self, arena: &'de Arena) {
170        let new_cap = if self.cap == 0 {
171            MIN_CAP
172        } else {
173            self.cap.checked_mul(2).expect("capacity overflow")
174        };
175        self.grow_to(new_cap, arena);
176    }
177
178    fn grow_to(&mut self, new_cap: u32, arena: &'de Arena) {
179        // On 64-bit, u32 * size_of::<Item>() cannot overflow usize.
180        #[cfg(target_pointer_width = "32")]
181        let new_size = (new_cap as usize)
182            .checked_mul(size_of::<Item<'_>>())
183            .expect("capacity overflow");
184        #[cfg(not(target_pointer_width = "32"))]
185        let new_size = new_cap as usize * size_of::<Item<'_>>();
186        if self.cap > 0 {
187            let old_size = self.cap as usize * size_of::<Item<'_>>();
188            // Safety: ptr was returned by a prior arena alloc of old_size bytes.
189            self.ptr = unsafe { arena.realloc(self.ptr.cast(), old_size, new_size).cast() };
190        } else {
191            self.ptr = arena.alloc(new_size).cast();
192        }
193        self.cap = new_cap;
194    }
195}
196
197impl std::fmt::Debug for Array<'_> {
198    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199        f.debug_list().entries(self.as_slice()).finish()
200    }
201}
202
203impl<'a, 'de> IntoIterator for &'a Array<'de> {
204    type Item = &'a Item<'de>;
205    type IntoIter = std::slice::Iter<'a, Item<'de>>;
206
207    fn into_iter(self) -> Self::IntoIter {
208        self.as_slice().iter()
209    }
210}
211
212impl<'a, 'de> IntoIterator for &'a mut Array<'de> {
213    type Item = &'a mut Item<'de>;
214    type IntoIter = std::slice::IterMut<'a, Item<'de>>;
215
216    fn into_iter(self) -> Self::IntoIter {
217        self.as_mut_slice().iter_mut()
218    }
219}
220
221/// Consuming iterator over an [`Array`], yielding [`Item`]s.
222pub struct IntoIter<'de> {
223    arr: Array<'de>,
224    index: u32,
225}
226
227impl<'de> Iterator for IntoIter<'de> {
228    type Item = Item<'de>;
229
230    fn next(&mut self) -> Option<Self::Item> {
231        if self.index < self.arr.len {
232            // SAFETY: index < len is checked above, so the read is within
233            // initialized elements.
234            let val = unsafe { self.arr.ptr.as_ptr().add(self.index as usize).read() };
235            self.index += 1;
236            Some(val)
237        } else {
238            None
239        }
240    }
241
242    fn size_hint(&self) -> (usize, Option<usize>) {
243        let remaining = (self.arr.len - self.index) as usize;
244        (remaining, Some(remaining))
245    }
246}
247
248impl<'de> ExactSizeIterator for IntoIter<'de> {}
249
250impl<'de> IntoIterator for Array<'de> {
251    type Item = Item<'de>;
252    type IntoIter = IntoIter<'de>;
253
254    fn into_iter(self) -> Self::IntoIter {
255        IntoIter {
256            arr: self,
257            index: 0,
258        }
259    }
260}
261
262impl<'de> std::ops::Index<usize> for Array<'de> {
263    type Output = MaybeItem<'de>;
264
265    #[inline]
266    fn index(&self, index: usize) -> &Self::Output {
267        if let Some(item) = self.get(index) {
268            return MaybeItem::from_ref(item);
269        }
270        &crate::value::NONE
271    }
272}