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}