Skip to main content

alux_http_text/
output.rs

1//! Names the output conversion an endpoint selects, without converting anything.
2
3use crate::TextHandlerImpl;
4use alux_http::{
5    BytesOutAlg, EmptyOutAlg, FileOutAlg, HeaderOutAlg, HtmlOutAlg, HttpErrorAlg, HttpStatus, JsonOutAlg, OutputAlg,
6    RedirectOutAlg, ResultOutAlg, StatusOutAlg, StreamOutAlg, TextOutAlg,
7};
8use core::marker::PhantomData;
9
10macro_rules! text_outputs {
11    ($($output:ident => $alg:ident, $selected:ident, $meaning:literal),+ $(,)?) => {
12        $(
13            #[doc = concat!("Interprets ", $meaning, " output selection in text descriptions.")]
14            pub struct $output;
15
16            impl<From> OutputAlg<From> for $output {
17                type Output = From;
18
19                fn output(from: From) -> From {
20                    from
21                }
22            }
23
24            impl $alg for TextHandlerImpl {
25                type $selected<From> = $output;
26            }
27        )+
28    };
29}
30
31text_outputs! {
32    TextJsonOutput     => JsonOutAlg, Json, "JSON",
33    TextFileOutput     => FileOutAlg, File, "streamed-file",
34    TextTextOutput     => TextOutAlg, Text, "plain-text",
35    TextHtmlOutput     => HtmlOutAlg, Html, "HTML",
36    TextBytesOutput    => BytesOutAlg, Bytes, "raw-byte",
37    TextRedirectOutput => RedirectOutAlg, Redirect, "redirect",
38    TextStreamOutput   => StreamOutAlg, Stream, "streamed",
39}
40
41/// Interprets empty output selection in text descriptions.
42///
43/// An endpoint stating no body converts a handler that returns nothing, so this reads `()` and
44/// nothing else. That is the partiality the description witnesses on every interpreter's behalf.
45pub struct TextEmptyOutput;
46
47impl OutputAlg<()> for TextEmptyOutput {
48    type Output = ();
49
50    fn output((): ()) {}
51}
52
53impl EmptyOutAlg for TextHandlerImpl {
54    type Empty<From> = TextEmptyOutput;
55}
56
57/// Interprets a header an answer carries, in text descriptions.
58pub struct TextHeaderOutput<Inner, Name>(PhantomData<fn(Inner, Name)>);
59
60impl<Inner, Name, Value, Rest> OutputAlg<(Value, Rest)> for TextHeaderOutput<Inner, Name>
61where
62    Inner: OutputAlg<Rest>,
63{
64    type Output = Inner::Output;
65
66    fn output((_value, rest): (Value, Rest)) -> Self::Output {
67        Inner::output(rest)
68    }
69}
70
71impl HeaderOutAlg for TextHandlerImpl {
72    type Header<Inner, Name> = TextHeaderOutput<Inner, Name>;
73}
74
75/// Interprets a declared status in text descriptions.
76pub struct TextStatusOutput<Inner, const CODE: u16>(PhantomData<Inner>);
77
78impl<Inner, From, const CODE: u16> OutputAlg<From> for TextStatusOutput<Inner, CODE>
79where
80    Inner: OutputAlg<From>,
81{
82    type Output = Inner::Output;
83
84    fn output(from: From) -> Self::Output {
85        Inner::output(from)
86    }
87}
88
89impl StatusOutAlg for TextHandlerImpl {
90    type Status<Inner, const CODE: u16> = TextStatusOutput<Inner, CODE>;
91}
92
93/// Interprets a failing handler in text descriptions.
94///
95/// The description keeps the status a failure is answered with and discards the message, because
96/// what a surface states is that the failure has a status, not what it reads like.
97pub struct TextResultOutput<Inner, Error>(PhantomData<fn(Inner, Error)>);
98
99impl<Inner, Error, Value> OutputAlg<Result<Value, Error>> for TextResultOutput<Inner, Error>
100where
101    Inner: OutputAlg<Value>,
102    Error: HttpErrorAlg,
103{
104    type Output = Result<Inner::Output, HttpStatus>;
105
106    fn output(from: Result<Value, Error>) -> Self::Output {
107        from.map(Inner::output).map_err(|error| error.http_status())
108    }
109}
110
111impl ResultOutAlg for TextHandlerImpl {
112    type Result<Inner, Error> = TextResultOutput<Inner, Error>;
113}