use std::num::NonZero;
use crate::{
buffer,
buffer::{
segments,
segments::{Chain, Handle, chain::view, handles, scatter},
},
depot::arena::{linked, linked::slots},
};
pub struct Cursor<'a, T> {
nodes: linked::Iter<'a, segments::Item<T>>,
current: &'a [u8],
remaining: usize,
}
impl<'a, T: buffer::raw::Segment> Cursor<'a, T> {
pub(in crate::buffer) unsafe fn resume<H: Handle<T>>(
source: &'a Chain<T, H>,
position: &mut scatter::raw::Position,
offset: usize,
) -> Self {
let nodes = handles::nodes(&source.handle);
let (head, len) = match unsafe { source.occupied() } {
view::Occupied::Single(index, item) => (index, item.len().get()),
view::Occupied::Multi(desc) => (desc.links.head_raw(), desc.len),
};
if position.index == slots::Index::NONE || offset < position.start {
position.index = head;
position.start = 0;
}
loop {
let item = unsafe { nodes.value(position.index) };
let bytes = item.chunk().bytes();
let skip = offset - position.start;
let next = unsafe { nodes.next(position.index) };
if skip < bytes.len() {
return Self {
nodes: unsafe { linked::Iter::new(nodes, next) },
current: unsafe { bytes.get_unchecked(skip..) },
remaining: len - offset,
};
}
position.start += bytes.len();
position.index = next;
}
}
pub(in crate::buffer) fn remaining(&self) -> usize {
self.remaining
}
pub(in crate::buffer) unsafe fn next_chunk<const MAX: usize>(
&mut self,
cap: NonZero<usize>,
_left: NonZero<usize>,
) -> buffer::raw::Chunk<'a, MAX> {
if self.current.is_empty() {
let item = unsafe { self.nodes.next_live() };
self.current = item.chunk().bytes();
}
let len = unsafe { NonZero::new_unchecked(self.current.len()) }.min(cap);
let (bytes, suffix) = self.current.split_at(len.get());
self.current = suffix;
self.remaining -= len.get();
unsafe { buffer::raw::Chunk::new(bytes) }
}
pub(in crate::buffer::segments) fn new<H: Handle<T>>(source: &'a Chain<T, H>) -> Self {
let sequence = source;
let nodes = handles::nodes(&sequence.handle);
let (head, len) = match sequence.state() {
view::State::Empty => (slots::Index::NONE, 0),
view::State::Single(index, item) => (index, item.len().get()),
view::State::Multi(desc) => (desc.links.head_raw(), desc.len),
};
Self {
nodes: unsafe { linked::Iter::new(nodes, head) },
current: &[],
remaining: len,
}
}
}
const _: () = {
assert!(size_of::<Cursor<'static, ()>>() == 5 * size_of::<usize>());
assert!(size_of::<Option<Cursor<'static, ()>>>() == size_of::<Cursor<'static, ()>>());
};