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