use alux_shape::ShapeOf;
use alux_shape_typescript::{TsShape, TsType};
use core::marker::PhantomData;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TsSource {
Path,
Query,
Header,
Cookie,
Body,
Form,
Multipart,
Raw,
Unstated,
}
impl TsSource {
pub fn label(self) -> &'static str {
match self {
Self::Path => "path",
Self::Query => "query",
Self::Header => "header",
Self::Cookie => "cookie",
Self::Body => "body",
Self::Form => "form",
Self::Multipart => "multipart",
Self::Raw => "raw",
Self::Unstated => "none",
}
}
}
#[derive(Debug, Clone)]
pub struct TsArgument {
pub source: TsSource,
pub shape: TsType,
}
pub trait TsInputAlg {
fn describe(shapes: &TsShape) -> TsArgument;
}
macro_rules! ts_inputs {
($($marker:ident => $source:expr, $meaning:literal),+ $(,)?) => {
$(
#[doc = concat!("Takes ", $meaning, ".")]
pub struct $marker<Input>(PhantomData<Input>);
impl<Input> TsInputAlg for $marker<Input>
where
Input: ShapeOf<TsShape, Shape = TsType>,
{
fn describe(shapes: &TsShape) -> TsArgument {
TsArgument { source: $source, shape: Input::shape_of(shapes) }
}
}
)+
};
}
ts_inputs! {
TsPathInput => TsSource::Path, "a segment the path binds",
TsQueryInput => TsSource::Query, "a value in the query string",
TsHeaderInput => TsSource::Header, "a header the caller sends",
TsCookieInput => TsSource::Cookie, "a cookie the caller sends",
TsBodyInput => TsSource::Body, "a request body written as a document",
TsFormInput => TsSource::Form, "a request body written as a form",
TsMultipartInput => TsSource::Multipart, "a request body written as parts",
TsRawBodyInput => TsSource::Raw, "a request body sent as it stands",
}
pub struct TsUnstatedInput<Input>(PhantomData<Input>);
impl<Input> TsInputAlg for TsUnstatedInput<Input>
where
Input: ShapeOf<TsShape, Shape = TsType>,
{
fn describe(shapes: &TsShape) -> TsArgument {
TsArgument { source: TsSource::Unstated, shape: Input::shape_of(shapes) }
}
}
pub trait TsInputsAlg {
fn describe(shapes: &TsShape) -> Vec<TsArgument>;
}
impl TsInputsAlg for () {
fn describe(_shapes: &TsShape) -> Vec<TsArgument> {
Vec::new()
}
}
macro_rules! ts_products {
($($input:ident),+ $(,)?) => {
impl<$($input),+> TsInputsAlg for ($($input,)+)
where
$($input: TsInputAlg,)+
{
fn describe(shapes: &TsShape) -> Vec<TsArgument> {
vec![$($input::describe(shapes),)+]
}
}
};
}
ts_products!(I1);
ts_products!(I1, I2);
ts_products!(I1, I2, I3);
ts_products!(I1, I2, I3, I4);
ts_products!(I1, I2, I3, I4, I5);
ts_products!(I1, I2, I3, I4, I5, I6);
ts_products!(I1, I2, I3, I4, I5, I6, I7);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15);
ts_products!(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16);