use crate::{buffer, buffer::pool::owners};
pub(in crate::buffer::pool) mod fill;
pub(in crate::buffer::pool) mod limit;
use std::ptr;
use pool::state;
use crate::buffer::{
pool, storage, write,
write::{SpareExt as _, consume},
};
pub struct Cursor<L = pool::Layout, M = pool::Owned> {
pub(in crate::buffer::pool) lease: pool::Span<owners::Plain<L>, M>,
head: u32,
}
impl<L, M> Cursor<L, M> {
fn into_shared(self) -> storage::Shared<owners::Edge<owners::Plain<L>, M>> {
let start = self.head as usize;
let len = self.lease.len() - start;
unsafe { pool::raw::into_shared(self.lease, start, len) }
}
}
impl<L, M> Cursor<L, M> {
pub fn len(&self) -> usize {
self.lease.len() - self.head as usize
}
pub fn spare_len(&self) -> usize {
self.lease.capacity().get() as usize - self.len()
}
fn clear(&mut self) {
self.head = 0;
self.lease.truncate(0);
}
pub fn spare(&mut self) -> write::Spare<'_> {
self.compact();
self.lease.spare()
}
pub(in crate::buffer::pool) fn compact_for(&mut self, len: usize) {
if len > self.lease.capacity().get() as usize - self.lease.len() {
self.compact();
}
}
fn compact(&mut self) {
if self.head == 0 {
return;
}
let len = self.len();
let data = self.lease.as_mut_slice().as_mut_ptr();
unsafe { ptr::copy(data.add(self.head as usize), data, len) };
self.head = 0;
self.lease.len = len as u32;
}
}
const _: () = {
assert!(size_of::<Cursor>() == 3 * size_of::<usize>());
assert!(size_of::<Cursor<pool::Layout, pool::Borrowed<'static>>>() == 3 * size_of::<usize>());
};
impl<L, M> Cursor<L, M> {
fn advance(prefix: buffer::raw::Selection<'_, Self>) {
let (target, amount) = prefix.into_parts();
let head = target.head + amount as u32;
if head as usize == target.lease.len() {
target.clear();
} else {
target.head = head;
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn try_append<'a, 'source>(
&'a mut self,
source: &'source [u8],
) -> Result<pool::Append<'a, &'source [u8], Self>, consume::Error> {
let input = owners::Measured::slice(source);
pool::Append::try_input(self, input)
}
pub fn write(&mut self, source: &[u8]) -> usize {
let append = pool::Append::prefix(self, source);
let copied = append.input.len();
append.commit();
copied
}
}
impl<L> Cursor<L> {
pub fn recycle(self) {
self.lease.recycle();
}
#[must_use]
pub fn freeze(self) -> storage::Shared {
self.into_shared().into()
}
}
impl<'pool, L> Cursor<L, pool::Borrowed<'pool>> {
#[must_use]
pub fn freeze(self) -> storage::Shared<owners::Edge<owners::Plain<L>, pool::Borrowed<'pool>>> {
self.into_shared()
}
}
impl<L, M> AsRef<[u8]> for Cursor<L, M> {
fn as_ref(&self) -> &[u8] {
unsafe { self.lease.as_slice().get_unchecked(self.head as usize..) }
}
}
impl<L, M> consume::Consume for Cursor<L, M> {
fn remaining(&self) -> usize {
self.lease.len() - self.head as usize
}
fn try_consume(&mut self, amount: usize) -> Result<(), consume::Error> {
buffer::raw::Selection::try_new(self, amount).map(Self::advance)
}
fn consume_max(&mut self, max: usize) -> usize {
let selected = buffer::raw::Selection::new(self, max);
let amount = selected.len();
Self::advance(selected);
amount
}
}
impl<L, M> write::Sink for Cursor<L, M> {
type Error = consume::Error;
fn write_slice(&mut self, source: &[u8]) -> Result<(), Self::Error> {
self.try_append(source)?.commit();
Ok(())
}
fn write_slices<const N: usize>(&mut self, slices: [&[u8]; N]) -> Result<(), Self::Error> {
let input = owners::Input::try_measure(slices)?;
pool::Append::try_input(self, input)?.copy();
Ok(())
}
}
unsafe impl<L, M> buffer::raw::Source for Cursor<L, M> {}
impl<L, M> From<pool::Span<owners::Plain<L>, M, state::Uninit>> for Cursor<L, M> {
fn from(lease: pool::Span<owners::Plain<L>, M, state::Uninit>) -> Self {
Self { lease, head: 0 }
}
}
impl<L, M> AsMut<[u8]> for Cursor<L, M> {
fn as_mut(&mut self) -> &mut [u8] {
let head = self.head as usize;
unsafe { self.lease.as_mut_slice().get_unchecked_mut(head..) }
}
}