multiversx_sc/tuple_util/
nested_tuples.rs

1/// A tuple of the form (A, (B, (... (N, ())))).
2///
3/// It is always terminated with a unit.
4pub trait NestedTuple {}
5
6impl NestedTuple for () {}
7
8impl<Head, Tail> NestedTuple for (Head, Tail) where Tail: NestedTuple {}
9
10/// Allows to append at the end of a nested tuple list.
11pub trait NestedTupleAppend<T> {
12    type Output;
13
14    fn append(self, t: T) -> Self::Output;
15}
16
17impl<T> NestedTupleAppend<T> for () {
18    type Output = (T, ());
19
20    fn append(self, t: T) -> Self::Output {
21        (t, ())
22    }
23}
24
25impl<Head, Tail, T> NestedTupleAppend<T> for (Head, Tail)
26where
27    Tail: NestedTupleAppend<T>,
28{
29    type Output = (Head, Tail::Output);
30
31    fn append(self, t: T) -> Self::Output {
32        (self.0, self.1.append(t))
33    }
34}
35
36/// Defines conversion of a nested tuple list to a regular tuple.
37pub trait NestedTupleFlatten: NestedTuple {
38    type Flattened;
39    type Unpacked;
40
41    /// Converts a nested tuple list to a regular tuple.
42    fn flatten(self) -> Self::Flattened;
43
44    /// Same as `flatten`, converts a nested tuple list to a regular tuple,
45    /// but additionally, it unpacks singleton tuples into their content (`(item,)` -> `item`).
46    fn flatten_unpack(self) -> Self::Unpacked;
47}
48
49impl NestedTupleFlatten for () {
50    type Flattened = ();
51    type Unpacked = ();
52
53    fn flatten(self) -> Self::Flattened {}
54    fn flatten_unpack(self) -> Self::Unpacked {}
55}
56
57impl<T> NestedTupleFlatten for (T, ()) {
58    type Flattened = (T,);
59    type Unpacked = T;
60
61    fn flatten(self) -> Self::Flattened {
62        (self.0,)
63    }
64
65    fn flatten_unpack(self) -> Self::Unpacked {
66        self.0
67    }
68}
69
70macro_rules! tuple_list_type {
71    () => ( () );
72    ($i:ty)  => ( ($i, ()) );
73    ($i:ty, $($e:ty),*)  => ( ($i, tuple_list_type!($($e),*)) );
74}
75
76macro_rules! unnest {
77    (($layer:expr); ($($v:expr),*); ($u:ident, $($us:ident,)*)) => {
78        unnest!(($layer . 1); ($($v,)* $layer . 0); ($($us,)*))
79    };
80    (($layer:expr); ($($v:expr),*); ()) => { ($($v,)*) };
81}
82
83macro_rules! flatten_impl {
84    ($(($t:ident $($ts:ident)+))+) => {
85        $(
86            impl<$t,$($ts),+> NestedTupleFlatten for tuple_list_type!($t,$($ts),+) {
87                type Flattened = ($t,$($ts),+);
88                type Unpacked = ($t,$($ts),+);
89
90                fn flatten(self) -> Self::Flattened {
91                    unnest!((self); (); ($t, $($ts,)*))
92                }
93
94                fn flatten_unpack(self) -> Self::Unpacked {
95                    self.flatten()
96                }
97            }
98        )+
99    }
100}
101
102flatten_impl! {
103    (T1 T2)
104    (T1 T2 T3)
105    (T1 T2 T3 T4)
106    (T1 T2 T3 T4 T5)
107    (T1 T2 T3 T4 T5 T6)
108    (T1 T2 T3 T4 T5 T6 T7)
109    (T1 T2 T3 T4 T5 T6 T7 T8)
110    (T1 T2 T3 T4 T5 T6 T7 T8 T9)
111    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10)
112    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11)
113    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12)
114    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13)
115    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14)
116    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15)
117    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16)
118}
119
120#[cfg(test)]
121mod test {
122    use super::*;
123
124    #[test]
125    fn test_flatten() {
126        let flat2 = (1, (2, ())).flatten();
127        assert_eq!(flat2, (1, 2));
128
129        let n3 = (1u8, (2u16, (3u32, ())));
130        let flat3 = n3.flatten();
131        assert_eq!(flat3, (1u8, 2u16, 3u32));
132
133        let n4 = n3.append(4u64);
134        let flat4 = n4.flatten();
135        assert_eq!(flat4, (1u8, 2u16, 3u32, 4u64));
136    }
137}