use std::any::TypeId; use paste::paste; use seq_macro::seq; use util_macros::sub; pub trait Tuple: sealed::Sealed { /// `Self` with the given type added as the last element. /// /// `(String, i32, u8)::WithElementAtEnd = (String, i32, u8, Path)` /// /// # Important note /// If `Self` has 16 elements, this will be `()`. The reason for this is that the /// `Tuple` trait is only implemented for tuples with up to and including 16 elements. type WithElementAtEnd: Tuple; /// `Self` without the last element. /// /// `(u16, AtomicU8)::WithoutLastElement = (u16,)` type WithoutLastElement: Tuple; /// The last element of `Self`. type LastElement; /// Self with all elements wrapped in [`Option`]. type InOptions: Tuple; /// Pops the last element from this tuple, returning the new tuple and the popped /// element. fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement); /// Converts this tuple so that all elements are wrapped in [`Option`]. fn into_in_options(self) -> Self::InOptions; } /// A tuple with element types that all have the lifetime `'static`. pub trait WithAllElemLtStatic: Tuple + sealed::Sealed { /// Returns the element at the given index. fn get_mut(&mut self, index: usize) -> Option<&mut Element>; } /// Using the type system, reduces the elements of a tuple to a single one. Each element /// determines itself how it is handled. pub trait Reduce { type Out; } pub trait ReduceElement { type Return; } macro_rules! tuple_reduce_elem_tuple { (overflow) => { () }; ($index: tt) => { paste! { []::Return } }; } macro_rules! elem_type_by_index { (overflow) => { () }; ($index: tt) => { paste! { [] } }; } macro_rules! elem_by_index { (overflow) => { () }; ($index: tt, $self: ident) => { $self.$index }; } macro_rules! all_except_last { (start $($rest: tt)*) => { all_except_last!(@[] $($rest)*) }; (@[$($included_elem: ident,)*] $elem: ident $($rest: tt)+) => { all_except_last!(@[$($included_elem,)* $elem,] $($rest)*) }; (@[$($included_elem: expr,)*] ($elem: expr) $($rest: tt)+) => { all_except_last!(@[$($included_elem,)* $elem,] $($rest)*) }; (@[$($included_elem: ident,)*] $elem: ident) => { ($($included_elem,)*) }; (@[$($included_elem: expr,)*] $elem: expr) => { ($($included_elem,)*) }; (@[]) => { () }; } macro_rules! impl_tuple_traits { ($cnt: tt) => { seq!(I in 0..$cnt { impl<#(Elem~I,)*> Tuple for (#(Elem~I,)*) { type WithElementAtEnd = (#(Elem~I,)* NewElem,); type WithoutLastElement = all_except_last!(start #(Elem~I)*); type LastElement = sub!($cnt - 1, elem_type_by_index); type InOptions = (#(Option,)*); fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement) { ( all_except_last!(start #((self.I))*), sub!($cnt - 1, elem_by_index, (self)) ) } fn into_in_options(self) -> Self::InOptions { #![allow(clippy::unused_unit)] (#(Some(self.I),)*) } } impl<#(Elem~I: 'static,)*> WithAllElemLtStatic for (#(Elem~I,)*) { fn get_mut(&mut self, index: usize) -> Option<&mut Element> { match index { #( I => { assert!(TypeId::of::() == TypeId::of::()); // SAFETY: It is checked above that the type is correct Some(unsafe { &mut *(&raw mut self.I).cast::() }) } )* _ => None } } } impl<#(Elem~I,)*> sealed::Sealed for (#(Elem~I,)*) { } paste! { impl Reduce for (#(Elem~I,)*) where #( Elem~I: ReduceElement< sub!(I - 1, tuple_reduce_elem_tuple), Operation >, )* { type Out = sub!($cnt - 1, tuple_reduce_elem_tuple); } } }); }; } seq!(N in 0..16 { impl_tuple_traits!(N); }); seq!(I in 0..16 { impl<#(Elem~I,)*> Tuple for (#(Elem~I,)*) { type WithElementAtEnd = (); type WithoutLastElement = all_except_last!(start #(Elem~I)*); type LastElement = Elem15; type InOptions = (#(Option,)*); fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement) { ( all_except_last!(start #((self.I))*), self.15 ) } fn into_in_options(self) -> Self::InOptions { #![allow(clippy::unused_unit)] (#(Some(self.I),)*) } } impl<#(Elem~I: 'static,)*> WithAllElemLtStatic for (#(Elem~I,)*) { fn get_mut(&mut self, index: usize) -> Option<&mut Element> { match index { #( I => { assert!(TypeId::of::() == TypeId::of::()); // SAFETY: It is checked above that the type is correct Some(unsafe { &mut *(&raw mut self.I).cast::() }) } )* _ => None } } } impl<#(Elem~I,)*> sealed::Sealed for (#(Elem~I,)*) { } }); mod sealed { pub trait Sealed {} }