1#[diagnostic::on_unimplemented(
15    message = "`{Self}` is not a tuple, doesn't have an element #{N}, or is too long",
16    note = "At the moment, the trait is implemented only for tuples up to length 8"
17)]
18pub trait Index<const N: usize>: Tuple {
19    type Nth;
21    type NthMapped<U>;
23
24    fn nth(this: Self) -> Self::Nth;
26
27    fn nth_ref(this: &Self) -> &Self::Nth;
29
30    fn map_nth<U>(this: Self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>;
32}
33
34#[diagnostic::on_unimplemented(
41    message = "`{Self}` is not tuple, has less than {N} elements, or is too long",
42    note = "At the moment, the trait is implemented only for tuples up to length 8"
43)]
44pub trait Slice<const N: usize>: Tuple {
45    type FirstN;
47
48    type FirstNStripped;
50
51    fn first_n(this: Self) -> Self::FirstN;
53
54    fn strip_first_n(this: Self) -> Self::FirstNStripped;
56
57    fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped);
60}
61
62pub trait CloneableRefs: Tuple {
69    type Cloned;
71
72    fn cloned(this: Self) -> Self::Cloned;
74}
75
76pub trait CopiableRefs: Tuple {
83    type Copied;
85
86    fn copied(this: Self) -> Self::Copied;
88}
89
90macro_rules! impl_nth_methods {
91    ($n:literal, $name:ident, $ref_name:ident, $map_name:ident) => {
92        #[doc = concat!("Returns the ", stringify!($name), " element of the tuple.")]
93        #[doc = "For a more generic function, see [`Tuple::nth`]"]
94        fn $name(self) -> Self::Nth
95        where
96            Self: Index<$n>,
97        {
98            Index::nth(self)
99        }
100
101        #[doc = concat!("Returns a reference to the ", stringify!($name), " element of the tuple.")]
102        #[doc = "For a more generic function, see [`Tuple::nth_ref`]"]
103        fn $ref_name(&self) -> &Self::Nth
104        where
105            Self: Index<$n>,
106        {
107            Index::nth_ref(self)
108        }
109
110        #[doc = concat!("Transforms the ", stringify!($name), " element of the tuple with `f`.")]
111        #[doc = "For a more generic function, see [`Tuple::map_nth`]"]
112        fn $map_name<U>(self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>
113        where
114            Self: Index<$n>,
115        {
116            Index::map_nth(self, f)
117        }
118    };
119}
120
121#[diagnostic::on_unimplemented(
123    message = "`{Self}` is not a tuple or is too long",
124    note = "At the moment, the trait is implemented only for tuples up to length 8"
125)]
126pub trait Tuple: Sized {
127    type Appended<NewElement>;
129
130    type Prepended<NewElement>;
132
133    type Reversed;
135
136    fn append<NewElement>(self, new_element: NewElement) -> Self::Appended<NewElement>;
139
140    fn prepend<NewElement>(self, new_element: NewElement) -> Self::Prepended<NewElement>;
143
144    fn rev(self) -> Self::Reversed;
147
148    fn cloned(self) -> Self::Cloned
151    where
152        Self: CloneableRefs,
153    {
154        CloneableRefs::cloned(self)
155    }
156
157    fn copied(self) -> Self::Copied
160    where
161        Self: CopiableRefs,
162    {
163        CopiableRefs::copied(self)
164    }
165
166    fn nth<const N: usize>(self) -> Self::Nth
169    where
170        Self: Index<N>,
171    {
172        Index::nth(self)
173    }
174
175    fn nth_ref<const N: usize>(&self) -> &Self::Nth
178    where
179        Self: Index<N>,
180    {
181        Index::nth_ref(self)
182    }
183
184    fn map_nth<const N: usize, U>(self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>
187    where
188        Self: Index<N>,
189    {
190        Index::map_nth(self, f)
191    }
192
193    impl_nth_methods!(0, first, first_ref, map_first);
194    impl_nth_methods!(1, second, second_ref, map_second);
195    impl_nth_methods!(2, third, third_ref, map_third);
196
197    fn first_n<const N: usize>(self) -> Self::FirstN
200    where
201        Self: Slice<N>,
202    {
203        Slice::first_n(self)
204    }
205
206    fn strip_first_n<const N: usize>(self) -> Self::FirstNStripped
209    where
210        Self: Slice<N>,
211    {
212        Slice::strip_first_n(self)
213    }
214
215    fn split<const N: usize>(self) -> (Self::FirstN, Self::FirstNStripped)
217    where
218        Self: Slice<N>,
219    {
220        Slice::split(self)
221    }
222}
223
224macro_rules! rev {
225    ($($x:ident,)*) => { rev!(| $($x,)* |) };
226    (| $x:ident, $($rest:ident,)* | $($rev:ident,)*) => { rev!(| $($rest,)* | $x, $($rev,)*) };
227    (| | $($rev:ident,)*) => { ($($rev,)*) };
228}
229
230macro_rules! impl_tuple_traits {
231    ($length:literal - $($n:literal : $t:ident),*) => {
232        impl_tuple_traits!([] [$($n:$t,)*] [$($t),*]);
233
234        impl<$($t),*> Slice<$length> for ($($t,)*) {
235            type FirstN = Self;
236            type FirstNStripped = ();
237
238            fn first_n(this: Self) -> Self::FirstN { this }
239            fn strip_first_n(_: Self) -> Self::FirstNStripped {}
240            fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped) { (this, ()) }
241        }
242
243        #[allow(non_snake_case)]
244        impl<$($t: Clone),*> CloneableRefs for ($(&$t,)*) {
245            type Cloned = ($($t,)*);
246
247            #[allow(clippy::unused_unit)]
248            fn cloned(this: Self) -> Self::Cloned {
249                let ($($t,)*) = this;
250                ($($t.clone(),)*)
251            }
252        }
253
254        #[allow(non_snake_case)]
255        impl<$($t: Copy),*> CopiableRefs for ($(&$t,)*) {
256            type Copied = ($($t,)*);
257
258            #[allow(clippy::unused_unit)]
259            fn copied(this: Self) -> Self::Copied {
260                let ($($t,)*) = this;
261                ($(*$t,)*)
262            }
263        }
264
265        #[allow(non_snake_case)]
266        impl<$($t),*> Tuple for ($($t,)*) {
267            type Appended<NewElement> = ($($t,)* NewElement,);
268            type Prepended<NewElement> = (NewElement, $($t,)*);
269            type Reversed = rev!($($t,)*);
270
271            fn append<NewElement>(self, new_element: NewElement) -> Self::Appended<NewElement> {
272                let ($($t,)*) = self;
273                ($($t,)* new_element,)
274            }
275
276            fn prepend<NewElement>(self, new_element: NewElement) -> Self::Prepended<NewElement> {
277                let ($($t,)*) = self;
278                (new_element, $($t,)*)
279            }
280
281            fn rev(self) -> Self::Reversed {
282                let ($($t,)*) = self;
283                rev!($($t,)*)
284            }
285        }
286    };
287
288    ($prev:tt [] $t:tt) => {};
289
290    ([$($prev:ident),*] [$id:literal : $nth:ident, $($next_id:literal : $next:ident,)*] [$($t:ident),+]) => {
291        #[allow(non_snake_case)]
292        impl<$($t),+> Index<$id> for ($($t,)+) {
293            type Nth = $nth;
294            type NthMapped<U> = ($($prev,)* U, $($next,)*);
295
296            #[allow(unused)]
297            fn nth(this: Self) -> Self::Nth {
298                let ($($t,)+) = this;
299                $nth
300            }
301
302            #[allow(unused)]
303            fn nth_ref(this: &Self) -> &Self::Nth {
304                let ($($t,)+) = this;
305                $nth
306            }
307
308            fn map_nth<U>(this: Self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U> {
309                let ($($t,)+) = this;
310                ($($prev,)* f($nth), $($next,)*)
311            }
312        }
313
314        #[allow(non_snake_case)]
315        impl<$($t),+> Slice<$id> for ($($t,)+) {
316            type FirstN = ($($prev,)*);
317            type FirstNStripped = ($nth, $($next,)*);
318
319            #[allow(unused, clippy::unused_unit)]
320            fn first_n(this: Self) -> Self::FirstN {
321                let ($($t,)+) = this;
322                ($($prev,)*)
323            }
324
325            #[allow(unused)]
326            fn strip_first_n(this: Self) -> Self::FirstNStripped {
327                let ($($t,)+) = this;
328                ($nth, $($next,)*)
329            }
330
331            fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped) {
332                let ($($t,)+) = this;
333                (($($prev,)*), ($nth, $($next,)*))
334            }
335        }
336
337        impl_tuple_traits!([$($prev,)* $nth] [$($next_id:$next,)*] [$($t),+]);
338    };
339}
340
341impl_tuple_traits!(0 -);
342impl_tuple_traits!(1 - 0: T0);
343impl_tuple_traits!(2 - 0: T0, 1: T1);
344impl_tuple_traits!(3 - 0: T0, 1: T1, 2: T2);
345impl_tuple_traits!(4 - 0: T0, 1: T1, 2: T2, 3: T3);
346impl_tuple_traits!(5 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4);
347impl_tuple_traits!(6 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5);
348impl_tuple_traits!(7 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6);
349impl_tuple_traits!(8 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7);
350
351#[rustfmt::skip]
352macro_rules! impl_nth_fn {
353    ($n:literal, $name:ident, $ref_name:ident, $map_name:ident) => {
354        #[doc = concat!("Returns the ", stringify!($name), " element of the tuple.")]
355        #[doc = "For a more generic function, see [`Tuple::nth`]"]
356        pub fn $name<T: Index<$n>>(tuple: T) -> T::Nth {
357            Index::nth(tuple)
358        }
359
360        #[doc = concat!("Returns a reference to the ", stringify!($name), " element of the tuple.")]
361        #[doc = "For a more generic function, see [`Tuple::nth_ref`]"]
362        pub fn $ref_name<T: Index<$n>>(tuple: &T) -> &T::Nth {
363            Index::nth_ref(tuple)
364        }
365
366        #[doc = concat!("Returns a function that transforms the ", stringify!($name), " element of a tuple with `f`.")]
367        #[doc = "For a more generic function, see [`Tuple::map_nth`]"]
368        pub fn $map_name<T: Index<$n>, U>(
369            mut f: impl FnMut(T::Nth) -> U,
370        ) -> impl FnMut(T) -> T::NthMapped<U> {
371            move |tuple| Index::map_nth(tuple, &mut f)
372        }
373    };
374}
375
376impl_nth_fn!(0, first, first_ref, map_first);
377impl_nth_fn!(1, second, second_ref, map_second);
378impl_nth_fn!(2, third, third_ref, map_third);
379
380pub fn append<T: Tuple, U: Clone>(new_element: U) -> impl Fn(T) -> T::Appended<U> {
382    move |tuple| tuple.append(new_element.clone())
383}
384
385pub fn prepend<U: Clone, T: Tuple>(new_element: U) -> impl Fn(T) -> T::Prepended<U> {
387    move |tuple| tuple.prepend(new_element.clone())
388}
389
390pub const fn tuple<T>(x: T) -> (T,) {
392    (x,)
393}
394
395pub fn rev<T: Tuple>(x: T) -> T::Reversed {
397    x.rev()
398}
399
400pub fn cloned<T: CloneableRefs>(x: T) -> T::Cloned {
402    CloneableRefs::cloned(x)
403}
404
405pub fn copied<T: CopiableRefs>(x: T) -> T::Copied {
407    CopiableRefs::copied(x)
408}
409
410#[macro_export]
428macro_rules! from_tuple {
429    ($name:ident { $($field:ident),* $(,)? }) => { |($($field,)*)| $name { $($field),* } };
430}
431
432#[macro_export]
433#[doc(hidden)]
434macro_rules! last {
435    ($_:tt $($rest:tt)+) => { $($rest)+ };
436    ($last:tt) => { $last };
437}
438
439#[macro_export]
458macro_rules! call {
459    ($($args:tt)*) => { |$crate::last!($($args)*)| $($args)* };
460}