use core::convert::Infallible;
use dope::{
core::{
BranchError,
driver::{route::Identity, schedule::ready::task::owner},
},
manifold::network::listener::conn,
};
use sark_core::{
body,
decode::{
exec, request,
state::{Family, Flow, Fold, Slot},
},
life,
manifold::task::app::Runtime,
};
use sark_http::{field::metadata::section::rules, payload::owned};
use crate::{
server::{
Target, payload,
payload::Buffer,
state,
task::{app::Drive, identify, ingress, response},
},
stream,
};
pub(in crate::server::task) unsafe fn buffered<'d, ID, R, Q, F>(
drive: Drive<'_, '_, 'd, ID, R, Q, F>,
stream: stream::Key,
input: <<R::Prepared as request::Prepared>::Family as Family<R::Prepared>>::State<
ingress::Receiving<'d>,
>,
) where
ID: Identity + 'd,
R: Runtime<'d, Target = Target<'d, ID>>,
Q: state::Transitions<conn::Id<'d, ID>>,
F: rules::Policy,
{
Flow::fold(input, Finish { drive, stream });
}
pub(in crate::server::task) unsafe fn sync<'d, ID, R, Q, F>(
drive: Drive<'_, '_, 'd, ID, R, Q, F>,
stream: stream::Key,
input: request::Admitted<exec::Sync, R::Prepared, Buffer<'d>>,
) where
ID: Identity + 'd,
R: Runtime<'d, Target = Target<'d, ID>>,
Q: state::Transitions<conn::Id<'d, ID>>,
F: rules::Policy,
{
(Finish { drive, stream }).sync(input);
}
pub(in crate::server::task) unsafe fn start<'d, ID, R, Q, F>(
drive: Drive<'_, '_, 'd, ID, R, Q, F>,
stream: stream::Key,
input: request::Admitted<exec::Task, R::Prepared, Buffer<'d>>,
) where
ID: Identity + 'd,
R: Runtime<'d, Target = Target<'d, ID>>,
Q: state::Transitions<conn::Id<'d, ID>>,
F: rules::Policy,
{
(Finish { drive, stream }).task(input);
}
pub(in crate::server::task) fn built<'d, ID, R, Q, F>(
drive: Drive<'_, '_, 'd, ID, R, Q, F>,
stream: stream::Key,
build: <R::Build as body::Build<'d>>::Output,
) where
ID: Identity + 'd,
R: Runtime<'d, Target = Target<'d, ID>>,
Q: state::Transitions<conn::Id<'d, ID>>,
F: rules::Policy,
{
(Finish { drive, stream }).built(build);
}
struct Finish<'a, 'state, 'd, ID: Identity + 'd, R, Q, F>
where
R: Runtime<'d, Target = Target<'d, ID>>,
F: rules::Policy,
{
drive: Drive<'a, 'state, 'd, ID, R, Q, F>,
stream: stream::Key,
}
impl<'d, ID: Identity + 'd, R, Q, F> Fold<R::Prepared, ingress::Receiving<'d>>
for Finish<'_, '_, 'd, ID, R, Q, F>
where
R: Runtime<'d, Target = Target<'d, ID>>,
Q: state::Transitions<conn::Id<'d, ID>>,
F: rules::Policy,
{
type Output = ();
fn sync_open<S: Slot<R::Prepared>>(self, slot: S, body: Buffer<'d>) -> Self::Output {
let input = slot.admit::<exec::Sync, _>(body);
self.sync(input)
}
fn task_open<S: Slot<R::Prepared>>(self, slot: S, body: Buffer<'d>) -> Self::Output {
let input = slot.admit::<exec::Task, _>(body);
self.task(input)
}
fn sync_done<S: Slot<R::Prepared>>(self, _: S, never: Infallible) -> Self::Output {
match never {}
}
fn task_done<S: Slot<R::Prepared>>(self, _: S, never: Infallible) -> Self::Output {
match never {}
}
fn duplex_open<S: Slot<R::Prepared>>(self, _: S, never: Infallible) -> Self::Output {
match never {}
}
fn duplex_done<S: Slot<R::Prepared>>(self, _: S, never: Infallible) -> Self::Output {
match never {}
}
fn reject_open<S: Slot<R::Prepared>>(self, _: S, never: Infallible) -> Self::Output {
match never {}
}
fn reject_done<S: Slot<R::Prepared>>(self, _: S, never: Infallible) -> Self::Output {
match never {}
}
}
impl<'a, 'state, 'd, ID: Identity + 'd, R, Q, F> Finish<'a, 'state, 'd, ID, R, Q, F>
where
R: Runtime<'d, Target = Target<'d, ID>>,
Q: state::Transitions<conn::Id<'d, ID>>,
F: rules::Policy,
{
fn built(mut self, build: <R::Build as body::Build<'d>>::Output) {
let call = identify(self.drive.conn, self.stream);
state::Transitions::started(self.drive.mode, call);
let result = match self
.drive
.tasks
.vacant(self.drive.index, self.drive.conn, self.stream)
{
Ok(vacant) => vacant
.try_insert(|target| {
Runtime::try_built(
self.drive.router.as_mut(),
build,
target,
owner::Owner::from(self.drive.conn),
self.drive.parent,
)
})
.map_err(BranchError::Second),
Err(error) => Err(BranchError::First(error)),
};
if let Err(cause) = result {
let code = match &cause {
BranchError::First(error) => error.code(),
BranchError::Second(error) => ingress::errors::reject_code(R::rejection(error)),
};
self.drive.reset(self.stream, code);
return;
}
self.drive.mode.observe(life::Event::TaskAdmitted(call));
}
fn sync(self, input: request::Admitted<exec::Sync, R::Prepared, Buffer<'d>>) {
self.complete(input, |mut this, input| {
let call = identify(this.drive.conn, this.stream);
this.drive.mode.observe(life::Event::BuildReady(call));
this.drive
.queue(this.stream, response::Response::Sync(input));
});
}
fn task(self, input: request::Admitted<exec::Task, R::Prepared, Buffer<'d>>) {
self.complete(input, |mut this, input| {
let call = identify(this.drive.conn, this.stream);
this.drive.mode.observe(life::Event::BuildReady(call));
let result =
match this
.drive
.tasks
.vacant(this.drive.index, this.drive.conn, this.stream)
{
Ok(vacant) => vacant
.try_insert(|target| {
Runtime::try_dispatch(
this.drive.router.as_mut(),
input,
target,
owner::Owner::from(this.drive.conn),
this.drive.parent,
)
})
.map_err(BranchError::Second),
Err(error) => Err(BranchError::First(error)),
};
if let Err(cause) = result {
let code = match &cause {
BranchError::First(error) => error.code(),
BranchError::Second(error) => ingress::errors::reject_code(R::rejection(error)),
};
this.drive.reset(this.stream, code);
return;
}
this.drive.mode.observe(life::Event::TaskAdmitted(call));
});
}
fn complete<K>(
mut self,
input: request::Admitted<K, R::Prepared, Buffer<'d>>,
ready: impl FnOnce(Self, request::Ready<K, R::Prepared, owned::Segments<'d>>),
) {
let call = identify(self.drive.conn, self.stream);
let result = self.drive.state.body_credit.scope(|mut ledger| {
let input = input.try_map_body(|body| {
let body = unsafe { ledger.bind(body) };
body.try_finish(&mut ledger, self.drive.mode.body(call))
});
match input {
Ok(input) => Ok(input.ready()),
Err(failure) => Err(payload::release_rejected(
failure,
&mut ledger,
&mut self.drive.mode.body(call),
)),
}
});
match result {
Ok(input) => ready(self, input),
Err(code) => self.drive.reset(self.stream, code),
}
}
}