1use core::convert::Infallible;
3use std::ops::ControlFlow;
4
5use o3::buffer::{bytes::scope, pool, resident::bound, storage::Shared};
6use sark_http::{
7 field::{
8 metadata::{
9 packed,
10 section::{
11 self, rules,
12 state::{RetainedHead, Selected},
13 storage::Fault,
14 },
15 },
16 text,
17 },
18 method,
19 owner::handoff::{self, input::Bound, stage},
20 payload::response::{
21 dispatch::{Accept, Sink},
22 status::Code,
23 },
24};
25
26use crate::{body, decode::state::admit, request::frame::proof, route, route::field::header};
27
28mod call;
29pub mod dispatch;
30pub mod exec;
31pub mod request;
32pub mod state;
33
34pub use call::Call;
35
36#[repr(C)]
38pub struct Scoped<'req, 'd: 'req, D: Decode + ?Sized, Q: stage::Proof = ()>(
39 D::Projected<'req, 'd>,
40 handoff::Slot<'req, 'd, (), Bound<'req, 'd, Q>>,
41);
42
43impl<'req, 'd: 'req, D: Decode + ?Sized, Q: stage::Proof> Scoped<'req, 'd, D, Q> {
44 #[doc(hidden)]
45 pub const fn new(
46 value: D::Projected<'req, 'd>,
47 source: handoff::Slot<'req, 'd, (), Bound<'req, 'd, Q>>,
48 ) -> Self {
49 Self(value, source)
50 }
51
52 pub fn into_inner(self) -> D::Projected<'req, 'd> {
53 self.0
54 }
55
56 pub fn into_parts(
57 self,
58 ) -> (
59 D::Projected<'req, 'd>,
60 handoff::Slot<'req, 'd, (), Bound<'req, 'd, Q>>,
61 ) {
62 (self.0, self.1)
63 }
64}
65
66pub trait Lineage<'id>: Sized {
68 type Output;
69
70 fn resolve_head<O: Into<scope::Owner<'id, Shared>>, P: proof::Proof>(
71 self,
72 head: crate::request::Head<O, P>,
73 ) -> Self::Output;
74}
75
76pub trait Cancel {
78 type Target;
79
80 fn cancel(self) -> Self::Target;
81}
82
83pub trait Encode<'req, 'd: 'req>:
84 Cancel
85 + Accept<
86 'd,
87 Output = <Self as Encode<'req, 'd>>::Prepared,
88 Error = (<Self as Encode<'req, 'd>>::Error, Self::Target),
89 >
90{
91 type Error;
92 type Prepared;
93 type Pending<'id>: Lineage<'id, Output = Self::Prepared>;
94 type Head<'a, 'id>: Accept<
95 'd,
96 Output = Self::Pending<'id>,
97 Error = (<Self as Encode<'req, 'd>>::Error, Self::Target),
98 > + Cancel<Target = Self::Target>;
99
100 fn begin_head<'a, 'id>(self, head: scope::View<'a, 'id>) -> Self::Head<'a, 'id>;
101}
102
103pub trait Streaming<'req, 'd: 'req>: Encode<'req, 'd> + Sink<'d> {
105 fn split_stream<S>(output: Self::Stream<S>) -> (Self::Prepared, Option<S>);
106}
107
108#[derive(PartialEq, Eq)]
110#[repr(u8)]
111#[derive(Debug)]
112pub enum HeadError<C = Infallible> {
113 BadRequest,
114 ContentLength(text::IntError),
115 Method(method::Error),
116 Bind(crate::request::BindError),
117 Storage(Fault),
118 Slot(header::Tag),
119 NotFound,
120 Schema(C),
121}
122
123impl<C> HeadError<C> {
124 pub const fn status(&self) -> Code {
125 match self {
126 Self::BadRequest
127 | Self::ContentLength(_)
128 | Self::Method(method::Error::Syntax(_))
129 | Self::Bind(_)
130 | Self::Storage(_)
131 | Self::Slot(_)
132 | Self::Schema(_) => Code::BAD_REQUEST,
133 Self::NotFound => Code::NOT_FOUND,
134 Self::Method(method::Error::Allocation(_)) => Code::INTERNAL_SERVER_ERROR,
135 }
136 }
137}
138
139pub trait Decode {
140 type Prepared: request::Prepared;
141 type Routes: state::Family<Self::Prepared>;
142 type Head: request::Head<
143 Prepared = Self::Prepared,
144 Start: request::Selection<
145 Self::Prepared,
146 Guard = Self::Routes,
147 Routed = <Self::Routes as state::Family<Self::Prepared>>::State<state::Routed>,
148 >,
149 >;
150 type Plan: rules::Policy;
151 type Cause;
152 type Error<'req>;
153 type Projected<'req, 'd>
154 where
155 'd: 'req;
156
157 type Egress<'d>: bound::Bound;
159
160 fn reject<'req>(error: Self::Error<'req>) -> route::Reject;
161
162 fn try_full(
164 &self,
165 head: RetainedHead<packed::Decoded, Selected<rules::RetainRaw>>,
166 ) -> Result<Self::Head, HeadError<Self::Cause>>;
167
168 fn try_head(
169 &self,
170 head: RetainedHead<<Self::Plan as section::Policy>::Block, Selected<Self::Plan>>,
171 ) -> Result<Self::Head, HeadError<Self::Cause>>;
172
173 fn try_project<'d, I, T, F>(
174 &self,
175 prepared: Self::Prepared,
176 body: body::Input<I>,
177 project: F,
178 ) -> body::Projection<T, I::Owner, (Self::Prepared, body::Input<I>)>
179 where
180 I: handoff::Project<'d>,
181 F: for<'req> FnOnce(Scoped<'req, 'd, Self, I::Proof>) -> T;
182
183 fn try_dispatch<'req, 'd, E: Encode<'req, 'd>>(
184 &self,
185 request: Self::Projected<'req, 'd>,
186 encoder: E,
187 ) -> Dispatched<'req, 'd, E, Self::Error<'req>>
188 where
189 'd: 'req;
190}
191
192pub trait Full: Decode {
194 fn try_prefixed<const PREFIX: usize>(
195 &self,
196 head: RetainedHead<packed::Decoded<pool::Span, PREFIX>, Selected<rules::RetainRaw<PREFIX>>>,
197 ) -> Result<Self::Head, HeadError<Self::Cause>>;
198}
199
200pub trait Guarded: Decode {
202 fn try_admit<'req, 'd: 'req, E, F, G, V>(
203 &self,
204 request: request::Guarded<<Self::Routes as state::Family<Self::Prepared>>::State<F>>,
205 encoder: E,
206 visit: &mut V,
207 ) -> Admission<'req, 'd, Self, E, F, G, V>
208 where
209 E: Encode<'req, 'd>,
210 F: state::Set,
211 G: state::Set,
212 V: admit::TryVisit<Self::Prepared, F, G, <E as Encode<'req, 'd>>::Error>;
213}
214
215type Dispatched<'req, 'd, E, F> = Result<
216 <E as Encode<'req, 'd>>::Prepared,
217 (
218 dispatch::Error<<E as Encode<'req, 'd>>::Error, Infallible, F>,
219 <E as Cancel>::Target,
220 ),
221>;
222
223type Admission<'req, 'd, D, E, F, G, V> = ControlFlow<
224 <V as admit::TryVisit<<D as Decode>::Prepared, F, G, <E as Encode<'req, 'd>>::Error>>::Break<
225 <E as Encode<'req, 'd>>::Prepared,
226 <E as Cancel>::Target,
227 >,
228 <<<D as Decode>::Prepared as request::Prepared>::Family as state::Family<
229 <D as Decode>::Prepared,
230 >>::State<G>,
231>;