Skip to main content

alux_http/
output.rs

1//! States what an endpoint answers with, before any framework can convert it.
2
3use core::marker::PhantomData;
4
5/// Transforms an inferred handler result into its portable API output.
6///
7/// Converter families are selected from an endpoint's output kind. The handler
8/// result supplies `From`, so API declarations never repeat it.
9pub trait OutputAlg<From> {
10    /// The transport value produced from the semantic handler result.
11    type Output;
12
13    /// Converts a handler result into the declared API output.
14    fn output(from: From) -> Self::Output;
15}
16
17/// Resolves a portable output kind through an interpreter.
18pub trait OutputKindAlg<Interpreter: ?Sized, From> {
19    /// The concrete converter chosen by `Interpreter` for this output kind.
20    ///
21    /// That the converter reads `From` is required where the endpoint is compiled rather than
22    /// here, so a kind may answer for some results and not others. An endpoint stating no body
23    /// converts a handler that returns nothing, and an endpoint stating a failure converts a
24    /// handler that can fail.
25    type Transform;
26}
27
28macro_rules! output_kinds {
29    ($($declaration:ident => $kind:ident, $alg:ident, $selected:ident, $meaning:literal),+ $(,)?) => {
30        $(
31            #[doc = concat!("Selects the converter used for ", $meaning, " API outputs.")]
32            pub trait $alg {
33                #[doc = concat!("The ", $meaning, " converter selected for `From`.")]
34                type $selected<From>;
35            }
36
37            #[doc = concat!("Selects ", $meaning, " output semantics.")]
38            #[derive(Debug, Default)]
39            pub struct $kind;
40
41            impl<Interpreter, From> OutputKindAlg<Interpreter, From> for $kind
42            where
43                Interpreter: $alg + ?Sized,
44            {
45                type Transform = Interpreter::$selected<From>;
46            }
47        )+
48    };
49}
50
51with_output_kinds!(output_kinds);
52
53/// Selects the converter used to answer with a declared status.
54pub trait StatusOutAlg {
55    /// The converter answering with `CODE` and the body `Inner` states.
56    type Status<Inner, const CODE: u16>;
57}
58
59/// Answers with `CODE` and the body `Kind` states.
60///
61/// The status is part of what an endpoint is declared to answer, so it is stated once in the
62/// program rather than chosen inside a handler.
63#[derive(Debug, Default)]
64pub struct StatusOut<Kind, const CODE: u16>(PhantomData<Kind>);
65
66impl<Interpreter, From, Kind, const CODE: u16> OutputKindAlg<Interpreter, From> for StatusOut<Kind, CODE>
67where
68    Interpreter: StatusOutAlg + ?Sized,
69    Kind: OutputKindAlg<Interpreter, From>,
70{
71    type Transform = Interpreter::Status<Kind::Transform, CODE>;
72}
73
74/// Selects the converter used to answer with a header beside a body.
75pub trait HeaderOutAlg {
76    /// The converter writing `Name` beside the body `Inner` states.
77    type Header<Inner, Name>;
78}
79
80/// Answers with a header the handler states, beside the body `Kind` states.
81///
82/// The handler answers with the header's value and the body, in that order, because a header whose
83/// value an endpoint cannot know is a header only the handler can state. Which header it is, is
84/// stated here: a name is all a header is to a program.
85#[derive(Debug, Default)]
86pub struct HeaderOut<Kind, Name>(PhantomData<fn(Kind, Name)>);
87
88impl<Interpreter, Value, Rest, Kind, Name> OutputKindAlg<Interpreter, (Value, Rest)> for HeaderOut<Kind, Name>
89where
90    Interpreter: HeaderOutAlg + ?Sized,
91    Kind: OutputKindAlg<Interpreter, Rest>,
92{
93    type Transform = Interpreter::Header<Kind::Transform, Name>;
94}
95
96/// Selects the converter used for a handler that can fail.
97pub trait ResultOutAlg {
98    /// The converter answering with `Inner` on success and with what `Error` means otherwise.
99    type Result<Inner, Error>;
100}
101
102/// Answers with `Kind` when the handler succeeded, and with what its failure means otherwise.
103///
104/// A handler that can fail returns a `Result`, so this kind reads one. What a failure means is
105/// stated by [`HttpErrorAlg`](crate::HttpErrorAlg) on the error itself.
106#[derive(Debug, Default)]
107pub struct ResultOut<Kind>(PhantomData<Kind>);
108
109impl<Interpreter, Kind, Value, Error> OutputKindAlg<Interpreter, Result<Value, Error>> for ResultOut<Kind>
110where
111    Interpreter: ResultOutAlg + ?Sized,
112    Kind: OutputKindAlg<Interpreter, Value>,
113{
114    type Transform = Interpreter::Result<Kind::Transform, Error>;
115}