#[derive(Debug)] pub struct Product(pub(crate) H, pub(crate) T); pub type One = (T,); #[inline] pub(crate) fn one(val: T) -> One { (val,) } #[derive(Debug)] pub enum Either { A(T), B(U), } // Converts Product (and ()) into tuples. pub trait HList: Sized { type Tuple: Tuple; fn flatten(self) -> Self::Tuple; } // Typeclass that tuples can be converted into a Product (or unit ()). pub trait Tuple: Sized { type HList: HList; fn hlist(self) -> Self::HList; #[inline] fn combine(self, other: T) -> CombinedTuples where Self: Sized, T: Tuple, Self::HList: Combine, { self.hlist().combine(other.hlist()).flatten() } } pub type CombinedTuples = <<::HList as Combine<::HList>>::Output as HList>::Tuple; // Combines Product together. pub trait Combine { type Output: HList; fn combine(self, other: T) -> Self::Output; } pub trait Func { type Output; fn call(&self, args: Args) -> Self::Output; } // ===== impl Combine ===== impl Combine for () { type Output = T; #[inline] fn combine(self, other: T) -> Self::Output { other } } impl Combine for Product where T: Combine, Product>::Output>: HList, { type Output = Product>::Output>; #[inline] fn combine(self, other: U) -> Self::Output { Product(self.0, self.1.combine(other)) } } impl HList for () { type Tuple = (); #[inline] fn flatten(self) -> Self::Tuple {} } impl Tuple for () { type HList = (); #[inline] fn hlist(self) -> Self::HList {} } impl Func<()> for F where F: Fn() -> R, { type Output = R; #[inline] fn call(&self, _args: ()) -> Self::Output { (*self)() } } impl Func for F where F: Fn(crate::Rejection) -> R, { type Output = R; #[inline] fn call(&self, arg: crate::Rejection) -> Self::Output { (*self)(arg) } } macro_rules! product { ($H:expr) => { Product($H, ()) }; ($H:expr, $($T:expr),*) => { Product($H, product!($($T),*)) }; } macro_rules! Product { ($H:ty) => { Product<$H, ()> }; ($H:ty, $($T:ty),*) => { Product<$H, Product!($($T),*)> }; } macro_rules! product_pat { ($H:pat) => { Product($H, ()) }; ($H:pat, $($T:pat),*) => { Product($H, product_pat!($($T),*)) }; } macro_rules! generics { ($type:ident) => { impl<$type> HList for Product!($type) { type Tuple = ($type,); #[inline] fn flatten(self) -> Self::Tuple { (self.0,) } } impl<$type> Tuple for ($type,) { type HList = Product!($type); #[inline] fn hlist(self) -> Self::HList { product!(self.0) } } impl Func for F where F: Fn($type) -> R, { type Output = R; #[inline] fn call(&self, args: Product!($type)) -> Self::Output { (*self)(args.0) } } impl Func<($type,)> for F where F: Fn($type) -> R, { type Output = R; #[inline] fn call(&self, args: ($type,)) -> Self::Output { (*self)(args.0) } } }; ($type1:ident, $( $type:ident ),*) => { generics!($( $type ),*); impl<$type1, $( $type ),*> HList for Product!($type1, $($type),*) { type Tuple = ($type1, $( $type ),*); #[inline] fn flatten(self) -> Self::Tuple { #[allow(non_snake_case)] let product_pat!($type1, $( $type ),*) = self; ($type1, $( $type ),*) } } impl<$type1, $( $type ),*> Tuple for ($type1, $($type),*) { type HList = Product!($type1, $( $type ),*); #[inline] fn hlist(self) -> Self::HList { #[allow(non_snake_case)] let ($type1, $( $type ),*) = self; product!($type1, $( $type ),*) } } impl Func for F where F: Fn($type1, $( $type ),*) -> R, { type Output = R; #[inline] fn call(&self, args: Product!($type1, $($type),*)) -> Self::Output { #[allow(non_snake_case)] let product_pat!($type1, $( $type ),*) = args; (*self)($type1, $( $type ),*) } } impl Func<($type1, $($type),*)> for F where F: Fn($type1, $( $type ),*) -> R, { type Output = R; #[inline] fn call(&self, args: ($type1, $($type),*)) -> Self::Output { #[allow(non_snake_case)] let ($type1, $( $type ),*) = args; (*self)($type1, $( $type ),*) } } }; } generics! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 }