#[diagnostic::on_unimplemented(
message = "`{Self}` is not a tuple, doesn't have an element #{N}, or is too long",
note = "At the moment, the trait is implemented only for tuples up to length 8"
)]
pub trait Index<const N: usize>: Tuple {
type Nth;
type NthMapped<U>;
fn nth(this: Self) -> Self::Nth;
fn nth_ref(this: &Self) -> &Self::Nth;
fn map_nth<U>(this: Self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>;
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is not tuple, has less than {N} elements, or is too long",
note = "At the moment, the trait is implemented only for tuples up to length 8"
)]
pub trait Slice<const N: usize>: Tuple {
type FirstN;
type FirstNStripped;
fn first_n(this: Self) -> Self::FirstN;
fn strip_first_n(this: Self) -> Self::FirstNStripped;
fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped);
}
pub trait CloneableRefs: Tuple {
type Cloned;
fn cloned(this: Self) -> Self::Cloned;
}
pub trait CopiableRefs: Tuple {
type Copied;
fn copied(this: Self) -> Self::Copied;
}
macro_rules! impl_nth_methods {
($n:literal, $name:ident, $ref_name:ident, $map_name:ident) => {
#[doc = concat!("Returns the ", stringify!($name), " element of the tuple.")]
#[doc = "For a more generic function, see [`Tuple::nth`]"]
fn $name(self) -> Self::Nth
where
Self: Index<$n>,
{
Index::nth(self)
}
#[doc = concat!("Returns a reference to the ", stringify!($name), " element of the tuple.")]
#[doc = "For a more generic function, see [`Tuple::nth_ref`]"]
fn $ref_name(&self) -> &Self::Nth
where
Self: Index<$n>,
{
Index::nth_ref(self)
}
#[doc = concat!("Transforms the ", stringify!($name), " element of the tuple with `f`.")]
#[doc = "For a more generic function, see [`Tuple::map_nth`]"]
fn $map_name<U>(self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>
where
Self: Index<$n>,
{
Index::map_nth(self, f)
}
};
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a tuple or is too long",
note = "At the moment, the trait is implemented only for tuples up to length 8"
)]
pub trait Tuple: Sized {
type Appended<NewElement>;
type Prepended<NewElement>;
type Reversed;
fn append<NewElement>(self, new_element: NewElement) -> Self::Appended<NewElement>;
fn prepend<NewElement>(self, new_element: NewElement) -> Self::Prepended<NewElement>;
fn rev(self) -> Self::Reversed;
fn cloned(self) -> Self::Cloned
where
Self: CloneableRefs,
{
CloneableRefs::cloned(self)
}
fn copied(self) -> Self::Copied
where
Self: CopiableRefs,
{
CopiableRefs::copied(self)
}
fn nth<const N: usize>(self) -> Self::Nth
where
Self: Index<N>,
{
Index::nth(self)
}
fn nth_ref<const N: usize>(&self) -> &Self::Nth
where
Self: Index<N>,
{
Index::nth_ref(self)
}
fn map_nth<const N: usize, U>(self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>
where
Self: Index<N>,
{
Index::map_nth(self, f)
}
impl_nth_methods!(0, first, first_ref, map_first);
impl_nth_methods!(1, second, second_ref, map_second);
impl_nth_methods!(2, third, third_ref, map_third);
fn first_n<const N: usize>(self) -> Self::FirstN
where
Self: Slice<N>,
{
Slice::first_n(self)
}
fn strip_first_n<const N: usize>(self) -> Self::FirstNStripped
where
Self: Slice<N>,
{
Slice::strip_first_n(self)
}
fn split<const N: usize>(self) -> (Self::FirstN, Self::FirstNStripped)
where
Self: Slice<N>,
{
Slice::split(self)
}
}
macro_rules! rev {
($($x:ident,)*) => { rev!(| $($x,)* |) };
(| $x:ident, $($rest:ident,)* | $($rev:ident,)*) => { rev!(| $($rest,)* | $x, $($rev,)*) };
(| | $($rev:ident,)*) => { ($($rev,)*) };
}
macro_rules! impl_tuple_traits {
($length:literal - $($n:literal : $t:ident),*) => {
impl_tuple_traits!([] [$($n:$t,)*] [$($t),*]);
impl<$($t),*> Slice<$length> for ($($t,)*) {
type FirstN = Self;
type FirstNStripped = ();
fn first_n(this: Self) -> Self::FirstN { this }
fn strip_first_n(_: Self) -> Self::FirstNStripped {}
fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped) { (this, ()) }
}
#[allow(non_snake_case)]
impl<$($t: Clone),*> CloneableRefs for ($(&$t,)*) {
type Cloned = ($($t,)*);
#[allow(clippy::unused_unit)]
fn cloned(this: Self) -> Self::Cloned {
let ($($t,)*) = this;
($($t.clone(),)*)
}
}
#[allow(non_snake_case)]
impl<$($t: Copy),*> CopiableRefs for ($(&$t,)*) {
type Copied = ($($t,)*);
#[allow(clippy::unused_unit)]
fn copied(this: Self) -> Self::Copied {
let ($($t,)*) = this;
($(*$t,)*)
}
}
#[allow(non_snake_case)]
impl<$($t),*> Tuple for ($($t,)*) {
type Appended<NewElement> = ($($t,)* NewElement,);
type Prepended<NewElement> = (NewElement, $($t,)*);
type Reversed = rev!($($t,)*);
fn append<NewElement>(self, new_element: NewElement) -> Self::Appended<NewElement> {
let ($($t,)*) = self;
($($t,)* new_element,)
}
fn prepend<NewElement>(self, new_element: NewElement) -> Self::Prepended<NewElement> {
let ($($t,)*) = self;
(new_element, $($t,)*)
}
fn rev(self) -> Self::Reversed {
let ($($t,)*) = self;
rev!($($t,)*)
}
}
};
($prev:tt [] $t:tt) => {};
([$($prev:ident),*] [$id:literal : $nth:ident, $($next_id:literal : $next:ident,)*] [$($t:ident),+]) => {
#[allow(non_snake_case)]
impl<$($t),+> Index<$id> for ($($t,)+) {
type Nth = $nth;
type NthMapped<U> = ($($prev,)* U, $($next,)*);
#[allow(unused)]
fn nth(this: Self) -> Self::Nth {
let ($($t,)+) = this;
$nth
}
#[allow(unused)]
fn nth_ref(this: &Self) -> &Self::Nth {
let ($($t,)+) = this;
$nth
}
fn map_nth<U>(this: Self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U> {
let ($($t,)+) = this;
($($prev,)* f($nth), $($next,)*)
}
}
#[allow(non_snake_case)]
impl<$($t),+> Slice<$id> for ($($t,)+) {
type FirstN = ($($prev,)*);
type FirstNStripped = ($nth, $($next,)*);
#[allow(unused, clippy::unused_unit)]
fn first_n(this: Self) -> Self::FirstN {
let ($($t,)+) = this;
($($prev,)*)
}
#[allow(unused)]
fn strip_first_n(this: Self) -> Self::FirstNStripped {
let ($($t,)+) = this;
($nth, $($next,)*)
}
fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped) {
let ($($t,)+) = this;
(($($prev,)*), ($nth, $($next,)*))
}
}
impl_tuple_traits!([$($prev,)* $nth] [$($next_id:$next,)*] [$($t),+]);
};
}
impl_tuple_traits!(0 -);
impl_tuple_traits!(1 - 0: T0);
impl_tuple_traits!(2 - 0: T0, 1: T1);
impl_tuple_traits!(3 - 0: T0, 1: T1, 2: T2);
impl_tuple_traits!(4 - 0: T0, 1: T1, 2: T2, 3: T3);
impl_tuple_traits!(5 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4);
impl_tuple_traits!(6 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5);
impl_tuple_traits!(7 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6);
impl_tuple_traits!(8 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7);
impl_tuple_traits!(9 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8);
impl_tuple_traits!(10 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7, 8: T8, 9: T9);
#[rustfmt::skip]
macro_rules! impl_nth_fn {
($n:literal, $name:ident, $ref_name:ident, $map_name:ident) => {
#[doc = concat!("Returns the ", stringify!($name), " element of the tuple.")]
#[doc = "For a more generic function, see [`Tuple::nth`]"]
pub fn $name<T: Index<$n>>(tuple: T) -> T::Nth {
Index::nth(tuple)
}
#[doc = concat!("Returns a reference to the ", stringify!($name), " element of the tuple.")]
#[doc = "For a more generic function, see [`Tuple::nth_ref`]"]
pub fn $ref_name<T: Index<$n>>(tuple: &T) -> &T::Nth {
Index::nth_ref(tuple)
}
#[doc = concat!("Returns a function that transforms the ", stringify!($name), " element of a tuple with `f`.")]
#[doc = "For a more generic function, see [`Tuple::map_nth`]"]
pub fn $map_name<T: Index<$n>, U>(
mut f: impl FnMut(T::Nth) -> U,
) -> impl FnMut(T) -> T::NthMapped<U> {
move |tuple| Index::map_nth(tuple, &mut f)
}
};
}
impl_nth_fn!(0, first, first_ref, map_first);
impl_nth_fn!(1, second, second_ref, map_second);
impl_nth_fn!(2, third, third_ref, map_third);
pub fn append<T: Tuple, U: Clone>(new_element: U) -> impl Fn(T) -> T::Appended<U> {
move |tuple| tuple.append(new_element.clone())
}
pub fn prepend<U: Clone, T: Tuple>(new_element: U) -> impl Fn(T) -> T::Prepended<U> {
move |tuple| tuple.prepend(new_element.clone())
}
pub const fn tuple<T>(x: T) -> (T,) {
(x,)
}
pub fn rev<T: Tuple>(x: T) -> T::Reversed {
x.rev()
}
pub fn cloned<T: CloneableRefs>(x: T) -> T::Cloned {
CloneableRefs::cloned(x)
}
pub fn copied<T: CopiableRefs>(x: T) -> T::Copied {
CopiableRefs::copied(x)
}
#[macro_export]
macro_rules! from_tuple {
($name:ident { $($field:ident),* $(,)? }) => { |($($field,)*)| $name { $($field),* } };
}
#[macro_export]
#[doc(hidden)]
macro_rules! last {
($_:tt $($rest:tt)+) => { $($rest)+ };
($last:tt) => { $last };
}
#[macro_export]
macro_rules! call {
($($args:tt)*) => { |$crate::last!($($args)*)| $($args)* };
}