Skip to main content

alux_http_typescript/
input.rs

1//! States where each argument comes from, in the vocabulary a caller writes.
2
3use alux_shape::ShapeOf;
4use alux_shape_typescript::{TsShape, TsType};
5use core::marker::PhantomData;
6
7/// Where a call says one argument goes.
8///
9/// A caller states an argument once; what it becomes on the wire is what the declaration said, so
10/// the generated module carries the role rather than a hand-written request.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum TsSource {
13    /// A segment the path binds.
14    Path,
15    /// A value in the query string.
16    Query,
17    /// A header the caller sends.
18    Header,
19    /// A cookie the caller sends.
20    Cookie,
21    /// The request body, written as a document.
22    Body,
23    /// The request body, written as a form.
24    Form,
25    /// The request body, written as parts.
26    Multipart,
27    /// The request body, sent as it stands.
28    Raw,
29    /// Something a caller does not state.
30    Unstated,
31}
32
33impl TsSource {
34    /// Returns the word a generated module carries this role as.
35    pub fn label(self) -> &'static str {
36        match self {
37            Self::Path => "path",
38            Self::Query => "query",
39            Self::Header => "header",
40            Self::Cookie => "cookie",
41            Self::Body => "body",
42            Self::Form => "form",
43            Self::Multipart => "multipart",
44            Self::Raw => "raw",
45            Self::Unstated => "none",
46        }
47    }
48}
49
50/// One argument, as a call takes it.
51#[derive(Debug, Clone)]
52pub struct TsArgument {
53    /// Where the argument goes.
54    pub source: TsSource,
55    /// The type the argument carries.
56    pub shape: TsType,
57}
58
59/// States how a call takes one argument.
60pub trait TsInputAlg {
61    /// Reads the type this argument carries, and where it goes.
62    fn describe(shapes: &TsShape) -> TsArgument;
63}
64
65macro_rules! ts_inputs {
66    ($($marker:ident => $source:expr, $meaning:literal),+ $(,)?) => {
67        $(
68            #[doc = concat!("Takes ", $meaning, ".")]
69            pub struct $marker<Input>(PhantomData<Input>);
70
71            impl<Input> TsInputAlg for $marker<Input>
72            where
73                Input: ShapeOf<TsShape, Shape = TsType>,
74            {
75                fn describe(shapes: &TsShape) -> TsArgument {
76                    TsArgument { source: $source, shape: Input::shape_of(shapes) }
77                }
78            }
79        )+
80    };
81}
82
83ts_inputs! {
84    TsPathInput      => TsSource::Path, "a segment the path binds",
85    TsQueryInput     => TsSource::Query, "a value in the query string",
86    TsHeaderInput    => TsSource::Header, "a header the caller sends",
87    TsCookieInput    => TsSource::Cookie, "a cookie the caller sends",
88    TsBodyInput      => TsSource::Body, "a request body written as a document",
89    TsFormInput      => TsSource::Form, "a request body written as a form",
90    TsMultipartInput => TsSource::Multipart, "a request body written as parts",
91    TsRawBodyInput   => TsSource::Raw, "a request body sent as it stands",
92}
93
94/// Takes nothing, because a caller states nothing here.
95pub struct TsUnstatedInput<Input>(PhantomData<Input>);
96
97impl<Input> TsInputAlg for TsUnstatedInput<Input>
98where
99    Input: ShapeOf<TsShape, Shape = TsType>,
100{
101    fn describe(shapes: &TsShape) -> TsArgument {
102        TsArgument { source: TsSource::Unstated, shape: Input::shape_of(shapes) }
103    }
104}
105
106/// States the whole argument product a call takes, in declaration order.
107pub trait TsInputsAlg {
108    /// Reads each argument, in the order the declaration states them.
109    fn describe(shapes: &TsShape) -> Vec<TsArgument>;
110}
111
112impl TsInputsAlg for () {
113    fn describe(_shapes: &TsShape) -> Vec<TsArgument> {
114        Vec::new()
115    }
116}
117
118macro_rules! ts_products {
119    ($($input:ident),+ $(,)?) => {
120        impl<$($input),+> TsInputsAlg for ($($input,)+)
121        where
122            $($input: TsInputAlg,)+
123        {
124            fn describe(shapes: &TsShape) -> Vec<TsArgument> {
125                vec![$($input::describe(shapes),)+]
126            }
127        }
128    };
129}
130
131ts_products!(I1);
132ts_products!(I1, I2);
133ts_products!(I1, I2, I3);
134ts_products!(I1, I2, I3, I4);
135ts_products!(I1, I2, I3, I4, I5);
136ts_products!(I1, I2, I3, I4, I5, I6);
137ts_products!(I1, I2, I3, I4, I5, I6, I7);
138ts_products!(I1, I2, I3, I4, I5, I6, I7, I8);
139ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9);
140ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10);
141ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11);
142ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12);
143ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13);
144ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14);
145ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15);
146ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16);