Skip to main content

sark_http/payload/response/dispatch/
mod.rs

1use o3::buffer::resident::bound;
2
3use crate::{
4    payload,
5    payload::{
6        fixed::Body,
7        response::{
8            self, bounded, exact,
9            headers::{self, set},
10            status::Code,
11        },
12    },
13};
14
15pub mod chunk;
16
17pub enum Sync {}
18pub enum Polled {}
19pub enum Never {}
20
21pub trait Dispatch {
22    type Output<'d, E: Sink<'d>, S>;
23
24    fn fold<'d, E: Sink<'d>, S, T>(
25        output: Self::Output<'d, E, S>,
26        sync: impl FnOnce(E::Output) -> T,
27        stream: impl FnOnce(E::Stream<S>) -> T,
28    ) -> T;
29}
30
31impl Dispatch for Sync {
32    type Output<'d, E: Sink<'d>, S> = E::Output;
33
34    fn fold<'d, E: Sink<'d>, S, T>(
35        output: Self::Output<'d, E, S>,
36        sync: impl FnOnce(E::Output) -> T,
37        _: impl FnOnce(E::Stream<S>) -> T,
38    ) -> T {
39        sync(output)
40    }
41}
42
43impl Dispatch for Polled {
44    type Output<'d, E: Sink<'d>, S> = E::Stream<S>;
45
46    fn fold<'d, E: Sink<'d>, S, T>(
47        output: Self::Output<'d, E, S>,
48        _: impl FnOnce(E::Output) -> T,
49        stream: impl FnOnce(E::Stream<S>) -> T,
50    ) -> T {
51        stream(output)
52    }
53}
54
55/// One of two synchronous response shapes without allocation or type erasure.
56pub enum Either<L, R> {
57    Left(L),
58    Right(R),
59}
60
61/// Response writes retain only the destination's storage lifetime.
62pub trait Accept<'d>: Sized {
63    type Output;
64    type Error;
65
66    fn fixed<H, B>(self, status: Code, headers: H, body: B) -> Result<Self::Output, Self::Error>
67    where
68        H: headers::Source,
69        B: response::Body<'d>;
70
71    fn statics<'body, H>(
72        self,
73        status: Code,
74        headers: H,
75        body: Body<'body>,
76    ) -> Result<Self::Output, Self::Error>
77    where
78        H: headers::Source,
79        'body: 'd,
80    {
81        self.fixed(status, headers, body)
82    }
83
84    fn exact<H, B>(self, status: Code, headers: H, body: B) -> Result<Self::Output, Self::Error>
85    where
86        H: headers::Source,
87        B: exact::TryBody;
88
89    fn bounded<H, B>(self, status: Code, headers: H, body: B) -> Result<Self::Output, Self::Error>
90    where
91        H: headers::Source,
92        B: bounded::Body;
93}
94
95/// A destination that also transfers ownership of a body stream.
96pub trait Sink<'d>: Accept<'d> {
97    type Stream<S>;
98
99    fn stream<H, S>(
100        self,
101        status: Code,
102        headers: H,
103        stream: S,
104    ) -> Result<Self::Stream<S>, Self::Error>
105    where
106        H: headers::Source;
107}
108
109pub trait Emit<'req, 'd>: Sized {
110    type Kind: Dispatch;
111    type Stream;
112    type Bound: bound::Bound + 'd;
113
114    const BODY: payload::Kind;
115
116    fn emit<S>(
117        self,
118        sink: S,
119    ) -> Result<<Self::Kind as Dispatch>::Output<'d, S, Self::Stream>, S::Error>
120    where
121        S: Sink<'d>;
122}
123
124pub trait IntoOutput<'req, 'd>: Sized {
125    type Output: Emit<'req, 'd>;
126
127    fn into_output(self) -> Self::Output;
128}
129
130#[doc(hidden)]
131pub trait Complete<'req, 'd>: Sized {
132    type Bound: bound::Bound + 'd;
133
134    const BODY: payload::Kind;
135
136    fn complete<S>(self, sink: S) -> Result<S::Output, S::Error>
137    where
138        S: Accept<'d>;
139}
140
141impl<'req, 'd, T: Complete<'req, 'd>> Emit<'req, 'd> for T {
142    type Kind = Sync;
143    type Stream = Never;
144    type Bound = T::Bound;
145
146    const BODY: payload::Kind = T::BODY;
147
148    fn emit<S: Sink<'d>>(self, sink: S) -> Result<S::Output, S::Error> {
149        self.complete(sink)
150    }
151}
152
153/// Response behavior that cannot produce a polled body stream.
154///
155pub trait Immediate<'req, 'd>: Sized {
156    type Bound: bound::Bound + 'd;
157
158    fn emit<S>(self, sink: S) -> Result<S::Output, S::Error>
159    where
160        S: Accept<'d>;
161}
162
163impl<'req, 'd, T> Immediate<'req, 'd> for T
164where
165    T: IntoOutput<'req, 'd>,
166    T::Output: Complete<'req, 'd>,
167{
168    type Bound = <T::Output as Complete<'req, 'd>>::Bound;
169
170    fn emit<S>(self, sink: S) -> Result<S::Output, S::Error>
171    where
172        S: Accept<'d>,
173    {
174        self.into_output().complete(sink)
175    }
176}
177
178impl<'req, 'd, L, R> IntoOutput<'req, 'd> for Either<L, R>
179where
180    L: Immediate<'req, 'd>,
181    R: Immediate<'req, 'd>,
182{
183    type Output = Self;
184
185    fn into_output(self) -> Self::Output {
186        self
187    }
188}
189
190impl<'req, 'd, T, E> IntoOutput<'req, 'd> for Result<T, E>
191where
192    T: Immediate<'req, 'd>,
193    E: Immediate<'req, 'd>,
194{
195    type Output = Either<T, E>;
196
197    fn into_output(self) -> Self::Output {
198        match self {
199            Ok(output) => Either::Left(output),
200            Err(error) => Either::Right(error),
201        }
202    }
203}
204
205impl<'req, 'd, L, R> Complete<'req, 'd> for Either<L, R>
206where
207    L: Immediate<'req, 'd>,
208    R: Immediate<'req, 'd>,
209{
210    type Bound = bound::Max<L::Bound, R::Bound>;
211
212    const BODY: payload::Kind = payload::Kind::Inline;
213
214    fn complete<S>(self, sink: S) -> Result<S::Output, S::Error>
215    where
216        S: Accept<'d>,
217    {
218        match self {
219            Self::Left(output) => output.emit(sink),
220            Self::Right(output) => output.emit(sink),
221        }
222    }
223}
224
225pub struct Stream<'req, S, const N: usize = 0> {
226    status: Code,
227    headers: set::Set<'req, N>,
228    stream: S,
229}
230
231impl<S, const N: usize> Stream<'_, S, N> {
232    pub fn with_status(mut self, status: Code) -> Self {
233        self.status = status;
234        self
235    }
236}
237
238impl<'req, S> Stream<'req, S, 0> {
239    pub fn new(stream: S) -> Self {
240        Self {
241            status: Code::OK,
242            headers: set::Set::new(),
243            stream,
244        }
245    }
246
247    pub fn headers<const N: usize>(self, headers: set::Set<'req, N>) -> Stream<'req, S, N> {
248        Stream {
249            status: self.status,
250            headers,
251            stream: self.stream,
252        }
253    }
254}
255
256impl<'req, 'd, 'head: 'req, S, const N: usize> IntoOutput<'req, 'd> for Stream<'head, S, N> {
257    type Output = Self;
258
259    fn into_output(self) -> Self::Output {
260        self
261    }
262}
263
264impl<'req, 'd, 'head: 'req, S, const N: usize> Emit<'req, 'd> for Stream<'head, S, N> {
265    type Kind = Polled;
266    type Stream = S;
267    type Bound = bound::Unbounded;
268
269    const BODY: payload::Kind = payload::Kind::Stream;
270
271    fn emit<E>(self, sink: E) -> Result<E::Stream<S>, E::Error>
272    where
273        E: Sink<'d>,
274    {
275        let Self {
276            status,
277            headers,
278            stream,
279        } = self;
280        sink.stream(status, headers, stream)
281    }
282}