use core::{
fmt,
iter::FusedIterator,
mem::{self, ManuallyDrop},
ops::RangeBounds,
ptr::{self, NonNull},
};
use crate::{
BumpBox, SizedTypeProperties, owned_slice,
polyfill::{non_null, slice},
};
use super::TakeOwnedSlice;
pub struct Drain<'a, T: 'a> {
tail_start: usize,
tail_len: usize,
iter: owned_slice::IntoIter<'a, T>,
slice: &'a mut NonNull<[T]>,
}
impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
}
}
impl<'a, T> Drain<'a, T> {
pub(crate) fn new(boxed: &'a mut BumpBox<[T]>, range: impl RangeBounds<usize>) -> Drain<'a, T> {
let len = boxed.len();
let range = slice::range(range, ..len);
unsafe {
boxed.set_len(range.start);
Drain {
tail_start: range.end,
tail_len: len - range.end,
iter: owned_slice::IntoIter::new_ranged(boxed.ptr(), range),
slice: boxed.mut_ptr(),
}
}
}
#[must_use]
pub fn as_slice(&self) -> &[T] {
self.iter.as_slice()
}
pub fn keep_rest(self) {
let mut this = ManuallyDrop::new(self);
unsafe {
let slice_ptr = non_null::as_non_null_ptr(*this.slice).as_ptr();
let start = this.slice.len();
let tail = this.tail_start;
let unyielded_len = this.iter.len();
let unyielded_ptr = this.iter.as_slice().as_ptr();
if !T::IS_ZST {
let start_ptr = slice_ptr.add(start);
if unyielded_ptr != start_ptr {
let src = unyielded_ptr;
let dst = start_ptr;
ptr::copy(src, dst, unyielded_len);
}
if tail != (start + unyielded_len) {
let src = slice_ptr.add(tail);
let dst = start_ptr.add(unyielded_len);
ptr::copy(src, dst, this.tail_len);
}
}
let new_len = start + unyielded_len + this.tail_len;
non_null::set_len(this.slice, new_len);
}
}
}
impl<T> AsRef<[T]> for Drain<'_, T> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
unsafe impl<T: Sync> Sync for Drain<'_, T> {}
unsafe impl<T: Send> Send for Drain<'_, T> {}
impl<T> Iterator for Drain<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.iter.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for Drain<'_, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
self.iter.next_back()
}
}
impl<T> Drop for Drain<'_, T> {
fn drop(&mut self) {
struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>);
impl<T> Drop for DropGuard<'_, '_, T> {
fn drop(&mut self) {
if self.0.tail_len > 0 {
unsafe {
let slice_ptr = non_null::as_non_null_ptr(*self.0.slice).as_ptr();
let start = self.0.slice.len();
let tail = self.0.tail_start;
if tail != start {
let src = slice_ptr.add(tail);
let dst = slice_ptr.add(start);
ptr::copy(src, dst, self.0.tail_len);
}
non_null::set_len(self.0.slice, start + self.0.tail_len);
}
}
}
}
let iter = mem::take(&mut self.iter);
if T::IS_ZST {
unsafe {
let old_len = self.slice.len();
non_null::set_len(self.slice, old_len + iter.len() + self.tail_len);
non_null::truncate(self.slice, old_len + self.tail_len);
}
return;
}
let _guard = DropGuard(self);
drop(iter);
}
}
impl<T> ExactSizeIterator for Drain<'_, T> {
#[cfg(feature = "nightly-exact-size-is-empty")]
fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}
#[cfg(feature = "nightly-trusted-len")]
unsafe impl<T> core::iter::TrustedLen for Drain<'_, T> {}
impl<T> FusedIterator for Drain<'_, T> {}
unsafe impl<T> TakeOwnedSlice for Drain<'_, T> {
type Item = T;
#[inline]
fn owned_slice_ref(&self) -> &[Self::Item] {
self.iter.owned_slice_ref()
}
#[inline]
fn take_owned_slice(&mut self) {
self.iter.take_owned_slice();
}
}