use {
crate::{SlimVec, utils::conform_range},
::core::{
convert::AsRef,
fmt,
iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator},
mem,
ops::{Range, RangeBounds},
panic::{RefUnwindSafe, UnwindSafe},
ptr, slice,
},
};
pub struct Drain<'v, T>
where
T: 'v,
{
pub(crate) slimvec: &'v mut SlimVec<T>,
pub(crate) tail: Range<usize>,
pub(crate) yield_range: Range<usize>,
}
impl<T> Drain<'_, T> {
#[inline]
pub fn as_slice(&self) -> &[T] {
if self.slimvec.raw.is_capacity_gt_zero() {
unsafe {
let ptr = self
.slimvec
.raw
.element_ptr(self.yield_range.start)
.as_ptr();
slice::from_raw_parts(ptr, self.len())
}
} else {
&[]
}
}
}
impl<T> Iterator for Drain<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
if self.len() == 0 {
return None;
}
self.yield_range.start += 1;
let element = unsafe { self.slimvec.raw.read(self.yield_range.start - 1) };
Some(element)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.yield_range.len();
(len, Some(len))
}
}
impl<T> DoubleEndedIterator for Drain<'_, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.len() == 0 {
return None;
}
self.yield_range.end -= 1;
let element = unsafe { self.slimvec.raw.read(self.yield_range.end) };
Some(element)
}
}
impl<T> ExactSizeIterator for Drain<'_, T> {}
impl<T> FusedIterator for Drain<'_, T> {}
impl<T> fmt::Debug for Drain<'_, T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.as_slice()).finish()
}
}
impl<T> AsRef<[T]> for Drain<'_, T> {
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> Drain<'_, T> {
#[inline]
pub(crate) fn new(
slimvec: &mut SlimVec<T>,
range: impl RangeBounds<usize>,
) -> Drain<'_, T> {
let yield_range = conform_range(range, slimvec.len());
let tail = yield_range.end..slimvec.len();
if !slimvec.is_empty() {
unsafe { slimvec.raw.set_length(yield_range.start) };
}
Drain {
slimvec,
tail,
yield_range,
}
}
#[inline]
pub(crate) fn void(&self) -> Range<usize> {
self.slimvec.len()..self.tail.start
}
#[inline]
pub(crate) fn fill_void(&mut self, with: &mut impl Iterator<Item = T>) {
for element in with.by_ref().take(self.void().len()) {
unsafe { self.slimvec.raw.push_unchecked(element) };
}
}
#[inline]
pub(crate) unsafe fn shift_tail(&mut self, to_index: usize) {
debug_assert!(
(self.slimvec.raw.is_capacity_gt_zero())
&& (self.slimvec.capacity() >= (to_index + self.tail.len())),
"required safety criteria"
);
unsafe {
ptr::NonNull::copy_from(
self.slimvec.raw.element_ptr(to_index),
self.slimvec.raw.element_ptr(self.tail.start),
self.tail.len(),
);
}
self.tail = to_index..(to_index + self.tail.len());
}
}
impl<T> Drop for Drain<'_, T> {
fn drop(&mut self) {
let yield_range = mem::take(&mut self.yield_range);
unsafe { self.slimvec.raw.drop_in_place(yield_range) };
if !self.tail.is_empty() {
let new_len = self.slimvec.len() + self.tail.len();
unsafe {
self.shift_tail(self.slimvec.len());
self.slimvec.raw.set_length(new_len);
}
}
}
}
impl<T> UnwindSafe for Drain<'_, T> where T: RefUnwindSafe {}