tuple_traits/append.rs
1/// Trait to append some value to the end of a tuple.
2///
3/// # Examples
4///
5/// ```
6/// # use static_assertions::assert_type_eq_all;
7/// # use tuple_traits::Append;
8/// #
9/// // Append a value to the unit value.
10/// assert_type_eq_all!(<() as Append>::Append<usize>, (usize,));
11///
12/// // Append a value to a single value tuple.
13/// assert_type_eq_all!(<(usize,) as Append>::Append<char>, (usize, char));
14///
15/// // Append a value to a multi-value tuple.
16/// assert_type_eq_all!(<(usize, char) as Append>::Append<bool>, (usize, char, bool));
17/// ```
18///
19/// The trait can also be used to modify the return value based on some generic.
20///
21/// ```no_run
22/// # use static_assertions::assert_type_eq_all;
23/// # use tuple_traits::Append;
24/// #
25/// fn append_usize<T>(value: T) -> T::Append<usize>
26/// where
27/// T: Append
28/// {
29/// // ...
30/// # todo!()
31/// }
32///
33/// let result: (char, bool, usize) = append_usize(('a', true));
34/// ```
35pub trait Append {
36 /// Append operation, which will be the type of the result.
37 type Append<T>;
38}
39
40macro_rules! impl_tuples {
41 // Base case, appending to unit (empty tuple).
42 () => {
43 impl Append for () {
44 type Append<T> = (T,);
45 }
46 };
47
48 // Recursive case, implement for a tuple, and recurse with the head removed.
49 ($T:ident $(, $($Tail:ident),* )?) => {
50 impl<$T, $($($Tail),*)?> Append for ($T, $($($Tail),*)?) {
51 type Append<T> = ($T, $($($Tail,)*)? T);
52 }
53
54 impl_tuples!($($($Tail),*)?);
55 };
56}
57
58crate::tuple_list!(impl_tuples);
59
60#[cfg(test)]
61mod test {
62 use static_assertions::assert_type_eq_all;
63
64 use super::*;
65
66 assert_type_eq_all!(<() as Append>::Append<usize>, (usize,));
67 assert_type_eq_all!(<(bool,) as Append>::Append<usize>, (bool, usize));
68 assert_type_eq_all!(<(bool, char) as Append>::Append<usize>, (bool, char, usize));
69}