use std::{marker, ops};
pub(crate) use attempt::{Attempt, State};
pub use direct::Direct;
use dope_core::{
driver::{
retained::flight,
route::{Identity, kind},
},
io::transfer,
};
use o3::base::marker::ThreadBound;
pub use policy::Policy;
use crate::wire;
mod sources;
pub use sources::{either::Either, empty::Empty, plain::Plain, vectored::Vectored};
mod attempt;
mod control;
mod direct;
mod policy;
pub mod progress;
pub mod raw;
pub mod reclaim;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub(crate) struct Sent(transfer::Len);
impl Sent {
pub(crate) const fn new(bytes: transfer::Len) -> Self {
Self(bytes)
}
pub(crate) const fn into_len(self) -> transfer::Len {
self.0
}
}
pub trait Consume: Store {
fn consume_max(&mut self, max: transfer::Len);
}
pub trait Store {
fn as_slice(&self) -> &[u8];
fn release(self) -> Availability;
}
impl Store for () {
fn as_slice(&self) -> &[u8] {
let () = self;
&[]
}
fn release(self) -> Availability {
let () = self;
Availability::Unchanged
}
}
pub struct Storage<'a, S: Store> {
storage: &'a mut S,
scope: Scope<'a>,
}
struct Scope<'a>(marker::PhantomData<&'a mut ThreadBound>);
#[must_use]
pub struct Completion<'a, P: reclaim::Policy, S: Store> {
storage: Storage<'a, S>,
sent: Sent,
policy: marker::PhantomData<fn() -> P>,
}
#[must_use = "consumed storage must be turned into a prepared send"]
pub struct Consumed<'a, S: Store> {
storage: Storage<'a, S>,
consumed: transfer::Len,
}
impl<'a, P: reclaim::Policy, S: Store> Completion<'a, P, S> {
pub(crate) fn from_sent(storage: Storage<'a, S>, sent: Sent) -> Self {
Self {
storage,
sent,
policy: marker::PhantomData,
}
}
pub fn into_storage(self) -> Storage<'a, S> {
self.storage
}
}
impl<'a, S: Consume> Completion<'a, reclaim::OnSubmit, S> {
pub fn consume_max(self) -> Storage<'a, S> {
Consume::consume_max(self.storage.storage, self.sent.into_len());
self.storage
}
}
impl<'a, S: Store> Storage<'a, S> {
pub fn new(store: &'a mut S) -> Self {
Self {
storage: store,
scope: Scope(marker::PhantomData),
}
}
#[must_use]
pub fn as_slice(&self) -> &[u8] {
self.storage.as_slice()
}
pub fn consume_none(self) -> Consumed<'a, S> {
Consumed {
storage: self,
consumed: transfer::Len::ZERO,
}
}
pub fn input(self, plain: Plain<'a>) -> Prepared<'a, reclaim::OnComplete, Plain<'a>> {
Prepared::new(plain, reclaim::Exact, self.scope)
}
pub fn vectored<const N: usize>(
self,
plain: Vectored<'a, N>,
) -> Prepared<'a, reclaim::OnComplete, Vectored<'a, N>> {
Prepared::new(plain, reclaim::Exact, self.scope)
}
pub fn buffered(self) -> Prepared<'a, reclaim::OnSubmit, Plain<'a>> {
self.consume_none().buffered()
}
pub fn buffer_wait(self) -> Prepared<'a, reclaim::OnSubmit, Plain<'a>> {
let mut ready = self.buffered();
if ready.payload.is_empty() {
ready.control.mark_waiting();
}
ready
}
pub fn empty<P: reclaim::Policy>(self) -> Prepared<'a, P, Empty> {
Prepared::new(Empty, P::empty(), self.scope)
}
}
impl<'a, S: Store> Consumed<'a, S> {
#[must_use]
pub fn is_empty(&self) -> bool {
self.storage.storage.as_slice().is_empty()
}
pub fn buffered(self) -> Prepared<'a, reclaim::OnSubmit, Plain<'a>> {
let bytes = self.storage.storage.as_slice();
Prepared::new(Plain::proven(bytes), self.consumed, self.storage.scope)
}
}
impl<S: Store> ops::Deref for Storage<'_, S> {
type Target = S;
fn deref(&self) -> &Self::Target {
self.storage
}
}
impl<S: Store> ops::DerefMut for Storage<'_, S> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.storage
}
}
pub trait Payload<'a> {
fn select(&self) -> Option<impl raw::Ready<'a>>;
}
#[must_use]
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Availability {
Unchanged = 0,
Released = 1 << 1,
}
#[must_use]
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum End {
Keep,
Close,
}
#[must_use]
pub struct Prepared<'a, P: reclaim::Policy, B: Payload<'a>> {
payload: B,
credit: P::Credit,
control: control::Control,
scope: Scope<'a>,
}
#[must_use]
#[repr(transparent)]
pub struct Transition<'a, P: reclaim::Policy, B: Payload<'a>>(Prepared<'a, P, B>);
impl<'a, B: Payload<'a>> Transition<'a, reclaim::OnSubmit, B> {
pub fn new(mut ready: Prepared<'a, reclaim::OnSubmit, B>, free: Availability) -> Self {
ready.control.mark_free(free);
Self(ready)
}
pub fn unchanged(ready: Prepared<'a, reclaim::OnSubmit, B>) -> Self {
Self::new(ready, Availability::Unchanged)
}
}
impl<'a> Transition<'a, reclaim::OnComplete, Empty> {
pub fn completed<S: Store>(send: Storage<'a, S>) -> Self {
Self(send.empty())
}
}
impl<'a, P: reclaim::Policy, B: Payload<'a>> Transition<'a, P, B> {
pub const fn availability(&self) -> Availability {
self.0.control.availability()
}
pub fn into_parts(self) -> (Prepared<'a, P, B>, Availability) {
let free = self.availability();
(self.0, free)
}
}
impl<'a, P: reclaim::Policy, B: Payload<'a>> Prepared<'a, P, B> {
fn new(body: B, credit: P::Credit, scope: Scope<'a>) -> Self {
Self {
payload: body,
credit,
control: control::Control::new(),
scope,
}
}
pub fn close_after(mut self) -> Self {
self.control.mark_close();
self
}
pub(crate) const fn is_waiting(&self) -> bool {
self.control.is_waiting()
}
pub fn into_parts(self) -> (B, P::Credit, End) {
(self.payload, self.credit, self.control.end())
}
pub fn into_left<R: Payload<'a>>(self) -> Prepared<'a, P, Either<B, R>> {
Prepared {
payload: Either::Left(self.payload),
credit: self.credit,
control: self.control,
scope: self.scope,
}
}
pub fn into_right<L: Payload<'a>>(self) -> Prepared<'a, P, Either<L, B>> {
Prepared {
payload: Either::Right(self.payload),
credit: self.credit,
control: self.control,
scope: self.scope,
}
}
}
const _: () = {
assert!(std::mem::size_of::<Scope<'static>>() == 0);
assert!(std::mem::size_of::<Storage<'static, ()>>() == std::mem::size_of::<&'static mut ()>());
assert!(
std::mem::align_of::<Storage<'static, ()>>() == std::mem::align_of::<&'static mut ()>()
);
assert!(
std::mem::size_of::<Completion<'static, reclaim::OnSubmit, ()>>()
== std::mem::size_of::<(Storage<'static, ()>, Sent)>()
);
};
pub struct Submitted<'d> {
pub bytes: transfer::NonZero,
pub flight: flight::Flight<'d, kind::Send>,
}
#[must_use]
pub struct Context<'a, 'd, ID: Identity + 'd, W: wire::Spec + 'd, T>
where
'd: 'a,
{
wire: &'a mut W::Connection<'d, ID>,
state: T,
}
impl<'a, 'd, ID: Identity + 'd, W: wire::Spec + 'd, T> Context<'a, 'd, ID, W, T>
where
'd: 'a,
{
pub(crate) fn new(wire: &'a mut W::Connection<'d, ID>, state: T) -> Self {
Self { wire, state }
}
pub fn into_parts(self) -> (&'a mut W::Connection<'d, ID>, T) {
(self.wire, self.state)
}
pub fn into_state(self) -> T {
self.state
}
}