use std::mem;
use o3::buffer::{self, segments::scatter};
use crate::io::transfer;
pub struct Bytes<'data> {
bytes: &'data [u8],
progress: State,
}
#[must_use = "the selected bytes must either be committed or left untouched"]
pub struct Slice<'a, 'data> {
bytes: &'data [u8],
step: Step<'a>,
}
impl<'data> Bytes<'data> {
#[must_use]
pub fn new(view: transfer::View<'data>) -> Self {
let (bytes, len) = view.into_parts();
Self {
bytes,
progress: State::new(len),
}
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.progress.is_empty()
}
pub fn take(&mut self, limit: transfer::Len) -> Slice<'_, 'data> {
let start = self.bytes.len() - self.progress.left().into_raw();
let step = self.progress.reserve(limit);
let end = start + step.amount().into_raw();
let bytes = unsafe { self.bytes.get_unchecked(start..end) };
Slice { bytes, step }
}
#[must_use]
pub const fn into_len(self) -> transfer::Len {
self.progress.len()
}
}
impl Slice<'_, '_> {
#[must_use]
pub const fn as_slice(&self) -> &[u8] {
self.bytes
}
#[must_use]
pub const fn amount(&self) -> transfer::Len {
self.step.amount()
}
pub fn commit(self) {
self.step.commit();
}
}
const _: () =
assert!(mem::size_of::<Bytes<'_>>() == mem::size_of::<&[u8]>() + mem::size_of::<State>());
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Exceeded {
requested: transfer::Len,
available: transfer::Len,
}
impl Exceeded {
const fn new(req: transfer::Len, avail: transfer::Len) -> Self {
Self {
requested: req,
available: avail,
}
}
pub const fn requested(self) -> transfer::Len {
self.requested
}
pub const fn available(self) -> transfer::Len {
self.available
}
}
pub struct State {
limit: transfer::Len,
remaining: transfer::Len,
}
impl State {
#[must_use]
pub const fn new(limit: transfer::Len) -> Self {
Self {
limit,
remaining: limit,
}
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.remaining.is_zero()
}
#[must_use]
pub const fn left(&self) -> transfer::Len {
self.remaining
}
#[must_use]
pub const fn len(&self) -> transfer::Len {
self.limit.abs_diff(self.remaining)
}
pub fn reserve(&mut self, limit: transfer::Len) -> Step<'_> {
let amount = limit.min(self.remaining);
Step {
progress: self,
amount,
}
}
pub fn scatter<'a>(
&mut self,
cursor: &mut impl buffer::raw::Scatter<'a>,
) -> Option<buffer::raw::Chunk<'a, { transfer::MAX_BYTES }>> {
let chunk = scatter::Take::new(cursor, self.remaining.into_raw())
.next_chunk::<{ transfer::MAX_BYTES }>()?;
let count = transfer::Len::from_count(chunk.len().into_count());
self.remaining = self.remaining.abs_diff(count);
Some(chunk)
}
pub fn try_extend(&self, amount: transfer::Len) -> Result<Self, Exceeded> {
if amount.is_greater(self.remaining) {
return Err(Exceeded::new(amount, self.remaining));
}
Ok(Self {
limit: self.limit,
remaining: self.remaining.abs_diff(amount),
})
}
}
pub struct Step<'a> {
progress: &'a mut State,
amount: transfer::Len,
}
impl Step<'_> {
#[must_use]
pub const fn amount(&self) -> transfer::Len {
self.amount
}
pub fn commit(self) {
self.progress.remaining = self.progress.remaining.abs_diff(self.amount);
}
}
const _: () = {
assert!(mem::size_of::<State>() == 2 * mem::size_of::<u32>());
let state = mem::size_of::<&mut State>() + mem::size_of::<u32>();
let align = mem::align_of::<Step<'_>>();
assert!(mem::size_of::<Step<'_>>() == state.div_ceil(align) * align);
};