Skip to main content

sark_core/manifold/task/
response.rs

1use std::convert::Infallible;
2
3pub type Stream<'d, R, A> =
4    <<<R as route::Task<'d, A>>::Output as dispatch::IntoOutput<'d, 'd>>::Output as dispatch::Emit<
5        'd,
6        'd,
7    >>::Stream;
8
9pub type Emitted<'d, S, B> = Result<
10    (
11        <S as decode::Encode<'d, 'd>>::Prepared,
12        Option<B>,
13        life::Outcome,
14    ),
15    (
16        <S as decode::Encode<'d, 'd>>::Error,
17        <S as decode::Cancel>::Target,
18    ),
19>;
20
21pub type Prepared<'d, S> = Result<
22    (<S as decode::Encode<'d, 'd>>::Prepared, State),
23    (
24        <S as decode::Encode<'d, 'd>>::Error,
25        <S as decode::Cancel>::Target,
26    ),
27>;
28
29pub type Complete<'d, S> = Result<
30    (<S as decode::Encode<'d, 'd>>::Prepared, life::Outcome),
31    (
32        <S as decode::Encode<'d, 'd>>::Error,
33        <S as decode::Cancel>::Target,
34    ),
35>;
36
37use sark_http::{
38    payload::response::{Response, dispatch, dispatch::chunk::Chunk},
39    request::Id,
40};
41
42use crate::{
43    decode, life,
44    route::{self, Reject},
45};
46
47pub enum Outcome<T> {
48    Response(T),
49    Rejected(Reject),
50}
51
52pub enum Event<'d, E> {
53    /// The initial response is held for emission. A polled task yields this exactly once,
54    /// before body events; it cannot publish informational heads or trailers.
55    Head,
56    Chunk(Chunk<'d>),
57    Failed(E),
58    /// The source ended and its runtime task slot and quota were released before handoff.
59    End,
60}
61
62pub enum State {
63    Complete(life::Outcome),
64    Streaming,
65}
66
67pub enum Access<T> {
68    /// No live stream source exists for this task.
69    Absent,
70    /// The stream exists but has no held value for this operation.
71    Active,
72    Ready(T),
73}
74
75/// Route-specific result retained by one generated task.
76pub struct Output<'d, R: route::Task<'d, A>, A> {
77    id: Id<'d>,
78    outcome: Outcome<R::Output>,
79}
80
81impl<'d, R: route::Task<'d, A>, A> Output<'d, R, A> {
82    pub const fn response(id: Id<'d>, response: R::Output) -> Self {
83        Self {
84            id,
85            outcome: Outcome::Response(response),
86        }
87    }
88
89    pub const fn rejected(id: Id<'d>, reject: Reject) -> Self {
90        Self {
91            id,
92            outcome: Outcome::Rejected(reject),
93        }
94    }
95
96    pub fn into_parts(self) -> (Id<'d>, Outcome<R::Output>) {
97        (self.id, self.outcome)
98    }
99
100    pub fn emit<S>(self, make: impl FnOnce(Id<'d>) -> S) -> Emitted<'d, S, Stream<'d, R, A>>
101    where
102        S: decode::Streaming<'d, 'd>,
103    {
104        let sink = make(self.id);
105        match self.outcome {
106            Outcome::Response(response) => {
107                let emitted =
108                    dispatch::Emit::emit(dispatch::IntoOutput::into_output(response), sink)?;
109                let (prepared, stream) =
110                    <<<R::Output as dispatch::IntoOutput<'d, 'd>>::Output as dispatch::Emit<
111                        'd,
112                        'd,
113                    >>::Kind as dispatch::Dispatch>::fold::<S, Stream<'d, R, A>, _>(
114                        emitted,
115                        |prepared| (prepared, None),
116                        S::split_stream,
117                    );
118                Ok((prepared, stream, life::Outcome::Completed))
119            }
120            Outcome::Rejected(reject) => {
121                let prepared = dispatch::Immediate::emit(Response::new(reject.status()), sink)?;
122                Ok((prepared, None, life::Outcome::Rejected))
123            }
124        }
125    }
126}
127/// A completed fixed response whose task slot has already been released.
128pub trait Completion<'d>: Sized {
129    fn emit<E: decode::Encode<'d, 'd>>(self, make: impl FnOnce(Id<'d>) -> E) -> Complete<'d, E>;
130}
131
132impl<'d, R, A> Completion<'d> for Output<'d, R, A>
133where
134    R: route::Task<'d, A>,
135    <R::Output as dispatch::IntoOutput<'d, 'd>>::Output: dispatch::Complete<'d, 'd>,
136{
137    fn emit<E: decode::Encode<'d, 'd>>(self, make: impl FnOnce(Id<'d>) -> E) -> Complete<'d, E> {
138        let sink = make(self.id);
139        let (prepared, outcome) = match self.outcome {
140            Outcome::Response(response) => (
141                dispatch::Immediate::emit(response, sink)?,
142                life::Outcome::Completed,
143            ),
144            Outcome::Rejected(reject) => (
145                dispatch::Immediate::emit(Response::new(reject.status()), sink)?,
146                life::Outcome::Rejected,
147            ),
148        };
149        Ok((prepared, outcome))
150    }
151}
152
153impl<'d> Completion<'d> for Infallible {
154    fn emit<E: decode::Encode<'d, 'd>>(self, _: impl FnOnce(Id<'d>) -> E) -> Complete<'d, E> {
155        match self {}
156    }
157}