Skip to main content

tl/inline/
vec.rs

1use core::fmt::{Debug, Formatter};
2use core::mem::MaybeUninit;
3use core::ops::Index;
4use core::ptr;
5
6use crate::ParseError;
7
8/// A wrapper around a `Vec<T>` that lives on the stack if it is small enough.
9#[derive(Debug, Clone)]
10pub struct InlineVec<T, const N: usize>(InlineVecInner<T, N>);
11
12impl<T, const N: usize> InlineVec<T, N> {
13    /// Creates a new InlineVec
14    #[inline]
15    pub(crate) fn new() -> Self {
16        Self(InlineVecInner::new())
17    }
18
19    /// Returns the number of elements in the vector
20    #[inline]
21    pub fn len(&self) -> usize {
22        self.0.len()
23    }
24
25    /// Returns true if the vector contains no elements
26    #[inline]
27    pub fn is_empty(&self) -> bool {
28        self.len() == 0
29    }
30
31    /// Checks whether this vector is allocated on the heap
32    #[inline]
33    pub fn is_heap_allocated(&self) -> bool {
34        self.0.is_heap_allocated()
35    }
36
37    /// If `self` is inlined, this returns the underlying raw parts that make up this `InlineVec`.
38    ///
39    /// Only the first `.1` elements are initialized.
40    ///
41    /// ```compile_fail
42    /// fn mutate<T, const N: usize>(values: &mut tl::inline::vec::InlineVec<T, N>) {
43    ///     let _ = values.inline_parts_mut(); // an unsafe call is required
44    /// }
45    /// ```
46    ///
47    /// # Safety
48    /// Before the borrow ends, the initialized prefix must contain valid, uniquely
49    /// owned values of the element type. Replacing a slot with uninitialized data,
50    /// duplicating an owner or dropping it without replacing it violates this contract.
51    /// Prefer `get_mut` or typed mutable access instead.
52    #[inline]
53    pub unsafe fn inline_parts_mut(&mut self) -> Option<(&mut [MaybeUninit<T>; N], usize)> {
54        self.0.inline_parts_mut()
55    }
56
57    /// Copies `self` into a new `Vec<T>`
58    #[inline]
59    #[cfg(feature = "std")]
60    pub fn to_vec(&self) -> Vec<T>
61    where
62        T: Clone,
63    {
64        self.0.to_vec()
65    }
66
67    /// Inserts a new element into the vector
68    #[inline]
69    pub fn push(&mut self, value: T) -> Result<(), ParseError> {
70        self.0.push(value)
71    }
72
73    /// Returns a reference to the value at the given index
74    #[inline]
75    pub fn get(&self, index: usize) -> Option<&T> {
76        self.0.get(index)
77    }
78
79    /// Returns a mutable reference to the value at the given index
80    #[inline]
81    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
82        self.0.get_mut(index)
83    }
84
85    /// Returns the last element in the vector.
86    #[inline]
87    pub fn last(&self) -> Option<&T> {
88        self.as_slice().last()
89    }
90
91    /// Removes the last element and returns it, or `None` if it is empty.
92    #[inline]
93    pub fn pop(&mut self) -> Option<T> {
94        if self.is_empty() {
95            None
96        } else {
97            Some(self.remove(self.len() - 1))
98        }
99    }
100
101    /// Removes an element at a given index
102    ///
103    /// # Panics
104    /// Just like `Vec::remove`, this method will panic if the index is out of bounds.
105    #[inline]
106    pub fn remove(&mut self, index: usize) -> T {
107        self.0.remove(index)
108    }
109
110    /// Returns an iterator over the elements of this vector
111    #[inline]
112    pub fn iter(&self) -> InlineVecIter<'_, T, N> {
113        self.0.iter()
114    }
115
116    /// Returns a slice to the contents of this vector
117    #[inline]
118    pub fn as_slice(&self) -> &[T] {
119        self.0.as_slice()
120    }
121
122    /// Returns a mutable slice to the contents of this vector.
123    #[inline]
124    pub fn as_mut_slice(&mut self) -> &mut [T] {
125        self.0.as_mut_slice()
126    }
127}
128
129enum InlineVecInner<T, const N: usize> {
130    Inline {
131        len: usize,
132        data: [MaybeUninit<T>; N],
133    },
134    #[cfg(feature = "std")]
135    Heap(Vec<T>),
136}
137
138impl<T, const N: usize> Debug for InlineVecInner<T, N>
139where
140    T: Debug,
141{
142    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
143        write!(f, "InlineVec<{} items>", self.len())
144    }
145}
146
147impl<T, const N: usize> Clone for InlineVecInner<T, N>
148where
149    T: Clone,
150{
151    fn clone(&self) -> Self {
152        match self {
153            #[cfg(feature = "std")]
154            Self::Heap(m) => Self::Heap(m.clone()),
155            Self::Inline { len, data } => {
156                let mut cloned = Self::new();
157                let (initialized, target) = match &mut cloned {
158                    Self::Inline { len, data } => (len, data),
159                    #[cfg(feature = "std")]
160                    Self::Heap(_) => unreachable!("new storage is inline"),
161                };
162                for element in data.iter().take(*len) {
163                    // SAFETY: only the initialized prefix is read. The new owner
164                    // updates its prefix after each successful clone, so a panic
165                    // drops all previously cloned elements exactly once.
166                    let value = unsafe { element.assume_init_ref() }.clone();
167                    target[*initialized].write(value);
168                    *initialized += 1;
169                }
170                cloned
171            }
172        }
173    }
174}
175
176impl<T, const N: usize> InlineVecInner<T, N> {
177    #[inline]
178    pub(crate) fn new() -> Self {
179        Self::Inline {
180            len: 0,
181            data: super::uninit_array(),
182        }
183    }
184
185    pub fn as_slice(&self) -> &[T] {
186        match self {
187            Self::Inline { len, data } => unsafe {
188                core::slice::from_raw_parts(data.as_ptr() as *const T, *len)
189            },
190            #[cfg(feature = "std")]
191            Self::Heap(v) => v.as_slice(),
192        }
193    }
194
195    pub fn as_mut_slice(&mut self) -> &mut [T] {
196        match self {
197            Self::Inline { len, data } => unsafe {
198                core::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut T, *len)
199            },
200            #[cfg(feature = "std")]
201            Self::Heap(v) => v.as_mut_slice(),
202        }
203    }
204
205    #[inline]
206    pub fn inline_parts_mut(&mut self) -> Option<(&mut [MaybeUninit<T>; N], usize)> {
207        match self {
208            #[cfg(feature = "std")]
209            Self::Heap(_) => None,
210            Self::Inline { len, data } => Some((data, *len)),
211        }
212    }
213
214    #[cfg(feature = "std")]
215    pub fn to_vec(&self) -> Vec<T>
216    where
217        T: Clone,
218    {
219        match &self {
220            InlineVecInner::Heap(m) => m.to_vec(),
221            InlineVecInner::Inline { len, data } => {
222                let mut new_data = Vec::with_capacity(*len);
223
224                let iter = data.iter().take(*len);
225
226                for element in iter {
227                    new_data.push(unsafe { T::clone(&*element.as_ptr()) });
228                }
229
230                new_data
231            }
232        }
233    }
234
235    #[inline]
236    pub fn iter(&self) -> InlineVecIter<'_, T, N> {
237        InlineVecIter { idx: 0, vec: self }
238    }
239
240    #[inline]
241    pub fn len(&self) -> usize {
242        match self {
243            Self::Inline { len, .. } => *len,
244            #[cfg(feature = "std")]
245            Self::Heap(vec) => vec.len(),
246        }
247    }
248
249    pub fn get(&self, idx: usize) -> Option<&T> {
250        match self {
251            Self::Inline { data, len } => {
252                if idx < *len {
253                    Some(unsafe { &*data.get_unchecked(idx).as_ptr() })
254                } else {
255                    None
256                }
257            }
258            #[cfg(feature = "std")]
259            Self::Heap(vec) => vec.get(idx),
260        }
261    }
262
263    pub fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
264        match self {
265            Self::Inline { data, len } => {
266                if idx < *len {
267                    Some(unsafe { &mut *data.get_unchecked_mut(idx).as_mut_ptr() })
268                } else {
269                    None
270                }
271            }
272            #[cfg(feature = "std")]
273            Self::Heap(vec) => vec.get_mut(idx),
274        }
275    }
276
277    pub fn remove(&mut self, idx: usize) -> T {
278        match self {
279            Self::Inline { data, len } => {
280                assert!(idx < *len);
281
282                // at this point we know idx is in bounds
283                // carefully replace the value with MaybeUninit::uninit(), so it can be returned
284                let element = unsafe {
285                    core::mem::replace(data.get_unchecked_mut(idx), MaybeUninit::uninit())
286                };
287
288                for i in idx + 1..*len {
289                    // TODO(y21): data.swap_unchecked() worth it?
290                    data.swap(i, i - 1);
291                }
292
293                *len -= 1;
294
295                // we've made sure that idx is in bounds and if idx is in bounds, then `T` must be initialized
296                unsafe { element.assume_init() }
297            }
298            #[cfg(feature = "std")]
299            Self::Heap(h) => h.remove(idx),
300        }
301    }
302
303    pub fn push(&mut self, value: T) -> Result<(), ParseError> {
304        let (array, len) = match self {
305            Self::Inline { data, len } => (data, len),
306            #[cfg(feature = "std")]
307            Self::Heap(vec) => {
308                vec.push(value);
309                return Ok(());
310            }
311        };
312
313        if *len >= N {
314            #[cfg(not(feature = "std"))]
315            {
316                return Err(ParseError::ChildCapacityExceeded);
317            }
318
319            #[cfg(feature = "std")]
320            {
321                let mut vec = Vec::with_capacity(*len + 1);
322
323                // move old elements to heap
324                for element in array.iter_mut().take(*len) {
325                    let element = core::mem::replace(element, MaybeUninit::uninit());
326
327                    vec.push(unsafe { element.assume_init() });
328                }
329
330                // push the new element
331                vec.push(value);
332                let new_heap = InlineVecInner::Heap(vec);
333
334                // do not call the destructor!
335                unsafe { ptr::write(self, new_heap) };
336            }
337        } else {
338            array[*len].write(value);
339            *len += 1;
340        }
341
342        Ok(())
343    }
344
345    #[inline]
346    pub fn is_heap_allocated(&self) -> bool {
347        #[cfg(feature = "std")]
348        {
349            matches!(self, Self::Heap(_))
350        }
351        #[cfg(not(feature = "std"))]
352        {
353            false
354        }
355    }
356}
357
358impl<T, const N: usize> Index<usize> for InlineVec<T, N> {
359    type Output = T;
360
361    fn index(&self, idx: usize) -> &Self::Output {
362        self.0.get(idx).expect("index out of bounds")
363    }
364}
365
366/// An iterator over the elements stored in an [`InlineVec`]
367pub struct InlineVecIter<'a, T, const N: usize> {
368    vec: &'a InlineVecInner<T, N>,
369    idx: usize,
370}
371
372impl<'a, T, const N: usize> Iterator for InlineVecIter<'a, T, N> {
373    type Item = &'a T;
374
375    fn next(&mut self) -> Option<Self::Item> {
376        self.idx += 1;
377        self.vec.get(self.idx - 1)
378    }
379}
380
381impl<T, const N: usize> Drop for InlineVecInner<T, N> {
382    fn drop(&mut self) {
383        if let Some((data, len)) = self.inline_parts_mut() {
384            for element in data.iter_mut().take(len) {
385                unsafe { ptr::drop_in_place(element.as_mut_ptr()) };
386            }
387        }
388    }
389}
390
391#[cfg(all(test, feature = "std"))]
392mod tests {
393    #![allow(unused_must_use)]
394
395    use super::*;
396
397    #[test]
398    fn inlinevec_to_vec_stack() {
399        let mut x = InlineVec::<usize, 4>::new();
400
401        for i in 0..4 {
402            x.push(i * 2);
403        }
404
405        assert!(!x.is_heap_allocated());
406        assert_eq!(x.len(), 4);
407
408        let xx = x.to_vec();
409        assert_eq!(xx.as_slice(), &[0, 2, 4, 6]);
410
411        x.push(42);
412        assert!(x.is_heap_allocated());
413        assert_eq!(x.as_slice(), &[0, 2, 4, 6, 42]);
414        assert_eq!(x.get(4), Some(&42));
415
416        let xx = x.to_vec();
417        assert_eq!(xx.as_slice(), &[0, 2, 4, 6, 42]);
418    }
419
420    #[test]
421    fn inlinevec_to_vec_heap() {
422        let mut x = InlineVec::<String, 4>::new();
423
424        for i in 0..4u8 {
425            x.push(i.to_string());
426        }
427
428        assert!(!x.is_heap_allocated());
429        assert_eq!(x.len(), 4);
430
431        let xx = x.to_vec();
432        assert_eq!(xx.as_slice(), &["0", "1", "2", "3"]);
433
434        x.push("1337".into());
435        assert!(x.is_heap_allocated());
436        assert_eq!(x.as_slice(), &["0", "1", "2", "3", "1337"]);
437        assert_eq!(x.get(4).map(|x| &**x), Some("1337"));
438
439        let xx = x.to_vec();
440        assert_eq!(xx.as_slice(), &["0", "1", "2", "3", "1337"]);
441    }
442
443    #[test]
444    fn inlinevec_drop_stack() {
445        let mut x = InlineVec::<String, 4>::new();
446
447        for i in 0..3u8 {
448            x.push(i.to_string());
449        }
450
451        assert_eq!(x.as_slice(), &["0", "1", "2"]);
452        assert!(!x.is_heap_allocated());
453    }
454
455    #[test]
456    fn inlinehashmap_drop_heap() {
457        let mut x = InlineVec::<String, 4>::new();
458
459        for i in 0..8u8 {
460            x.push(i.to_string());
461        }
462
463        assert_eq!(x.as_slice(), &["0", "1", "2", "3", "4", "5", "6", "7"]);
464        assert!(x.is_heap_allocated());
465    }
466
467    #[test]
468    fn inlinevec_iter() {
469        let mut x = InlineVecInner::<usize, 2>::new();
470        x.push(13);
471        x.push(42);
472        x.push(17);
473        x.push(19);
474        let mut iter = x.iter();
475        assert_eq!(iter.next(), Some(&13));
476        assert_eq!(iter.next(), Some(&42));
477        assert_eq!(iter.next(), Some(&17));
478        assert_eq!(iter.next(), Some(&19));
479        assert_eq!(iter.next(), None);
480    }
481
482    #[test]
483    fn inlinevec_remove() {
484        let mut x = InlineVecInner::<usize, 4>::new();
485        x.push(789);
486        assert_eq!(x.len(), 1);
487        assert_eq!(x.get(0), Some(&789));
488        assert_eq!(x.remove(0), 789);
489        assert_eq!(x.len(), 0);
490
491        {
492            let mut xc = x.clone();
493            // out of bounds index must panic
494            assert!(std::panic::catch_unwind(move || xc.remove(0)).is_err());
495        }
496
497        for i in 0..4 {
498            x.push(i * 2);
499        }
500
501        assert!(!x.is_heap_allocated());
502        assert_eq!(x.as_slice(), &[0, 2, 4, 6]);
503
504        assert_eq!(x.remove(2), 4);
505        assert_eq!(x.as_slice(), &[0, 2, 6]);
506
507        assert_eq!(x.remove(2), 6);
508        assert_eq!(x.as_slice(), &[0, 2]);
509
510        assert_eq!(x.remove(1), 2);
511        assert_eq!(x.as_slice(), &[0]);
512
513        assert_eq!(x.remove(0), 0);
514        assert_eq!(x.as_slice(), &[]);
515        assert!(!x.is_heap_allocated());
516
517        // trigger heap allocation
518        for i in 0..8 {
519            x.push(i * 2);
520        }
521        assert!(x.is_heap_allocated());
522        assert_eq!(x.as_slice(), &[0, 2, 4, 6, 8, 10, 12, 14]);
523
524        assert_eq!(x.remove(7), 14);
525        assert_eq!(x.remove(0), 0);
526    }
527
528    #[test]
529    fn inlinevec_remove_heap() {
530        let mut x = InlineVecInner::<String, 4>::new();
531        x.push("test".into());
532        assert_eq!(x.len(), 1);
533        assert_eq!(x.remove(0), "test");
534        assert_eq!(x.len(), 0);
535    }
536
537    #[test]
538    fn inlinevec() {
539        let mut x = InlineVecInner::<usize, 4>::new();
540        assert_eq!(x.len(), 0);
541        assert_eq!(x.get(0), None);
542        assert!(!x.is_heap_allocated());
543
544        x.push(1337);
545        assert_eq!(x.len(), 1);
546        assert_eq!(x.get(0), Some(&1337));
547        assert!(!x.is_heap_allocated());
548
549        for v in 0..3 {
550            x.push(v);
551        }
552
553        assert_eq!(x.len(), 4);
554
555        // this call should move the vector to the heap
556        x.push(42);
557        assert_eq!(x.len(), 5);
558        assert!(x.is_heap_allocated());
559
560        // check that the old vector is still valid
561        assert_eq!(x.get(0), Some(&1337));
562
563        for v in 0..500 {
564            x.push(v);
565        }
566
567        assert_eq!(x.len(), 505);
568        assert!(x.is_heap_allocated());
569
570        assert_eq!(x.get(1337), None);
571
572        *x.get_mut(0).unwrap() = 444;
573        assert_eq!(x.get(0), Some(&444));
574        assert_eq!(x.get_mut(99999 /* out of bounds */), None);
575    }
576
577    #[test]
578    fn inlinevec_as_slice() {
579        let mut x = InlineVecInner::<usize, 4>::new();
580        x.push(1337);
581        x.push(42);
582        x.push(17);
583        assert_eq!(x.as_slice(), &[1337, 42, 17]);
584        x.push(19);
585        x.push(34);
586        assert_eq!(x.as_slice(), &[1337, 42, 17, 19, 34]);
587    }
588}