use crate::{
buffer,
buffer::{
hold, segments,
segments::{Chain, Handle, Key, Nonempty, Plural, Shape, handles},
},
depot::arena::linked::slots,
mem::rc,
};
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,
}
type Removed<'a, T> = (
slots::Live<segments::Item<T>, &'a slots::Store<segments::Item<T>>>,
hold::Charge,
Remaining,
);
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>) {
let handle = &self.sequence.handle;
let nodes = handles::nodes(handle);
let descs = handles::descriptors(handle);
unsafe {
let desc = &mut *descs.value_ptr(self.index);
let owner = &mut *nodes.value_ptr(desc.links.head_raw());
(desc, owner)
}
}
#[inline(always)]
pub(in crate::buffer::segments) fn take_front(self) -> (segments::Item<T>, Remaining) {
let (owner, _, rest) = self.remove();
(owner.take().0, rest)
}
pub(in crate::buffer::segments) fn discard(self) -> (hold::Charge, Remaining) {
let (_, charge, rest) = self.remove();
(charge, rest)
}
#[inline(always)]
fn remove(self) -> Removed<'a, T> {
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) };
let len = owner.get().len().get();
let resident = buffer::Residency::resident(owner.get());
let charge = hold::Charge::from_owner(len, resident);
let count = Plural(desc.count);
let rest = if count.raw() == 2 {
let entry = unsafe { descs.detached(self.index) };
self.sequence.key = Key::single(entry.get().links.head_raw());
Remaining::Single
} else {
desc.count = count.tail();
desc.len -= len;
desc.resident_bytes -= resident;
Remaining::Multi
};
(owner, charge, rest)
}
}
impl<T: buffer::raw::Segment> Nonempty<T> {
pub fn try_pop(self, limit: usize) -> Result<(T, Shape<T>), (rc::Error, Self)> {
match self {
Self::One(mut owner) => {
let Some(tail) = owner.tail(limit) else {
return Ok((owner.into_inner(), Shape::Empty));
};
match tail.try_commit() {
Ok(head) => Ok((head, Shape::One(owner))),
Err(error) => Err((error, Self::One(owner))),
}
}
Self::Many(owners) => {
let (head, rest) = owners
.try_pop(limit)
.map_err(|(error, owners)| (error, Self::Many(owners)))?;
Ok((head, rest.into_shape()))
}
}
}
}