use core::{
fmt::{self, Debug},
iter::FusedIterator,
mem,
ops::{Range, RangeBounds},
ptr::{self, NonNull},
slice,
};
use crate::{utils, TailVec, VecLike};
impl<T, V: VecLike<T = T>> TailVec<'_, T, V> {
pub fn drain<R>(&mut self, range: R) -> Drain<'_, V>
where R: RangeBounds<usize>,
{
let len = self.len();
let Range { start, end } = utils::range(range, ..len);
unsafe {
self.set_len(start);
let ptr = self.as_ptr().add(start);
let slice = slice::from_raw_parts(ptr, end - start);
Drain {
tail_start: end,
tail_len: len - end,
iter: slice.iter(),
vec: NonNull::from(self),
}
}
}
}
struct DropGuard<'r, 'a, V: VecLike>(&'r mut Drain<'a, V>);
impl<V: VecLike> Drop for DropGuard<'_, '_, V> {
fn drop(&mut self) {
unsafe {
let src_vec = self.0.vec.as_mut();
let start = src_vec.len();
let tail = self.0.tail_start;
let count = self.0.tail_len;
if tail != start {
let src = src_vec.as_ptr().add(tail);
let dst = src_vec.as_mut_ptr().add(start);
ptr::copy(src, dst, count);
}
src_vec.set_len(start + count);
}
}
}
pub struct Drain<'a, V: VecLike> where V::T: 'a {
tail_start: usize,
tail_len: usize,
iter: slice::Iter<'a, V::T>,
vec: NonNull<TailVec<'a, V::T, V>>,
}
impl<V: VecLike> Iterator for Drain<'_, V> {
type Item = V::T;
fn next(&mut self) -> Option<Self::Item> {
let ele = self.iter.next()?;
Some(unsafe { ptr::read(ele) })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<V: VecLike> DoubleEndedIterator for Drain<'_, V> {
fn next_back(&mut self) -> Option<Self::Item> {
let ele = self.iter.next_back()?;
Some(unsafe { ptr::read(ele) })
}
}
impl<V: VecLike> ExactSizeIterator for Drain<'_, V> {
}
impl<V: VecLike> FusedIterator for Drain<'_, V> {
}
unsafe impl<V: VecLike> Send for Drain<'_, V> where V::T: Send {
}
unsafe impl<V: VecLike> Sync for Drain<'_, V> where V::T: Sync {
}
impl<V: VecLike> Drop for Drain<'_, V> {
fn drop(&mut self) {
let is_zst = mem::size_of::<V::T>() == 0;
let iter = mem::take(&mut self.iter);
let drop_len = iter.len();
let mut vec = self.vec;
if is_zst {
unsafe {
let vec = self.vec.as_mut();
let old_len = vec.len();
vec.set_len(old_len + drop_len + self.tail_len);
vec.truncate(old_len + self.tail_len);
}
return;
}
let _guard = DropGuard(self);
if drop_len == 0 {
return;
}
let drop_ptr = iter.as_slice().as_ptr();
unsafe {
let vec_ptr = vec.as_mut().as_mut_ptr();
let drop_offset = drop_ptr.offset_from(vec_ptr).try_into().unwrap();
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
ptr::drop_in_place(to_drop);
}
}
}
impl<V: VecLike> Drain<'_, V> {
pub fn as_slice(&self) -> &[V::T] {
self.iter.as_slice()
}
}
impl<V: VecLike> Debug for Drain<'_, V>
where V::T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
}
}