Skip to main content

sark_core/decode/request/
mod.rs

1use core::{convert::Infallible, marker::PhantomData};
2
3use o3::mem::Rejected;
4use request::body::Source;
5use sark_http::{method::Method, owner::handoff::input, payload::owned, request};
6
7use crate::{
8    body,
9    decode::{Decode, Scoped, exec, state},
10    manifold::stream::Boundary,
11};
12
13pub mod admit;
14mod project;
15
16pub use project::Project;
17
18/// A selected request whose guard has admitted it.
19#[repr(C)]
20pub struct Admitted<K, P, B> {
21    prepared: P,
22    body: B,
23    kind: PhantomData<fn() -> K>,
24}
25
26impl<K, P, B> Admitted<K, P, B> {
27    pub(in crate::decode) const fn new(prepared: P, body: B) -> Self {
28        Self {
29            prepared,
30            body,
31            kind: PhantomData,
32        }
33    }
34
35    pub const fn body(&self) -> &B {
36        &self.body
37    }
38
39    pub const fn body_mut(&mut self) -> &mut B {
40        &mut self.body
41    }
42
43    pub fn into_body(self) -> B {
44        self.body
45    }
46
47    pub fn into_parts(self) -> (P, B) {
48        (self.prepared, self.body)
49    }
50
51    pub fn try_map_body<T, E>(
52        self,
53        f: impl FnOnce(B) -> Result<T, E>,
54    ) -> Result<Admitted<K, P, T>, Failure<K, P, E>> {
55        match f(self.body) {
56            Ok(body) => Ok(Admitted::new(self.prepared, body)),
57            Err(error) => Err(Failure::new(error, self.prepared)),
58        }
59    }
60}
61
62impl<P, B> Admitted<exec::Duplex, P, B> {
63    pub fn build<T, E>(self, f: impl FnOnce(P) -> Result<T, E>) -> Result<(T, B), (E, B)> {
64        match f(self.prepared) {
65            Ok(value) => Ok((value, self.body)),
66            Err(error) => Err((error, self.body)),
67        }
68    }
69}
70
71impl<K, P, S> Admitted<K, P, body::Body<S>> {
72    pub fn ready(self) -> Ready<K, P, S> {
73        Ready::new(self.prepared, self.body)
74    }
75}
76
77/// A selected, admitted request coupled to its completed body.
78#[must_use]
79#[repr(C)]
80#[derive(Debug)]
81pub struct Ready<K, P, S> {
82    prepared: P,
83    body: body::Body<S>,
84    kind: PhantomData<fn() -> K>,
85}
86
87impl<K, P, S> Ready<K, P, S> {
88    pub(in crate::decode) const fn new(prepared: P, body: body::Body<S>) -> Self {
89        Self {
90            prepared,
91            body,
92            kind: PhantomData,
93        }
94    }
95
96    pub const fn body(&self) -> &body::Body<S> {
97        &self.body
98    }
99
100    pub const fn prepared(&self) -> &P {
101        &self.prepared
102    }
103
104    pub fn into_body(self) -> body::Body<S> {
105        self.body
106    }
107}
108
109impl<P, S> Ready<exec::Task, P, S> {
110    pub fn into_parts(self) -> (P, body::Body<S>) {
111        (self.prepared, self.body)
112    }
113}
114
115impl<P, S> Ready<exec::Sync, P, S> {
116    /// Borrows this completed body only for its matching selected request.
117    ///
118    pub fn try_project<'d, D, T, F>(
119        self,
120        decoder: &D,
121        f: F,
122    ) -> Result<(T, body::Body<S>), Project<exec::Sync, P, S>>
123    where
124        S: Source<'d>,
125        D: Decode<Prepared = P>,
126        F: for<'a> FnOnce(&D, Scoped<'a, 'd, D>) -> T,
127    {
128        let Self {
129            prepared, mut body, ..
130        } = self;
131        let output = match decoder.try_project(prepared, body.input(), |view| f(decoder, view)) {
132            Ok((output, ())) => output,
133            Err(failure) => {
134                let ((prepared, _), error) = failure.into_parts();
135                return Err(Project::new(error, Ready::new(prepared, body)));
136            }
137        };
138        Ok((output, body))
139    }
140}
141
142impl<'d, P> Ready<exec::Sync, P, owned::Segments<'d>> {
143    /// Keeps response selection and the matching final owner in one generative scope.
144    pub fn with_input<T>(
145        self,
146        run: impl for<'owner> FnOnce(P, body::Input<input::Input<'owner, 'd>>) -> T,
147    ) -> T {
148        let Self { prepared, body, .. } = self;
149        let (source, len) = body.into_parts();
150        input::Input::with(source, |source| run(prepared, body::Input { source, len }))
151    }
152}
153
154/// Failed body transformation that returns the exact selected request owner.
155#[must_use]
156#[derive(Debug)]
157pub struct Failure<K, P, E> {
158    error: E,
159    prepared: P,
160    kind: PhantomData<fn() -> K>,
161}
162
163impl<K, P, E> Failure<K, P, E> {
164    const fn new(error: E, prepared: P) -> Self {
165        Self {
166            error,
167            prepared,
168            kind: PhantomData,
169        }
170    }
171
172    pub const fn error(&self) -> &E {
173        &self.error
174    }
175
176    /// Ends the rejected request owner and returns the transformation failure.
177    pub fn discard(self) -> E {
178        self.error
179    }
180
181    pub fn into_parts(self) -> (E, P) {
182        (self.error, self.prepared)
183    }
184}
185
186pub enum Body<O, F = O> {
187    Open(O),
188    Finished(F),
189}
190
191/// A routed request proved not to require response-capable admission.
192#[must_use]
193pub struct Plain<T>(T);
194
195impl<T> Plain<T> {
196    #[doc(hidden)]
197    pub const fn new(state: T) -> Self {
198        Self(state)
199    }
200
201    pub fn into_state(self) -> T {
202        self.0
203    }
204}
205
206/// A routed request carrying the exact method required by its selected guard.
207#[must_use]
208pub struct Guarded<T> {
209    state: T,
210    method: Method,
211}
212
213impl<T> Guarded<T> {
214    #[doc(hidden)]
215    pub const fn new(state: T, method: Method) -> Self {
216        Self { state, method }
217    }
218
219    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Guarded<U> {
220        Guarded::new(f(self.state), self.method)
221    }
222
223    pub fn fold<U>(self, f: impl FnOnce(T) -> U) -> U {
224        f(self.state)
225    }
226
227    pub fn state_mut(&mut self) -> &mut T {
228        &mut self.state
229    }
230
231    pub fn into_parts(self) -> (T, Method) {
232        (self.state, self.method)
233    }
234}
235
236/// Route-selected admission contract for an application containing both
237/// guarded and unguarded routes.
238#[must_use]
239pub enum Start<U, G> {
240    Plain(Plain<U>),
241    Guarded(Guarded<G>),
242}
243
244impl<U, G> Start<U, G> {
245    #[doc(hidden)]
246    pub const fn plain(state: U) -> Self {
247        Self::Plain(Plain::new(state))
248    }
249
250    #[doc(hidden)]
251    pub const fn guarded(state: G, method: Method) -> Self {
252        Self::Guarded(Guarded::new(state, method))
253    }
254}
255
256/// Generated route family that owns a selected guarded request.
257pub trait Selection<P> {
258    type Guard: state::Family<P>;
259    type Routed: state::Flow<P, state::Routed, Family = Self::Guard>;
260    type Deferred<T>;
261}
262
263impl<P, U> Selection<P> for Plain<U>
264where
265    U: state::Flow<P, state::Routed>,
266{
267    type Guard = U::Family;
268    type Routed = U;
269    type Deferred<T> = Infallible;
270}
271
272impl<P, G> Selection<P> for Guarded<G>
273where
274    G: state::Flow<P, state::Routed>,
275{
276    type Guard = G::Family;
277    type Routed = G;
278    type Deferred<T> = T;
279}
280
281impl<P, U, G> Selection<P> for Start<U, G>
282where
283    G: state::Flow<P, state::Routed>,
284{
285    type Guard = G::Family;
286    type Routed = G;
287    type Deferred<T> = T;
288}
289
290/// Selected head that consumes its body plan into an executable request.
291pub trait Head: Sized {
292    type Prepared: Prepared;
293    type Start: Selection<Self::Prepared>;
294
295    fn try_start(
296        self,
297        limit: usize,
298        boundary: Boundary,
299    ) -> Result<Self::Start, Rejected<Self, body::Error>>;
300}
301
302/// Request facts that remain after body-plan admission.
303pub trait Prepared: Sized {
304    type Execution: exec::Set;
305    type Family: state::Family<Self>;
306}
307
308/// A prepared request whose generated family contains only synchronous arms.
309pub trait Synchronous:
310    Prepared<Execution = exec::Sync, Family: state::Homogeneous<Self, exec::Sync>>
311{
312}
313
314impl<P> Synchronous for P
315where
316    P: Prepared<Execution = exec::Sync>,
317    P::Family: state::Homogeneous<P, exec::Sync>,
318{
319}
320
321const _: () = {
322    type Body = body::Body<()>;
323    type ReadyProof = Ready<exec::Sync, (), ()>;
324    assert!(core::mem::size_of::<ReadyProof>() == core::mem::size_of::<Body>());
325    assert!(core::mem::align_of::<ReadyProof>() == core::mem::align_of::<Body>());
326    assert!(
327        core::mem::size_of::<Admitted<exec::Task, usize, usize>>()
328            == 2 * core::mem::size_of::<usize>()
329    );
330};