Skip to main content

stx/inline_array/
mod.rs

1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3use core::{
4    borrow::Borrow,
5    fmt,
6    hash::{Hash, Hasher},
7    mem::MaybeUninit,
8    ops::{Deref, DerefMut},
9    slice,
10};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct CapacityError;
14
15pub struct InlineArray<T, const N: usize> {
16    buf: [MaybeUninit<T>; N],
17    len: usize,
18}
19
20impl<T, const N: usize> InlineArray<T, N> {
21    #[inline]
22    pub const fn new() -> Self {
23        Self {
24            buf: [const { MaybeUninit::uninit() }; N],
25            len: 0,
26        }
27    }
28
29    #[inline]
30    pub const fn capacity(&self) -> usize {
31        N
32    }
33
34    #[inline]
35    pub const fn len(&self) -> usize {
36        self.len
37    }
38
39    #[inline]
40    pub const fn is_empty(&self) -> bool {
41        self.len == 0
42    }
43
44    #[inline]
45    pub const fn is_full(&self) -> bool {
46        self.len == N
47    }
48
49    #[inline]
50    pub fn as_slice(&self) -> &[T] {
51        // SAFETY: only the first `len` elements are initialized.
52        unsafe { slice::from_raw_parts(self.buf.as_ptr().cast::<T>(), self.len) }
53    }
54
55    #[inline]
56    pub fn as_mut_slice(&mut self) -> &mut [T] {
57        // SAFETY: only the first `len` elements are initialized.
58        unsafe { slice::from_raw_parts_mut(self.buf.as_mut_ptr().cast::<T>(), self.len) }
59    }
60
61    #[inline]
62    pub fn push(&mut self, value: T) -> Result<(), T> {
63        if self.len == N {
64            return Err(value);
65        }
66
67        self.buf[self.len].write(value);
68        self.len += 1;
69        Ok(())
70    }
71
72    #[inline]
73    pub fn pop(&mut self) -> Option<T> {
74        if self.len == 0 {
75            return None;
76        }
77
78        self.len -= 1;
79        // SAFETY: element at `len` was initialized and is now being moved out exactly once.
80        Some(unsafe { self.buf[self.len].assume_init_read() })
81    }
82
83    #[inline]
84    pub fn clear(&mut self) {
85        self.truncate(0);
86    }
87
88    #[inline]
89    pub fn truncate(&mut self, new_len: usize) {
90        let new_len = new_len.min(self.len);
91        while self.len > new_len {
92            self.len -= 1;
93            // SAFETY: indices below old `len` and >= new `len` were initialized.
94            unsafe { self.buf[self.len].assume_init_drop() };
95        }
96    }
97
98    #[inline]
99    pub fn try_extend<I>(&mut self, iter: I) -> Result<(), CapacityError>
100    where
101        I: IntoIterator<Item = T>,
102    {
103        for item in iter {
104            if self.push(item).is_err() {
105                return Err(CapacityError);
106            }
107        }
108
109        Ok(())
110    }
111
112    #[inline]
113    pub fn try_from_iter<I>(iter: I) -> Result<Self, CapacityError>
114    where
115        I: IntoIterator<Item = T>,
116    {
117        let mut out = Self::new();
118        out.try_extend(iter)?;
119        Ok(out)
120    }
121}
122
123impl<T, const N: usize> Default for InlineArray<T, N> {
124    #[inline]
125    fn default() -> Self {
126        Self::new()
127    }
128}
129
130impl<T, const N: usize> Drop for InlineArray<T, N> {
131    fn drop(&mut self) {
132        self.clear();
133    }
134}
135
136impl<T: Clone, const N: usize> Clone for InlineArray<T, N> {
137    fn clone(&self) -> Self {
138        let mut out = Self::new();
139        for item in self.as_slice() {
140            assert!(
141                out.push(item.clone()).is_ok(),
142                "stx::InlineArray clone capacity exceeded"
143            );
144        }
145        out
146    }
147}
148
149impl<T: fmt::Debug, const N: usize> fmt::Debug for InlineArray<T, N> {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        f.debug_list().entries(self.as_slice()).finish()
152    }
153}
154
155impl<T: PartialEq, const N: usize> PartialEq for InlineArray<T, N> {
156    fn eq(&self, other: &Self) -> bool {
157        self.as_slice() == other.as_slice()
158    }
159}
160
161impl<T: Eq, const N: usize> Eq for InlineArray<T, N> {}
162
163impl<T: PartialOrd, const N: usize> PartialOrd for InlineArray<T, N> {
164    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
165        self.as_slice().partial_cmp(other.as_slice())
166    }
167}
168
169impl<T: Ord, const N: usize> Ord for InlineArray<T, N> {
170    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
171        self.as_slice().cmp(other.as_slice())
172    }
173}
174
175impl<T: Hash, const N: usize> Hash for InlineArray<T, N> {
176    fn hash<H: Hasher>(&self, state: &mut H) {
177        self.as_slice().hash(state);
178    }
179}
180
181impl<T, const N: usize> Borrow<[T]> for InlineArray<T, N> {
182    fn borrow(&self) -> &[T] {
183        self.as_slice()
184    }
185}
186
187impl<T, const N: usize> AsRef<[T]> for InlineArray<T, N> {
188    fn as_ref(&self) -> &[T] {
189        self.as_slice()
190    }
191}
192
193impl<T, const N: usize> AsMut<[T]> for InlineArray<T, N> {
194    fn as_mut(&mut self) -> &mut [T] {
195        self.as_mut_slice()
196    }
197}
198
199impl<T, const N: usize> Deref for InlineArray<T, N> {
200    type Target = [T];
201
202    fn deref(&self) -> &Self::Target {
203        self.as_slice()
204    }
205}
206
207impl<T, const N: usize> DerefMut for InlineArray<T, N> {
208    fn deref_mut(&mut self) -> &mut Self::Target {
209        self.as_mut_slice()
210    }
211}
212
213impl<'a, T, const N: usize> IntoIterator for &'a InlineArray<T, N> {
214    type Item = &'a T;
215    type IntoIter = slice::Iter<'a, T>;
216
217    fn into_iter(self) -> Self::IntoIter {
218        self.as_slice().iter()
219    }
220}
221
222impl<'a, T, const N: usize> IntoIterator for &'a mut InlineArray<T, N> {
223    type Item = &'a mut T;
224    type IntoIter = slice::IterMut<'a, T>;
225
226    fn into_iter(self) -> Self::IntoIter {
227        self.as_mut_slice().iter_mut()
228    }
229}
230
231impl<T, const N: usize> Extend<T> for InlineArray<T, N> {
232    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
233        for item in iter {
234            assert!(
235                self.push(item).is_ok(),
236                "stx::InlineArray capacity exceeded"
237            );
238        }
239    }
240}
241
242impl<T, const N: usize> FromIterator<T> for InlineArray<T, N> {
243    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
244        let mut out = Self::new();
245        out.extend(iter);
246        out
247    }
248}
249
250impl<T: Clone, const N: usize> TryFrom<&[T]> for InlineArray<T, N> {
251    type Error = CapacityError;
252
253    fn try_from(slice: &[T]) -> Result<Self, Self::Error> {
254        Self::try_from_iter(slice.iter().cloned())
255    }
256}
257
258#[cfg(feature = "alloc")]
259impl<T, const N: usize> TryFrom<Vec<T>> for InlineArray<T, N> {
260    type Error = CapacityError;
261
262    fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
263        Self::try_from_iter(value)
264    }
265}
266
267#[cfg(test)]
268mod tests;