use dope_core::io::{recv, transfer};
use o3::buffer::write::consume::Consume as _;
use receive::mode;
use crate::wire::receive;
mod state;
pub use state::State;
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct Prefix(transfer::NonZero);
impl Prefix {
pub const ONE: Self = Self(transfer::NonZero::fixed_size::<1>());
pub const fn new(bytes: transfer::NonZero) -> Self {
Self(bytes)
}
pub const fn try_new(bytes: usize) -> Option<Self> {
match transfer::NonZero::try_new(bytes) {
Some(bytes) => Some(Self(bytes)),
None => None,
}
}
pub const fn fixed<const BYTES: usize>() -> Self {
Self(transfer::NonZero::fixed_size::<BYTES>())
}
fn consume(self, bytes: &mut recv::Lease<'_>) -> Option<Self> {
let total = transfer::Len::from_nonzero(self.0);
let used = transfer::Len::prefix(bytes.consume_max(total.into_raw()), total);
total.checked_sub(used).map(Self)
}
}
pub trait Policy: mode::Flag {
type State;
const STATE: Self::State;
fn begin(state: &mut Self::State, prefix: Prefix) -> Start;
fn is_pending(state: &Self::State) -> bool;
fn consume(state: &mut Self::State, bytes: &mut recv::Lease<'_>) -> (transfer::Len, bool);
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Start {
Started,
Busy,
Closing,
Unsupported {
requested: Prefix,
},
}
impl Policy for mode::Disabled {
type State = ();
const STATE: Self::State = ();
fn begin(state: &mut Self::State, prefix: Prefix) -> Start {
let () = *state;
Start::Unsupported { requested: prefix }
}
fn is_pending(_: &Self::State) -> bool {
false
}
fn consume(state: &mut Self::State, bytes: &mut recv::Lease<'_>) -> (transfer::Len, bool) {
let () = *state;
(bytes.len(), false)
}
}
impl Policy for mode::Enabled {
type State = State;
const STATE: Self::State = State::EMPTY;
fn begin(state: &mut Self::State, prefix: Prefix) -> Start {
if state.remaining.is_some() {
return Start::Busy;
}
state.remaining = Some(prefix);
Start::Started
}
fn is_pending(state: &Self::State) -> bool {
state.remaining.is_some()
}
fn consume(state: &mut Self::State, bytes: &mut recv::Lease<'_>) -> (transfer::Len, bool) {
let Some(prefix) = state.remaining else {
return (bytes.len(), false);
};
state.remaining = prefix.consume(bytes);
(bytes.len(), state.remaining.is_none())
}
}
const _: () = {
use std::mem;
assert!(mem::size_of::<Prefix>() == mem::size_of::<transfer::NonZero>());
assert!(mem::size_of::<Option<Prefix>>() == mem::size_of::<transfer::NonZero>());
assert!(mem::size_of::<<mode::Disabled as Policy>::State>() == 0);
assert!(mem::size_of::<<mode::Enabled as Policy>::State>() == mem::size_of::<Prefix>());
assert!(mem::size_of::<Start>() == 2 * mem::size_of::<Prefix>());
};