#![cfg(feature = "panic-on-alloc")]
use core::{ptr, slice};
use crate::{BumpVec, destructure::destructure, traits::BumpAllocatorTyped};
use super::Drain;
#[derive(Debug)]
pub struct Splice<'a, I: Iterator + 'a, A: BumpAllocatorTyped> {
pub(super) drain: Drain<'a, I::Item, A>,
pub(super) replace_with: I,
}
impl<I: Iterator, A: BumpAllocatorTyped> Iterator for Splice<'_, I, A> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.drain.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.drain.size_hint()
}
}
impl<I: Iterator, A: BumpAllocatorTyped> DoubleEndedIterator for Splice<'_, I, A> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.drain.next_back()
}
}
impl<I: Iterator, A: BumpAllocatorTyped> ExactSizeIterator for Splice<'_, I, A> {}
impl<I: Iterator, A: BumpAllocatorTyped> Drop for Splice<'_, I, A> {
fn drop(&mut self) {
self.drain.by_ref().for_each(drop);
self.drain.iter = <[I::Item]>::iter(&[]);
unsafe {
if self.drain.tail_len == 0 {
self.drain.vec.as_mut().extend(self.replace_with.by_ref());
return;
}
if !self.drain.fill(&mut self.replace_with) {
return;
}
let (lower_bound, _upper_bound) = self.replace_with.size_hint();
if lower_bound > 0 {
self.drain.move_tail(lower_bound);
if !self.drain.fill(&mut self.replace_with) {
return;
}
}
let collected = BumpVec::from_iter_in(&mut self.replace_with, self.drain.vec.as_ref().allocator());
destructure!(let BumpVec::<I::Item, &A> { fixed: collected } = collected);
let mut collected = collected.cook().into_iter();
#[expect(clippy::len_zero)]
if collected.len() > 0 {
self.drain.move_tail(collected.len());
let filled = self.drain.fill(&mut collected);
debug_assert!(filled);
debug_assert_eq!(collected.len(), 0);
}
}
}
}
impl<T, A: BumpAllocatorTyped> Drain<'_, T, A> {
unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
unsafe {
let vec = self.vec.as_mut();
let range_start = vec.len();
let range_end = self.tail_start;
let range_slice = slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start);
for place in range_slice {
match replace_with.next() {
Some(new_item) => {
ptr::write(place, new_item);
vec.inc_len(1);
}
_ => {
return false;
}
}
}
true
}
}
unsafe fn move_tail(&mut self, additional: usize) {
unsafe {
let vec = self.vec.as_mut();
let len = self.tail_start + self.tail_len;
vec.buf_reserve(len, additional);
let new_tail_start = self.tail_start + additional;
let src = vec.as_ptr().add(self.tail_start);
let dst = vec.as_mut_ptr().add(new_tail_start);
ptr::copy(src, dst, self.tail_len);
self.tail_start = new_tail_start;
}
}
}