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}