use std::{convert::Infallible, fmt, mem, pin};
use app::step;
use dope_core::driver;
use driver::schedule::{app, ready};
use ready::task::owner;
use request::admit;
use sark_http::{payload::owned, request::Id};
use crate::{
decode,
decode::{dispatch, exec, request},
duplex,
manifold::task::{self, Target, response},
route,
};
pub trait Bind<'d>: Sized
where
<Self::Runtime as decode::Decode>::Egress<'d>: 'd,
{
type Target: Target + 'd;
type Runtime: Runtime<'d, Target = Self::Target>;
type Error;
fn try_bind(self, bind: driver::Binding<'d>) -> Result<Self::Runtime, Self::Error>;
}
#[must_use]
#[repr(u8)]
pub enum Turn<'turn, 'd, C = ()> {
Idle,
Deferred,
Pending(step::Receipt<'turn, 'd>),
PendingReady(step::Receipt<'turn, 'd>),
Ready(C, step::Receipt<'turn, 'd>),
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Wake {
Ready,
Idle,
}
pub trait Handoff<'d, T: Target, F: response::Completion<'d>>: Sized {
type Ready;
fn pending(self, target: T);
fn complete(self, target: T, output: F) -> Self::Ready;
fn ready<E: fmt::Debug>(self, target: T, event: response::Event<'d, E>) -> Self::Ready;
}
pub trait Runtime<'d>:
decode::Decode<Head: request::Head<Start: admit::Start<Self>>, Egress<'d>: 'd>
+ duplex::Application<'d>
+ Sized
{
type Task;
type Fixed: response::Completion<'d>;
type Build: crate::body::Push<'d>;
type Target: Target + 'd;
type Admission;
type OwnerCause: fmt::Debug;
type RetireCause: fmt::Debug;
fn reject_step(error: <Self::Build as crate::body::Build<'d>>::StepError) -> route::Reject;
fn reject_push(error: <Self::Build as crate::body::Push<'d>>::Error) -> route::Reject;
fn rejection(error: &task::Error<Self::Admission>) -> route::Reject;
fn register(
self: pin::Pin<&Self>,
owner: owner::Owner<Self::Target>,
) -> Result<(), Self::OwnerCause>;
fn try_retire(
self: pin::Pin<&Self>,
owner: owner::Owner<Self::Target>,
) -> Result<(), Self::RetireCause>;
fn try_dispatch(
self: pin::Pin<&mut Self>,
req: request::Ready<exec::Task, Self::Prepared, owned::Segments<'d>>,
target: Self::Target,
owner: owner::Owner<Self::Target>,
parent: ready::Target<'d>,
) -> Result<Self::Task, task::Error<Self::Admission>>;
fn try_start(
&self,
req: Self::Prepared,
) -> Result<Self::Build, dispatch::Error<Infallible, Infallible, route::Reject>>;
fn try_built(
self: pin::Pin<&mut Self>,
output: <Self::Build as crate::body::Build<'d>>::Output,
target: Self::Target,
owner: owner::Owner<Self::Target>,
parent: ready::Target<'d>,
) -> Result<Self::Task, task::Error<Self::Admission>>;
fn drive<'turn, H: Handoff<'d, Self::Target, Self::Fixed>>(
self: pin::Pin<&mut Self>,
scope: owner::Scope<Self::Target>,
work: app::Work<'turn, 'd>,
driver: &mut driver::Context<'_, 'd>,
sink: H,
) -> Turn<'turn, 'd, H::Ready>;
fn emit<E: decode::Streaming<'d, 'd>>(
self: pin::Pin<&mut Self>,
task: &Self::Task,
make: impl FnOnce(Id<'d>) -> E,
) -> response::Access<response::Prepared<'d, E>>;
fn resume(self: pin::Pin<&mut Self>, task: &Self::Task) -> response::Access<()>;
fn has_work(self: pin::Pin<&Self>, scope: owner::Scope<Self::Target>) -> bool;
fn wake(self: pin::Pin<&mut Self>, scope: owner::Scope<Self::Target>);
fn try_wake(self: pin::Pin<&mut Self>, scope: owner::Scope<Self::Target>) -> Wake;
fn cancel(self: pin::Pin<&mut Self>, task: Self::Task);
}
const _: () = assert!(mem::size_of::<Turn<'static, 'static>>() == 1);