tiny_vec/
iter.rs

1//! Iterator implementation for TinyVec
2
3use core::iter::FusedIterator;
4use core::marker::PhantomData;
5use core::mem::{self, ManuallyDrop, MaybeUninit};
6use core::num::NonZero;
7use core::ptr;
8
9use alloc::slice;
10
11use crate::raw::RawVec;
12use crate::TinyVec;
13
14enum Kind<T, const N: usize> {
15    Stack([MaybeUninit<T>; N]),
16    Heap(RawVec<T>),
17}
18
19impl<T, const N: usize> Kind<T, N> {
20    const fn ptr(&self) -> *const T {
21        match self {
22            Kind::Stack(s) => s.as_ptr().cast(),
23            Kind::Heap(rv) => rv.ptr.as_ptr()
24        }
25    }
26
27    const fn ptr_mut(&mut self) -> *mut T {
28        match self {
29            Kind::Stack(s) => s.as_mut_ptr().cast(),
30            Kind::Heap(rv) => rv.ptr.as_ptr()
31        }
32    }
33}
34
35/// Iterator over the elements of a [TinyVec]
36///
37/// This struct is returned from the [TinyVec::into_iter] function
38pub struct TinyVecIter<T, const N: usize> {
39    start: usize,
40    len: usize,
41    buf: Kind<T, N>,
42    _marker: PhantomData<TinyVec<T, N>>,
43}
44
45impl<T, const N: usize> TinyVecIter<T, N> {
46    /// Casts the remaining portion of this iterator as a slice of T
47    pub const fn as_slice(&self) -> &[T] {
48        unsafe {
49            let ptr = self.buf.ptr().add(self.start);
50            slice::from_raw_parts(ptr, self.len)
51        }
52    }
53
54    /// Casts the remaining portion of this iterator as a mutable slice of T
55    pub const fn as_mut_slice(&mut self) -> &mut [T] {
56        unsafe {
57            let ptr = self.buf.ptr_mut().add(self.start);
58            slice::from_raw_parts_mut(ptr, self.len)
59        }
60    }
61}
62
63impl<T, const N: usize> Drop for TinyVecIter<T, N> {
64    fn drop(&mut self) {
65        let raw = match self.buf {
66            Kind::Stack(_) => None,
67            Kind::Heap(raw) => Some(raw),
68        };
69
70        if mem::needs_drop::<T>() {
71            for e in self {
72                mem::drop(e);
73            }
74        }
75
76        if let Some(mut raw) = raw {
77            unsafe { raw.destroy(); }
78        }
79    }
80}
81
82impl<T, const N: usize> TinyVecIter<T, N> {
83
84    #[inline(always)]
85    fn _advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
86        if n > self.len {
87            /* SAFTEY: n is strictly greater that self.len, so
88             * (n - self.len) will always be greater than zero */
89            return Err(unsafe { NonZero::new_unchecked(n - self.len) })
90        }
91        self.len -= n;
92        self.start += n;
93        Ok(())
94    }
95
96    #[inline(always)]
97    fn _advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
98        if n > self.len {
99            /* SAFTEY: n is strictly greater that self.len, so
100             * (n - self.len) will always be greater than zero */
101            return Err(unsafe { NonZero::new_unchecked(n - self.len) })
102        }
103        self.len -= n;
104        Ok(())
105    }
106
107    #[cfg(not(feature = "use-nightly-features"))]
108    #[inline(always)]
109    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
110        self._advance_back_by(n)
111    }
112
113    #[cfg(not(feature = "use-nightly-features"))]
114    #[inline(always)]
115    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
116        self._advance_by(n)
117    }
118}
119
120impl<T, const N: usize> Iterator for TinyVecIter<T, N> {
121    type Item = T;
122
123    fn next(&mut self) -> Option<Self::Item> {
124        if self.len == 0 {
125            None
126        } else {
127            let e = unsafe {
128                self.buf
129                    .ptr_mut()
130                    .add(self.start)
131                    .read()
132            };
133            self.start += 1;
134            self.len -= 1;
135            Some(e)
136        }
137    }
138
139    fn size_hint(&self) -> (usize, Option<usize>) {
140        (self.len, Some(self.len))
141    }
142
143    fn nth(&mut self, n: usize) -> Option<Self::Item> {
144        self.advance_by(n).ok()?;
145        self.next()
146    }
147
148    #[cfg(feature = "use-nightly-features")]
149    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
150        self._advance_by(n)
151    }
152}
153
154impl<T, const N: usize> DoubleEndedIterator for TinyVecIter<T, N> {
155    fn next_back(&mut self) -> Option<Self::Item> {
156        if self.len == 0 {
157            None
158        } else {
159            self.len -= 1;
160            let e = unsafe {
161                self.buf
162                    .ptr_mut()
163                    .add(self.start + self.len)
164                    .read()
165            };
166            Some(e)
167        }
168    }
169
170    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
171        self.advance_back_by(n).ok()?;
172        self.next_back()
173    }
174
175    #[cfg(feature = "use-nightly-features")]
176    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
177        self._advance_back_by(n)
178    }
179}
180
181impl<T, const N: usize> ExactSizeIterator for TinyVecIter<T, N> { }
182
183impl<T, const N: usize> FusedIterator for TinyVecIter<T, N> { }
184
185impl<T, const N: usize> IntoIterator for TinyVec<T, N> {
186    type Item = T;
187
188    type IntoIter = TinyVecIter<T, N>;
189
190    fn into_iter(self) -> Self::IntoIter {
191        let vec = ManuallyDrop::new(self);
192
193        let is_stack = vec.lives_on_stack();
194        let len = vec.len();
195
196        let buf = unsafe {
197            let inner = ptr::read( &vec.inner );
198            if is_stack {
199                Kind::Stack(ManuallyDrop::into_inner( inner.stack ))
200            } else {
201                Kind::Heap(inner.raw)
202            }
203        };
204
205        TinyVecIter { start: 0, len, buf, _marker: PhantomData }
206    }
207}
208
209#[cfg(test)]
210#[allow(clippy::iter_nth_zero)]
211mod test {
212    use crate::TinyVec;
213
214    #[test]
215    fn nth() {
216        let mut it = TinyVec::from([1, 2, 3, 4, 5, 6, 7]).into_iter();
217
218        assert_eq!(Some(3), it.nth(2));
219        assert_eq!(Some(4), it.nth(0));
220
221        assert_eq!(Some(6), it.nth_back(1));
222        assert_eq!(Some(5), it.nth_back(0));
223
224        assert_eq!(it.len(), 0);
225    }
226}