Skip to main content

sharky_arrayvec/
iter.rs

1use core::fmt::Debug;
2use core::mem::ManuallyDrop;
3
4use crate::ArrayVec;
5
6impl<const C: usize, T> IntoIterator for ArrayVec<C, T> {
7    type IntoIter = ArrayVecIter<C, T>;
8    type Item = T;
9
10    #[inline]
11    fn into_iter(self) -> Self::IntoIter {
12        ArrayVecIter::new(self)
13    }
14}
15
16/// Iterate over elements of an [`ArrayVec`].
17///
18/// ```rust
19/// # use sharky_arrayvec::*;
20///
21/// let vec = ArrayVec::from_array([1, 2, 3]);
22/// let mut iter = ArrayVecIter::new(vec);
23///
24/// assert_eq!(iter.next(), Some(1));
25/// assert_eq!(iter.next(), Some(2));
26/// assert_eq!(iter.next(), Some(3));
27/// assert_eq!(iter.next(), None);
28/// ```
29#[must_use]
30pub struct ArrayVecIter<const C: usize, T> {
31    // NOTE: The vec can't be automatically dropped because the yielded elements would be
32    // double-dropped.
33    vec:   ManuallyDrop<ArrayVec<C, T>>,
34    index: usize,
35}
36
37impl<const C: usize, T> Drop for ArrayVecIter<C, T> {
38    #[inline]
39    fn drop(&mut self) {
40        let len = self.vec.len();
41
42        // SAFETY:
43        // - All elements up to self.vec.len are valid and initialized.
44        // - Only non-yielded elements are dropped to prevent double dropping
45        unsafe {
46            self.vec.array[self.index..len].assume_init_drop();
47        }
48    }
49}
50
51impl<const C: usize, T> ArrayVecIter<C, T> {
52    /// Create a new [`ArrayVec`].
53    ///
54    /// ```rust
55    /// # use sharky_arrayvec::*;
56    ///
57    /// let vec = ArrayVec::from_array([1, 2, 3]);
58    /// let mut iter = ArrayVecIter::new(vec);
59    ///
60    /// assert_eq!(iter.next(), Some(1));
61    /// assert_eq!(iter.next(), Some(2));
62    /// assert_eq!(iter.next(), Some(3));
63    /// assert_eq!(iter.next(), None);
64    /// ```
65    #[inline]
66    pub const fn new(vec: ArrayVec<C, T>) -> Self {
67        Self {
68            vec:   ManuallyDrop::new(vec),
69            index: 0,
70        }
71    }
72}
73
74impl<const C: usize, T> Iterator for ArrayVecIter<C, T> {
75    type Item = T;
76
77    #[inline]
78    fn next(&mut self) -> Option<Self::Item> {
79        if self.index < self.vec.len() {
80            // SAFETY:
81            //
82            // - The item is initialized because `self.index <= self.len()`
83            // - It's okay to duplicate the item because `self.vec` has already been moved
84            //   into the iterator; The only usable copy is what's returned.
85            // - The returned value will be dropped, so nothing is leaked.
86            let item = unsafe { self.vec.array[self.index].assume_init_read() };
87            // NOTE: the index is less than the length; therefore, it's impossible for it to
88            // be equal to usize::MAX, so checks would be redundant.
89            self.index = self.index.wrapping_add(1);
90            Some(item)
91        } else {
92            None
93        }
94    }
95}
96
97impl<const C: usize, T: Debug> Debug for ArrayVecIter<C, T> {
98    #[inline]
99    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100        f.debug_tuple("ArrayVecIter").field(&*self.vec).finish()
101    }
102}
103
104impl<const C: usize, T: Clone> Clone for ArrayVecIter<C, T> {
105    #[inline]
106    fn clone(&self) -> Self {
107        Self {
108            vec:   self.vec.clone(),
109            index: self.index,
110        }
111    }
112}
113
114#[cfg_attr(coverage_nightly, coverage(off))]
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn debug() {
121        let expected = "ArrayVecIter([2, 2])";
122        let iter = ArrayVec::from_array([2; 2]).into_iter();
123        let str = format!("{iter:?}");
124        assert_eq!(expected, str);
125    }
126
127    #[test]
128    fn iter_consuming() {
129        let vec = ArrayVec::from_array([1u8, 2, 3]);
130        let collected: Vec<_> = vec.into_iter().collect();
131        assert_eq!(collected, [1, 2, 3]);
132    }
133
134    #[test]
135    fn iter_drop_partial() {
136        // Non-Copy type; verifies no double-free under Miri
137        let vec = ArrayVec::from_array([String::from("a"), String::from("b"), String::from("c")]);
138        let mut iter = vec.into_iter();
139        assert_eq!(iter.next(), Some(String::from("a")));
140        drop(iter); // "b" and "c" must be dropped here, "a" already consumed
141    }
142
143    #[test]
144    fn iter_empty() {
145        let vec: ArrayVec<4, u8> = ArrayVec::new();
146        assert_eq!(vec.into_iter().next(), None);
147    }
148
149    #[test]
150    fn iter_clone_independent() {
151        let vec = ArrayVec::from_array([1u8, 2, 3]);
152        let mut iter = vec.into_iter();
153        iter.next();
154        let mut iter2 = iter.clone();
155        assert_eq!(iter.next(), Some(2));
156        assert_eq!(iter2.next(), Some(2));
157    }
158}