use varihappy_macros::{ repeat, tuple_expr_reverse, tuple_len, tuple_new, tuple_reverse, tuple_trait_def, type_to_field_access, }; pub trait Tuple { const LEN: usize; type AsRef<'a>: Tuple where Self: 'a; type AsMut<'a>: Tuple where Self: 'a; type Reversed: Tuple; fn as_ref(&self) -> Self::AsRef<'_>; fn as_mut(&mut self) -> Self::AsMut<'_>; fn rev(self) -> Self::Reversed; } pub trait Tuple1: Tuple { type Item0; type Rest: Tuple; fn into_0(self) -> Self::Item0; fn split_into(self) -> (Self::Item0, Self::Rest); fn into_rest(self) -> Self::Rest; } pub trait ArrayTupleOrEmpty: Tuple {} pub trait ArrayTuple: Tuple { type Item; } impl ArrayTupleOrEmpty for () {} impl> ArrayTupleOrEmpty for T {} impl Tuple for () { type AsRef<'a> = () where Self: 'a; type AsMut<'a> = () where Self: 'a; type Reversed = (); const LEN: usize = 0; fn as_ref(&self) -> Self::AsRef<'_> {} fn as_mut(&mut self) -> Self::AsMut<'_> {} fn rev(self) -> Self::Reversed {} } macro_rules! tuple_apply { (($($letter: ident,)*), $other: ident) => { $other!(($($letter,)*)) }; } macro_rules! tuple_rest { ((A, $($letter: ident,)*)) => { ($($letter,)*) }; } macro_rules! tuple_expr_apply { ($this: ident, ($($letter: ident,)*), $other: ident) => { $other!($this, ($($letter,)*)) }; } macro_rules! tuple_expr_ref { ($this: ident, ($($letter: ident,)*)) => { { let this = $this; ($(&type_to_field_access!($letter),)*) } } } macro_rules! tuple_expr_mut { ($this: ident, ($($letter: ident,)*)) => { { let this = $this; ($(&mut type_to_field_access!($letter),)*) } } } macro_rules! tuple_expr_rest { ($this: ident, (A, $($letter: ident,)*)) => { #[allow(unused_variables, clippy::unused_unit)] { let this = $this; ($(type_to_field_access!($letter),)*) } } } macro_rules! tuple_expr_split { ($this: ident, (A, $($letter: ident,)*)) => { { let this = $this; (this.0, ($(type_to_field_access!($letter),)*)) } } } macro_rules! impl_tuple_inner { (($($letter: ident,)*)) => { impl<$($letter),*> Tuple for ($($letter,)*) { const LEN: usize = tuple_len!(($($letter,)*)); type AsRef<'a> = ($(&'a $letter,)*) where Self: 'a; type AsMut<'a> = ($(&'a mut $letter,)*) where Self: 'a; type Reversed = tuple_apply!(($($letter,)*), tuple_reverse); fn as_ref(&self) -> Self::AsRef<'_> { tuple_expr_apply!(self, ($($letter,)*), tuple_expr_ref) } fn as_mut(&mut self) -> Self::AsMut<'_> { tuple_expr_apply!(self, ($($letter,)*), tuple_expr_mut) } fn rev(self) -> Self::Reversed { tuple_expr_apply!(self, ($($letter,)*), tuple_expr_reverse) } } impl<$($letter),*> Tuple1 for ($($letter,)*) { type Item0 = A; type Rest = tuple_apply!(($($letter,)*), tuple_rest); fn into_0(self) -> Self::Item0 { self.0 } fn split_into(self) -> (Self::Item0, Self::Rest) { tuple_expr_apply!(self, ($($letter,)*), tuple_expr_split) } fn into_rest(self) -> Self::Rest { tuple_expr_apply!(self, ($($letter,)*), tuple_expr_rest) } } }; } macro_rules! impl_tuple { ($number: literal) => { tuple_new! { $number, impl_tuple_inner } }; } macro_rules! tuple_trait_inner { (trait $trait_name: ident for $trait_minus1: ident { type $item_name: ident; fn $item_getter: ident; }) => { pub trait $trait_name: $trait_minus1 { type $item_name; type Rest: Tuple; fn $item_getter(self) -> Self::$item_name; fn into_rest(self) -> ::Rest; } impl> $trait_name for T { type $item_name = R::Item0; type Rest = R::Rest; fn $item_getter(self) -> Self::$item_name { $trait_minus1::into_rest(self).into_0() } fn into_rest(self) -> ::Rest { $trait_minus1::into_rest(self).into_rest() } } }; } macro_rules! tuple_trait { ($number: literal) => { tuple_trait_def! { $number, tuple_trait_inner } }; } macro_rules! t { ($_t:tt) => { T }; } macro_rules! impl_array_tuple_inner { (($($letter: ident,)*)) => { impl ArrayTuple for ($(t!($letter),)*) { type Item = T; } }; } macro_rules! impl_array_tuple { ($number: literal) => { tuple_new! { $number, impl_array_tuple_inner } }; } repeat!(1..64, impl_tuple); repeat!(2..64, tuple_trait); repeat!(1..64, impl_array_tuple);