1use alux_shape::ShapeOf;
4use alux_shape_typescript::{TsShape, TsType};
5use core::marker::PhantomData;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum TsSource {
13 Path,
15 Query,
17 Header,
19 Cookie,
21 Body,
23 Form,
25 Multipart,
27 Raw,
29 Unstated,
31}
32
33impl TsSource {
34 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#[derive(Debug, Clone)]
52pub struct TsArgument {
53 pub source: TsSource,
55 pub shape: TsType,
57}
58
59pub trait TsInputAlg {
61 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
94pub 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
106pub trait TsInputsAlg {
108 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);