use std::num::NonZero;
use crate::{
buffer,
buffer::{
hold, segments,
segments::{Chain, Handle, Key, Plural, handles},
},
depot::arena::linked::slots,
};
pub(in crate::buffer::segments) enum Remaining {
Single,
Multi,
}
pub(in crate::buffer::segments) struct Multi<'a, T, H: Handle<T>> {
pub(in crate::buffer::segments) sequence: &'a mut Chain<T, H>,
pub(in crate::buffer::segments) index: slots::Index,
}
struct Removed<'a, T, H: Handle<T>> {
owner: slots::Live<segments::Item<T>, &'a slots::Store<segments::Item<T>>>,
handle: &'a H,
key: &'a mut Key,
index: slots::Index,
}
unsafe impl<'a, T: 'a, H: Handle<T>> buffer::raw::Linked<'a> for &'a mut Multi<'_, T, H> {
type Item = segments::Item<T>;
type Metadata = handles::Descriptor;
fn parts(
self,
) -> (
&'a slots::Store<Self::Item>,
&'a slots::Store<Self::Metadata>,
slots::Index,
) {
let handle = &self.sequence.handle;
(
handles::nodes(handle),
handles::descriptors(handle),
self.index,
)
}
fn head(metadata: &Self::Metadata) -> slots::Index {
metadata.links.head_raw()
}
}
unsafe impl<'a, T: 'a, H: Handle<T>> buffer::raw::LinkedMut<'a> for &'a mut Multi<'_, T, H> {}
impl<'a, T: buffer::raw::Segment, H: Handle<T>> Multi<'a, T, H> {
pub(in crate::buffer::segments) fn front(
&mut self,
) -> (&mut handles::Descriptor, &mut segments::Item<T>) {
buffer::raw::LinkedMut::front_mut(self)
}
pub(in crate::buffer::segments::chain::edit) fn consume(
mut self,
amount: NonZero<usize>,
) -> Option<NonZero<usize>> {
let (desc, owner) = self.front();
if let Some(tail) = segments::Tail::positive(owner, amount) {
tail.commit();
desc.len -= amount.get();
return None;
}
let owner = self.take();
NonZero::new(amount.get() - owner.len().get())
}
pub(in crate::buffer::segments) fn take(self) -> segments::Item<T> {
self.take_front().0
}
#[inline(always)]
pub(in crate::buffer::segments) fn take_front(self) -> (segments::Item<T>, Remaining) {
let mut removed = self.detach();
let rest = removed.finish().1;
let owner = removed.owner.take().0;
(owner, rest)
}
pub(in crate::buffer::segments) fn discard(self) -> (hold::Charge, Remaining) {
self.detach().finish()
}
fn detach(self) -> Removed<'a, T, H> {
let nodes = handles::nodes(&self.sequence.handle);
let descs = handles::descriptors(&self.sequence.handle);
let desc = unsafe { &mut *descs.value_ptr(self.index) };
let head = desc.links.head_raw();
let owner = unsafe { crate::depot::raw::SlotOwner::detach(&mut desc.links, nodes, head) };
Removed {
owner,
handle: &self.sequence.handle,
key: &mut self.sequence.key,
index: self.index,
}
}
}
impl<T: buffer::raw::Segment, H: Handle<T>> Removed<'_, T, H> {
#[inline(always)]
fn finish(&mut self) -> (hold::Charge, Remaining) {
let len = self.owner.get().len().get();
let resident = buffer::Residency::resident(self.owner.get());
let charge = hold::Charge::from_owner(len, resident);
let descs = handles::descriptors(self.handle);
let desc = unsafe { &mut *descs.value_ptr(self.index) };
let count = Plural(desc.count);
let rest = if count.raw() == 2 {
let entry = unsafe { descs.detached(self.index) };
*self.key = Key::single(entry.get().links.head_raw());
Remaining::Single
} else {
desc.count = count.tail();
desc.len -= len;
desc.resident_bytes -= resident;
Remaining::Multi
};
(charge, rest)
}
}