bump_scope/owned_slice/
into_iter.rs

1use core::{
2    fmt::Debug,
3    iter::FusedIterator,
4    marker::PhantomData,
5    mem::{self, ManuallyDrop},
6    ops::Range,
7    ptr::NonNull,
8    slice,
9};
10
11use crate::{BumpBox, SizedTypeProperties, polyfill::non_null};
12
13use super::TakeOwnedSlice;
14
15/// An iterator that moves out of an owned slice.
16///
17/// This `struct` is created by the `into_iter` method on
18/// [`BumpBox`](BumpBox::into_iter),
19/// [`FixedBumpVec`](crate::FixedBumpVec::into_iter),
20/// [`MutBumpVec`](crate::MutBumpVec::into_iter) and
21/// [`MutBumpVecRev`](crate::MutBumpVecRev::into_iter)
22/// (provided by the [`IntoIterator`] trait).
23pub struct IntoIter<'a, T> {
24    ptr: NonNull<T>,
25    end: NonNull<T>, // if T is a ZST this is ptr + len
26
27    /// First field marks the lifetime.
28    /// Second field marks ownership over T. (<https://doc.rust-lang.org/nomicon/phantom-data.html#generic-parameters-and-drop-checking>)
29    marker: PhantomData<(&'a (), T)>,
30}
31
32unsafe impl<T: Send> Send for IntoIter<'_, T> {}
33unsafe impl<T: Sync> Sync for IntoIter<'_, T> {}
34
35impl<T: Debug> Debug for IntoIter<'_, T> {
36    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
38    }
39}
40
41impl<T> Default for IntoIter<'_, T> {
42    fn default() -> Self {
43        Self::EMPTY
44    }
45}
46
47impl<'a, T> IntoIter<'a, T> {
48    /// Iterator that yields nothing.
49    pub const EMPTY: Self = IntoIter {
50        ptr: NonNull::dangling(),
51        end: NonNull::dangling(),
52        marker: PhantomData,
53    };
54
55    #[inline(always)]
56    pub(crate) unsafe fn new(slice: NonNull<[T]>) -> Self {
57        unsafe {
58            if T::IS_ZST {
59                Self::new_zst(slice.len())
60            } else {
61                let start = slice.cast::<T>();
62                let end = start.add(slice.len());
63                Self::new_range(start..end)
64            }
65        }
66    }
67
68    #[inline(always)]
69    pub(crate) unsafe fn new_ranged(ptr: NonNull<[T]>, range: Range<usize>) -> Self {
70        unsafe {
71            if T::IS_ZST {
72                Self::new_zst(range.end - range.start)
73            } else {
74                let ptr = non_null::as_non_null_ptr(ptr);
75                let start = ptr.add(range.start);
76                let end = ptr.add(range.end);
77                Self::new_range(start..end)
78            }
79        }
80    }
81
82    #[inline(always)]
83    fn new_zst(len: usize) -> Self {
84        assert!(T::IS_ZST);
85
86        Self {
87            ptr: NonNull::dangling(),
88            end: unsafe { non_null::wrapping_byte_add(NonNull::dangling(), len) },
89            marker: PhantomData,
90        }
91    }
92
93    #[inline(always)]
94    unsafe fn new_range(range: Range<NonNull<T>>) -> Self {
95        assert!(!T::IS_ZST);
96
97        Self {
98            ptr: range.start,
99            end: range.end,
100            marker: PhantomData,
101        }
102    }
103
104    /// Returns the exact remaining length of the iterator.
105    #[must_use]
106    #[inline(always)]
107    pub fn len(&self) -> usize {
108        if T::IS_ZST {
109            self.end.addr().get().wrapping_sub(self.ptr.addr().get())
110        } else {
111            unsafe { non_null::offset_from_unsigned(self.end, self.ptr) }
112        }
113    }
114
115    /// Returns true if the iterator is empty.
116    #[must_use]
117    #[inline(always)]
118    pub fn is_empty(&self) -> bool {
119        self.ptr == self.end
120    }
121
122    /// Returns the remaining items of this iterator as a slice.
123    #[must_use]
124    #[inline(always)]
125    pub fn as_slice(&self) -> &[T] {
126        unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len()) }
127    }
128
129    /// Returns the remaining items of this iterator as a mutable slice.
130    #[must_use]
131    #[inline(always)]
132    pub fn as_mut_slice(&mut self) -> &mut [T] {
133        unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len()) }
134    }
135
136    /// Converts this iterator into a `BumpBox<[T]>`.
137    // NB: `IntoIter<T>` might come from a `BumpBox<[T]>` or `MutBumpVec<T>`.
138    // For `BumpBox` of course we can turn it back to a `BumpBox`.
139    // For `MutBumpVec`, `'a` is a mutable borrow of the bump allocator, so we can act as if we have a
140    // BumpBox allocated, for we can only mess with the bump allocator once that `BumpBox` is gone.
141    #[must_use]
142    #[inline(always)]
143    pub fn into_boxed_slice(self) -> BumpBox<'a, [T]> {
144        let this = ManuallyDrop::new(self);
145
146        unsafe {
147            let slice = NonNull::slice_from_raw_parts(this.ptr, this.len());
148            BumpBox::from_raw(slice)
149        }
150    }
151}
152
153impl<T> Iterator for IntoIter<'_, T> {
154    type Item = T;
155
156    #[inline(always)]
157    fn next(&mut self) -> Option<Self::Item> {
158        if self.ptr == self.end {
159            None
160        } else if T::IS_ZST {
161            // `ptr` has to stay aligned, so we decrement the length
162
163            // SAFETY: self.ptr < self.end; subtracting 1 won't overflow
164            self.end = unsafe { non_null::wrapping_byte_sub(self.end, 1) };
165
166            // SAFETY: its a ZST
167            Some(unsafe { mem::zeroed() })
168        } else {
169            unsafe {
170                let old = self.ptr;
171                self.ptr = self.ptr.add(1);
172                Some(old.as_ptr().read())
173            }
174        }
175    }
176
177    #[inline(always)]
178    fn size_hint(&self) -> (usize, Option<usize>) {
179        let exact = self.len();
180        (exact, Some(exact))
181    }
182
183    #[inline(always)]
184    fn count(self) -> usize {
185        self.len()
186    }
187}
188
189impl<T> DoubleEndedIterator for IntoIter<'_, T> {
190    #[inline(always)]
191    fn next_back(&mut self) -> Option<Self::Item> {
192        if self.end == self.ptr {
193            None
194        } else if T::IS_ZST {
195            // `ptr` has to stay aligned, so we decrement the length
196
197            // SAFETY: self.ptr < self.end; subtracting 1 won't overflow
198            self.end = unsafe { non_null::wrapping_byte_sub(self.end, 1) };
199
200            // SAFETY: its a ZST
201            Some(unsafe { mem::zeroed() })
202        } else {
203            unsafe {
204                self.end = self.end.sub(1);
205                Some(self.end.as_ptr().read())
206            }
207        }
208    }
209}
210
211impl<T> ExactSizeIterator for IntoIter<'_, T> {
212    #[inline(always)]
213    fn len(&self) -> usize {
214        IntoIter::len(self)
215    }
216}
217
218impl<T> FusedIterator for IntoIter<'_, T> {}
219
220impl<T> Drop for IntoIter<'_, T> {
221    #[inline]
222    fn drop(&mut self) {
223        unsafe {
224            NonNull::slice_from_raw_parts(self.ptr, self.len()).as_ptr().drop_in_place();
225        }
226    }
227}
228
229// this implementation is tested in `drain.rs`
230unsafe impl<T> TakeOwnedSlice for IntoIter<'_, T> {
231    type Item = T;
232
233    #[inline]
234    fn owned_slice_ref(&self) -> &[Self::Item] {
235        self.as_slice()
236    }
237
238    #[inline]
239    fn take_owned_slice(&mut self) {
240        // advance the iterator to the end without calling drop
241        self.ptr = self.end;
242    }
243}