tuple_utils/
lib.rs

1//! A simple set of utility traits for working with tuples
2
3/// Helper trait to allow Appending of tuples
4pub trait Append<T> {
5    type Output;
6    /// Append T onto the end of the tuple returning
7    /// a new tuple with the existing elements and T
8    fn append(self, other: T) -> Self::Output;
9}
10
11/// Helper trait to allow Plucking **tails** of tuples.
12///
13/// This is the inverse of [`Append`]
14pub trait PluckTail {
15    type Head;
16    type Tail;
17    /// Split the tuple into the tail (`Tail`) and the rest part (`Head`)
18    fn pluck_tail(self) -> (Self::Head, Self::Tail);
19}
20
21/// Helper trait to allow Perpending of tuples
22pub trait Prepend<T> {
23    type Output;
24    /// Append T onto the start of the tuple returning
25    /// a new tuple with all the elements from shifted
26    /// over one row and T in the first slot
27    fn prepend(self, other: T) -> Self::Output;
28}
29
30/// Helper trait to allow Plucking **heads** of tuples.
31///
32/// This is the inverse of [`Prepend`]
33pub trait Pluck {
34    type Head;
35    type Tail;
36    /// Split the tuple into the head (`Head`) and the rest part (`Tail`)
37    fn pluck(self) -> (Self::Head, Self::Tail);
38}
39
40macro_rules! tuple_impl {
41    // use variables to indicate the arity of the tuple
42    ($($from:ident,)*) => {
43        // the trailing commas are for the 1 tuple
44        impl<$($from,)* T> Append<T> for ( $( $from ,)* ) {
45            type Output = ( $( $from ,)*  T);
46
47            #[inline]
48            #[allow(non_snake_case)]
49            fn append(self, x: T) -> ( $( $from ,)*  T) {
50                match self {
51                    ($($from,)*) => ($($from,)* x)
52                }
53            }
54        }
55
56        impl<$($from,)* T> PluckTail for ($($from,)* T,) {
57            type Head = ($($from,)*);
58            type Tail = T;
59
60            #[inline]
61            #[allow(non_snake_case)]
62            fn pluck_tail(self) -> (Self::Head, Self::Tail) {
63                match self {
64                    ($($from,)* x,) => (($($from,)*), x)
65                }
66            }
67        }
68
69        // the trailing commas are for the 1 tuple
70        impl<$($from,)*  T> Prepend<T> for ( $( $from ,)* ) {
71            type Output = (T, $( $from ,)*);
72
73            #[inline]
74            #[allow(non_snake_case)]
75            fn prepend(self, x: T) -> (T, $( $from ,)*) {
76                match self {
77                    ($($from,)*) => (x, $($from,)*)
78                }
79            }
80        }
81
82        impl<$($from,)* T> Pluck for (T, $($from,)*) {
83            type Head = T;
84            type Tail = ($($from,)*);
85
86            #[inline]
87            #[allow(non_snake_case)]
88            fn pluck(self) -> (Self::Head, Self::Tail) {
89                match self {
90                    (x, $($from,)*) => (x, ($($from,)*))
91                }
92            }
93        }
94    }
95}
96
97macro_rules! for_each_prefix (
98    ($m:ident, [$(($arg:tt),)*]) => {
99        for_each_prefix!($m, [], [$(($arg),)*]);
100    };
101    ($m:ident, [$(($acc:tt),)*], []) => {
102        $m!($($acc,)*);
103    };
104    ($m:ident, [$(($acc:tt),)*], [($arg0:tt), $(($arg:tt),)*]) => {
105        $m!($($acc,)*);
106        for_each_prefix!($m, [$(($acc),)* ($arg0),], [$(($arg),)*]);
107    };
108);
109
110for_each_prefix! {
111    tuple_impl,
112    [(T0), (T1), (T2), (T3), (T4), (T5), (T6), (T7), (T8), (T9), (T10), (T11), (T12), (T13), (T14), (T15),]
113}
114
115macro_rules! merge_impl {
116    ([$($a:ident,)*], [$($b:ident,)*]) => {
117        // the trailing commas are for the 1 tuple
118        impl<$($a,)* $($b,)*> Merge<($($b,)*)> for ( $($a,)* ) {
119            type Output = ($($a,)* $($b,)*);
120
121            #[inline]
122            #[allow(non_snake_case)]
123            fn merge(self, x: ($($b,)*)) -> ($($a,)* $($b,)*) {
124                match (self, x) {
125                    (($($a,)*), ($($b,)*)) => ($($a,)* $($b,)*)
126                }
127            }
128        }
129    };
130}
131
132/// Helper trait that allow for merging of tuples
133pub trait Merge<T> {
134    type Output;
135    /// merge LHS with RHS returning a new tuple
136    /// that contains the elements of both tuples
137    /// ordering is preserved such that LHS elements
138    /// come before RHS elements.
139    fn merge(self, other: T) -> Self::Output;
140}
141
142macro_rules! for_each_prefix_suffix (
143    ($m:ident, [$(($acc:tt),)*], []) => {
144        $m!([$($acc,)*], []);
145    };
146    ($m:ident, [$(($acc:tt),)*], [($arg0:tt), $(($arg:tt),)*]) => {
147        $m!([$($acc,)*], [$arg0, $($arg,)*]);
148        for_each_prefix_suffix!($m, [$(($acc),)* ($arg0),], [$(($arg),)*]);
149    };
150);
151
152macro_rules! merge_impl2(
153    ($($a: ident,)*) => (
154        for_each_prefix_suffix!(
155            merge_impl,
156            [],
157            [$(($a),)*]
158        );
159    );
160);
161
162for_each_prefix! {
163    merge_impl2,
164    [(T0), (T1), (T2), (T3), (T4), (T5), (T6), (T7), (T8), (T9), (T10), (T11), (T12), (T13), (T14), (T15),]
165}
166
167/// Tries to split a tuple into two tuples
168/// if the tuple is odd sized the Right side will
169/// contain the extra element
170pub trait Split {
171    type Left;
172    type Right;
173
174    fn split(self) -> (Self::Left, Self::Right);
175}
176
177macro_rules! split_impl (
178    ($(($a:ident, $b:ident),)*) => (
179        impl<$($a,)* $($b,)*> Split for ($($a,)* $($b,)*) {
180            type Left = ($($a,)*);
181            type Right = ($($b,)*);
182            #[allow(non_snake_case)]
183            fn split(self) -> (Self::Left, Self::Right) {
184                match self {
185                    ($($a,)* $($b,)*) => (($($a,)*), ($($b,)*))
186                }
187            }
188        }
189        impl<$($a,)* $($b,)* TLast> Split for ($($a,)* $($b,)* TLast,) {
190            type Left = ($($a,)*);
191            type Right = ($($b,)* TLast,);
192            #[allow(non_snake_case)]
193            fn split(self) -> (Self::Left, Self::Right) {
194                match self {
195                    ($($a,)* $($b,)* t_last,) => (($($a,)*), ($($b,)* t_last,))
196                }
197            }
198        }
199    );
200);
201
202for_each_prefix! {
203    split_impl,
204    [((T0, T1)), ((T2, T3)), ((T4, T5)), ((T6, T7)), ((T8, T9)), ((T10, T11)), ((T12, T13)), ((T14, T15)),]
205}
206
207#[cfg(test)]
208mod test {
209    use {Append, Merge, Pluck, PluckTail, Prepend, Split};
210
211    #[test]
212    fn append() {
213        let out = (0,).append(1);
214        assert_eq!(out.0, 0);
215        assert_eq!(out.1, 1);
216        let out = out.append(2);
217        assert_eq!(out.0, 0);
218        assert_eq!(out.1, 1);
219        assert_eq!(out.2, 2);
220        let out = out.append(3);
221        assert_eq!(out.0, 0);
222        assert_eq!(out.1, 1);
223        assert_eq!(out.2, 2);
224        assert_eq!(out.3, 3);
225        let out = out.append("foo");
226        assert_eq!(out.0, 0);
227        assert_eq!(out.1, 1);
228        assert_eq!(out.2, 2);
229        assert_eq!(out.3, 3);
230        assert_eq!(out.4, "foo");
231
232        let (head, tail) = out.pluck_tail();
233        assert_eq!((head, tail), ((0, 1, 2, 3), "foo"));
234        let (head, tail) = head.pluck_tail();
235        assert_eq!((head, tail), ((0, 1, 2), 3));
236    }
237
238    #[test]
239    fn prepend() {
240        let out = (0,).prepend(1);
241        assert_eq!(out.0, 1);
242        assert_eq!(out.1, 0);
243        let out = out.prepend(2);
244        assert_eq!(out.0, 2);
245        assert_eq!(out.1, 1);
246        assert_eq!(out.2, 0);
247        let out = out.prepend(3);
248        assert_eq!(out.0, 3);
249        assert_eq!(out.1, 2);
250        assert_eq!(out.2, 1);
251        assert_eq!(out.3, 0);
252        let out = out.prepend("foo");
253        assert_eq!(out.0, "foo");
254        assert_eq!(out.1, 3);
255        assert_eq!(out.2, 2);
256        assert_eq!(out.3, 1);
257        assert_eq!(out.4, 0);
258
259        let (head, tail) = out.pluck();
260        assert_eq!((head, tail), ("foo", (3, 2, 1, 0)));
261        let (head, tail) = tail.pluck();
262        assert_eq!((head, tail), (3, (2, 1, 0)));
263    }
264
265    #[test]
266    fn merge() {
267        let a = (1, 2, 3);
268        let b = ("foo", "bar");
269        let c = a.merge(b);
270        assert_eq!(c.0, 1);
271        assert_eq!(c.1, 2);
272        assert_eq!(c.2, 3);
273        assert_eq!(c.3, "foo");
274        assert_eq!(c.4, "bar");
275
276        // assert to see if adding an empty
277        // tuple results in a tuple.
278        let a = ("test",);
279        let out = a.merge(());
280        assert_eq!(out.0, "test");
281
282        let a = ("test",);
283        let out = ().merge(a);
284        assert_eq!(out.0, "test");
285        assert_eq!(().merge(()), ());
286        assert_eq!(().merge((1,)), (1,));
287        assert_eq!((1,).merge(()), (1,));
288    }
289
290    #[test]
291    fn split() {
292        let a = (1, 2, 3);
293        let (b, c) = a.split();
294        assert_eq!(b.0, 1);
295        assert_eq!(c.0, 2);
296        assert_eq!(c.1, 3);
297        assert_eq!(().split(), ((), ()));
298        assert_eq!((1,).split(), ((), (1,)));
299        assert_eq!((1, 2).split(), ((1,), (2,)));
300        assert_eq!((1, 2, 3).split(), ((1,), (2, 3)));
301    }
302}