bump_scope/mut_bump_vec/into_iter.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
use core::{
fmt::Debug,
iter::FusedIterator,
marker::PhantomData,
mem,
ptr::{self, NonNull},
slice,
};
use crate::{polyfill::nonnull, BumpAllocator, SizedTypeProperties};
/// An iterator that moves out of a vector.
///
/// This `struct` is created by the [`into_iter`] method on [`MutBumpVec`],
/// (provided by the [`IntoIterator`] trait).
///
/// [`into_iter`]: crate::MutBumpVec::into_iter
/// [`MutBumpVec`]: crate::MutBumpVec
pub struct IntoIter<T, A> {
ptr: NonNull<T>,
end: NonNull<T>, // if T is a ZST this is ptr + len
// Just holding on to it so it doesn't drop.
#[allow(dead_code)]
allocator: A,
/// First field marks the lifetime in the form of the allocator.
/// Second field marks ownership over T. (<https://doc.rust-lang.org/nomicon/phantom-data.html#generic-parameters-and-drop-checking>)
marker: PhantomData<(A, T)>,
}
unsafe impl<T: Send, A: Send> Send for IntoIter<T, A> {}
unsafe impl<T: Sync, A: Sync> Sync for IntoIter<T, A> {}
impl<T: Debug, A: BumpAllocator> Debug for IntoIter<T, A> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
}
}
impl<T, A> IntoIter<T, A> {
pub(crate) unsafe fn new(slice: NonNull<[T]>, allocator: A) -> Self {
if T::IS_ZST {
IntoIter {
ptr: NonNull::dangling(),
end: unsafe { nonnull::wrapping_byte_add(NonNull::dangling(), slice.len()) },
allocator,
marker: PhantomData,
}
} else {
let start = nonnull::as_non_null_ptr(slice);
let end = nonnull::add(start, slice.len());
IntoIter {
ptr: start,
end,
allocator,
marker: PhantomData,
}
}
}
/// Returns the exact remaining length of the iterator.
#[must_use]
#[inline(always)]
pub fn len(&self) -> usize {
#![allow(clippy::cast_sign_loss)]
if T::IS_ZST {
nonnull::addr(self.end).get().wrapping_sub(nonnull::addr(self.ptr).get())
} else {
unsafe { nonnull::sub_ptr(self.end, self.ptr) }
}
}
/// Returns true if the iterator is empty.
#[must_use]
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.ptr == self.end
}
/// Returns the remaining items of this iterator as a slice.
///
/// # Examples
///
/// ```
/// # use bump_scope::{ Bump, mut_bump_vec };
/// # let mut bump: Bump = Bump::new();
/// let vec = mut_bump_vec![in &mut bump; 1, 2, 3];
/// let mut into_iter = vec.into_iter();
/// assert_eq!(into_iter.as_slice(), &[1, 2, 3]);
/// assert_eq!(into_iter.next(), Some(1));
/// assert_eq!(into_iter.as_slice(), &[2, 3]);
/// assert_eq!(into_iter.next_back(), Some(3));
/// assert_eq!(into_iter.as_slice(), &[2]);
/// ```
#[must_use]
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len()) }
}
/// Returns the remaining items of this iterator as a mutable slice.
///
/// # Examples
///
/// ```
/// # use bump_scope::{ Bump, mut_bump_vec };
/// # let mut bump: Bump = Bump::new();
/// let vec = mut_bump_vec![in &mut bump; 'a', 'b', 'c'];
/// let mut into_iter = vec.into_iter();
/// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
/// into_iter.as_mut_slice()[2] = 'z';
/// assert_eq!(into_iter.next().unwrap(), 'a');
/// assert_eq!(into_iter.next().unwrap(), 'b');
/// assert_eq!(into_iter.next().unwrap(), 'z');
/// ```
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { &mut *self.as_raw_mut_slice() }
}
fn as_raw_mut_slice(&mut self) -> *mut [T] {
ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), self.len())
}
}
impl<T, A> AsRef<[T]> for IntoIter<T, A> {
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T, A> Iterator for IntoIter<T, A> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.ptr == self.end {
None
} else if T::IS_ZST {
// `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by
// reducing the `end`.
self.end = unsafe { nonnull::wrapping_byte_sub(self.end, 1) };
// Make up a value of this ZST.
Some(unsafe { mem::zeroed() })
} else {
let old = self.ptr;
self.ptr = unsafe { nonnull::add(self.ptr, 1) };
Some(unsafe { old.as_ptr().read() })
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = self.len();
(exact, Some(exact))
}
#[inline]
fn count(self) -> usize {
self.len()
}
}
impl<T, A> DoubleEndedIterator for IntoIter<T, A> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.end == self.ptr {
None
} else if T::IS_ZST {
// See above for why 'ptr.offset' isn't used
self.end = unsafe { nonnull::wrapping_byte_sub(self.end, 1) };
// Make up a value of this ZST.
Some(unsafe { mem::zeroed() })
} else {
self.end = unsafe { nonnull::sub(self.end, 1) };
Some(unsafe { self.end.as_ptr().read() })
}
}
}
impl<T, A> ExactSizeIterator for IntoIter<T, A> {}
impl<T, A> FusedIterator for IntoIter<T, A> {}
#[cfg(feature = "nightly-trusted-len")]
unsafe impl<T, A> core::iter::TrustedLen for IntoIter<T, A> {}
impl<T, A> Drop for IntoIter<T, A> {
#[inline]
fn drop(&mut self) {
unsafe {
nonnull::slice_from_raw_parts(self.ptr, self.len()).as_ptr().drop_in_place();
}
}
}