use super::{RawVec, RawVecInner};
use crate::{
Allocation, SizedTypeProperties, is_aligned,
vec::{GrowthStrategy, TryReserveError, handle_error},
};
use core::{
alloc::Layout, cmp, fmt, iter::FusedIterator, marker::PhantomData, mem::ManuallyDrop,
panic::UnwindSafe, ptr, slice,
};
#[derive(Clone, Copy, Debug)]
pub struct VecBuilder {
max_capacity: usize,
capacity: usize,
growth_strategy: GrowthStrategy,
header_layout: Layout,
}
impl VecBuilder {
#[inline]
pub(super) const fn new(max_capacity: usize) -> Self {
VecBuilder {
max_capacity,
capacity: 0,
growth_strategy: GrowthStrategy::new(),
header_layout: Layout::new::<()>(),
}
}
#[inline]
pub const fn capacity(&mut self, capacity: usize) -> &mut Self {
self.capacity = capacity;
self
}
#[inline]
#[track_caller]
pub const fn growth_strategy(&mut self, growth_strategy: GrowthStrategy) -> &mut Self {
growth_strategy.validate();
self.growth_strategy = growth_strategy;
self
}
#[inline]
#[track_caller]
pub const fn header(&mut self, header_layout: Layout) -> &mut Self {
assert!(is_aligned(header_layout.size(), header_layout.align()));
self.header_layout = header_layout;
self
}
#[must_use]
#[track_caller]
pub unsafe fn build<T>(&self) -> RawVec<T> {
match unsafe { self.try_build() } {
Ok(vec) => vec,
Err(err) => handle_error(err),
}
}
pub unsafe fn try_build<T>(&self) -> Result<RawVec<T>, TryReserveError> {
Ok(RawVec {
inner: unsafe {
RawVecInner::new(
self.max_capacity,
self.capacity,
self.growth_strategy,
self.header_layout,
size_of::<T>(),
align_of::<T>(),
)
}?,
marker: PhantomData,
})
}
}
pub struct IntoIter<T> {
start: *const T,
end: *const T,
#[allow(dead_code)]
allocation: Allocation,
marker: PhantomData<T>,
}
unsafe impl<T: Send> Send for IntoIter<T> {}
unsafe impl<T: Sync> Sync for IntoIter<T> {}
impl<T: UnwindSafe> UnwindSafe for IntoIter<T> {}
impl<T> IntoIter<T> {
#[inline]
pub(super) fn new(vec: RawVec<T>) -> Self {
let mut vec = ManuallyDrop::new(vec);
let allocation = unsafe { ptr::read(&vec.inner.allocation) };
let start = vec.as_mut_ptr();
let len = cmp::min(vec.len_mut(), vec.capacity_mut());
let end = if T::IS_ZST {
start.cast::<u8>().wrapping_add(len).cast::<T>()
} else {
unsafe { start.add(len) }
};
IntoIter {
start,
end,
allocation,
marker: PhantomData,
}
}
#[inline]
#[must_use]
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.start, self.len()) }
}
#[inline]
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.start.cast_mut(), self.len()) }
}
}
impl<T> AsRef<[T]> for IntoIter<T> {
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> AsMut<[T]> for IntoIter<T> {
#[inline]
fn as_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
}
}
impl<T> Drop for IntoIter<T> {
fn drop(&mut self) {
let elements = ptr::slice_from_raw_parts_mut(self.start.cast_mut(), self.len());
unsafe { elements.drop_in_place() };
}
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.start == self.end {
return None;
}
let ptr = if T::IS_ZST {
self.end = self.end.cast::<u8>().wrapping_sub(1).cast::<T>();
self.start
} else {
let old = self.start;
self.start = unsafe { old.add(1) };
old
};
Some(unsafe { ptr.read() })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
#[inline]
fn count(self) -> usize {
self.len()
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.start == self.end {
return None;
}
let ptr = if T::IS_ZST {
self.end = self.end.cast::<u8>().wrapping_sub(1).cast::<T>();
self.start
} else {
self.end = unsafe { self.end.sub(1) };
self.end
};
Some(unsafe { ptr.read() })
}
}
impl<T> ExactSizeIterator for IntoIter<T> {
#[inline]
fn len(&self) -> usize {
if T::IS_ZST {
self.end.addr().wrapping_sub(self.start.addr())
} else {
unsafe { self.end.offset_from_unsigned(self.start) }
}
}
}
impl<T> FusedIterator for IntoIter<T> {}