rs_std_ext/
tuple.rs

1//! Extension for typle types.
2//!
3//! All traits in this module are implemented with tuple no longer than 10.
4//!
5//! By default, the module only expose implementation for tuple no longer than 5.
6//! You can use longer impls by enabling the `long-tuple-impl` feature.
7//!
8//! Note that the [`TupleConcat`] trait is only implemented for those types that
9//! returns a tuple shorter than 10.
10
11/// Zip a tuple with another single value.
12///
13/// For concating two tuples, see [`TupleConcat`] for more details.
14///
15/// ## Example
16///
17/// ```rust
18/// use rs_std_ext::tuple::TupleZip;
19///
20/// let x = (10u8, 'a');
21/// let y = x.zip(-5i32);
22///
23/// assert_eq!(y, (10u8, 'a', -5i32));
24/// ```
25pub trait TupleZip<T> {
26    type Output;
27
28    /// Zip with another single value.
29    fn zip(self, val: T) -> Self::Output;
30}
31
32/// Insert a value into a tuple.
33///
34/// This is internally used behind the [`TupleInsert`] trait for convenience.
35///
36/// However, if something goes wrong with the trait solver,
37/// this trait can also be used explicitly.
38///
39/// ## Example
40///
41/// ```rust
42/// use rs_std_ext::tuple::TupleInsertExact;
43///
44/// let x = (10u8, 'a');
45/// let y = <(u8, char) as TupleInsertExact<1, _>>::insert(x, -5i32);
46///
47/// assert_eq!(y, (10u8, -5i32, 'a'));
48/// ```
49pub trait TupleInsertExact<const POS: usize, T> {
50    type Output;
51
52    fn insert(self, val: T) -> Self::Output;
53}
54
55/// Insert a value into a tuple.
56///
57/// Unlike `TupleInsertExact`, this trait moves the `const POS` to a method,
58/// so it can be used with the help of type derivation
59/// without explicitly declaring the underlying trait.
60///
61/// ## Example
62///
63/// ```rust
64/// use rs_std_ext::tuple::TupleInsert;
65///
66/// let x = (10u8, 'a');
67/// let y = x.insert::<1>(-5i32);
68///
69/// assert_eq!(y, (10u8, -5i32, 'a'));
70/// ```
71pub trait TupleInsert<T> {
72    fn insert<const POS: usize>(self, val: T) -> Self::Output
73    where
74        Self: TupleInsertExact<POS, T> + Sized,
75    {
76        <Self as TupleInsertExact<POS, T>>::insert(self, val)
77    }
78}
79
80/// Remove a value from a tuple.
81///
82/// This is internally used behind the [`TupleRemove`] trait for convenience.
83///
84/// However, if something goes wrong with the trait solver,
85/// this trait can also be used explicitly.
86///
87/// ## Example
88///
89/// ```rust
90/// use rs_std_ext::tuple::TupleRemoveExact;
91///
92/// let x = (10u8, 'a', -5i32);
93/// let y = <(u8, char, i32) as TupleRemoveExact<1>>::remove(x);
94///
95/// assert_eq!(y, (10u8, -5i32));
96/// ```
97pub trait TupleRemoveExact<const POS: usize> {
98    type Output;
99
100    fn remove(self) -> Self::Output;
101}
102
103/// Remove a value from a tuple.
104///
105/// Unlike `TupleRemoveExact`, this trait moves the `const POS` to a method,
106/// so it can be used with the help of type derivation
107/// without explicitly declaring the underlying trait.
108///
109/// ## Example
110///
111/// ```rust
112/// use rs_std_ext::tuple::TupleRemove;
113///
114/// let x = (10u8, 'a', -5i32);
115/// let y = x.remove::<1>();
116///
117/// assert_eq!(y, (10u8, -5i32));
118/// ```
119pub trait TupleRemove {
120    fn remove<const POS: usize>(self) -> Self::Output
121    where
122        Self: TupleRemoveExact<POS> + Sized,
123    {
124        <Self as TupleRemoveExact<POS>>::remove(self)
125    }
126}
127
128/// Concat two tuples.
129///
130/// This works like [`TupleZip`], but takes another tuple as input.
131///
132/// **Note:**
133/// This trait only has implementations for operations that return tuples of
134/// length 5 / 10 (`long-tuple-impl` feature) or less.
135/// That means that `(A, B, C, D, E, F, G)` cannot be concated with `(H, I, J, K, L)`.
136///
137/// ## Example
138///
139/// ```rust
140/// use rs_std_ext::tuple::TupleConcat;
141///
142/// let x = (10u8, 'a');
143/// let y = (-5i32, "foo");
144/// let z = x.concat(y);
145///
146/// assert_eq!(z, (10u8, 'a', -5i32, "foo"));
147/// ```
148pub trait TupleConcat<T> {
149    type Output;
150
151    fn concat(self, other: T) -> Self::Output;
152}
153
154mod __generated {
155    use paste::paste;
156
157    use super::{
158        TupleConcat, TupleInsert, TupleInsertExact, TupleRemove, TupleRemoveExact, TupleZip,
159    };
160
161    macro_rules! __impl_tuple_zip {
162        ($($ph:ident),+ | $tar:ident) => {
163            paste! {
164                impl<$($ph),+, $tar> TupleZip<$tar> for ($($ph,)+) {
165                    type Output = ($($ph),+, $tar);
166
167                    fn zip(self, val: $tar) -> Self::Output {
168                        let ($([< $ph:lower >],)+) = self;
169                        ($([< $ph:lower >]),+, val)
170                    }
171                }
172            }
173        };
174    }
175
176    macro_rules! __impl_tuple_insert {
177        ($($ph:ident),+ | $tar:ident) => {
178            impl<$($ph),+, $tar> TupleInsert<$tar> for ($($ph,)+) {}
179        };
180    }
181
182    macro_rules! __impl_tuple_insert_exact {
183        ($($ph:ident),+ | $tar:ident at $index:expr => $($res:ident),+) => {
184            paste! {
185                impl<$($ph),+, $tar> TupleInsertExact<$index, $tar> for ($($ph,)+) {
186                    type Output = ($($res,)+);
187
188                    fn insert(self, val: $tar) -> Self::Output {
189                        let [< $tar:lower >] = val;
190                        let ($([< $ph:lower >],)+) = self;
191                        ($([< $res:lower >]),+)
192                    }
193                }
194            }
195        };
196    }
197
198    macro_rules! __impl_tuple_remove {
199        ($($ph:ident),+) => {
200            impl<$($ph),+> TupleRemove for ($($ph,)+) {}
201        };
202    }
203
204    macro_rules! __impl_tuple_remove_exact {
205        ($($ph:ident),+ at $index:expr => $($res:ident),+) => {
206            paste! {
207                impl<$($ph),+> TupleRemoveExact<$index> for ($($ph,)+) {
208                    type Output = ($($res,)+);
209
210                    #[allow(unused_variables)]
211                    fn remove(self) -> Self::Output {
212                        let ($([< $ph:lower >],)+) = self;
213                        ($([< $res:lower >],)+)
214                    }
215                }
216            }
217        };
218    }
219
220    macro_rules! __impl_tuple_concat {
221        ($($ph:ident),+ with $($tar:ident),+) => {
222            paste! {
223                impl<$($ph),+, $($tar),+> TupleConcat<($($tar,)+)> for ($($ph,)+) {
224                    type Output = ($($ph),+, $($tar),+);
225
226                    fn concat(self, other: ($($tar,)+)) -> Self::Output {
227                        let ($([< $ph:lower >],)+) = self;
228                        let ($([< $tar:lower >],)+) = other;
229                        ($([< $ph:lower >]),+, $([< $tar:lower >]),+)
230                    }
231                }
232            }
233        };
234    }
235
236    include!(concat!(
237        env!("CARGO_MANIFEST_DIR"),
238        "/src/tuple_short_impl.rs"
239    ));
240
241    #[cfg(feature = "long-tuple-impl")]
242    mod __long_tuple_impl {
243        use paste::paste;
244    
245        use super::super::{
246            TupleConcat, TupleInsert, TupleInsertExact, TupleRemove, TupleRemoveExact, TupleZip,
247        };
248
249        include!(concat!(
250            env!("CARGO_MANIFEST_DIR"),
251            "/src/tuple_long_impl.rs"
252        ));
253    }
254}