Skip to main content

toml_spanner/
array.rs

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