shrimple_parser/
tuple.rs

1//! This module contains utilities for working with generic tuples, such as:
2//! - Extracting & transforming the N-th element of a tuple;
3//! - Extracting N first elements of a tuple or splitting it;
4//! - Extending a tuple from both ends;
5//! - Reversing a tuple.
6//! - Copying/cloning a tuple element per element. (i.e. turn `(&T, &U)` into `(T, U)`
7//!
8//! See the [`Tuple`] trait or the free-standing functions.
9
10/// The trait for a tuple that has the N-th element, the backbone of the [`Tuple::nth`] function.
11///
12/// The associated functions are not to be used directly, instead use the equivalent functions
13/// or methods of the [`Tuple`] trait.
14#[diagnostic::on_unimplemented(
15    message = "`{Self}` is not a tuple, doesn't have an element #{N}, or is too long",
16    note = "At the moment, the trait is implemented only for tuples up to length 8"
17)]
18pub trait Index<const N: usize>: Tuple {
19    /// The N-th element of the tuple.
20    type Nth;
21    /// The tuple with its N-th element mapped to `U`.
22    type NthMapped<U>;
23
24    /// Returns the N-th element of the tuple.
25    fn nth(this: Self) -> Self::Nth;
26
27    /// Returns a reference to the N-th element of the tuple.
28    fn nth_ref(this: &Self) -> &Self::Nth;
29
30    /// Returns the tuple with the N-th element transformed by `f`
31    fn map_nth<U>(this: Self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>;
32}
33
34/// The trait for a tuple that has at least N elements.
35///
36/// The backbone of the [`Tuple::first_n`] function.
37///
38/// The associated functions are not to be used directly, instead use the equivalent functions
39/// or methods of the [`Tuple`] trait.
40#[diagnostic::on_unimplemented(
41    message = "`{Self}` is not tuple, has less than {N} elements, or is too long",
42    note = "At the moment, the trait is implemented only for tuples up to length 8"
43)]
44pub trait Slice<const N: usize>: Tuple {
45    /// A tuple containing the first N elements of the original tuple.
46    type FirstN;
47
48    /// A tuple with the first N elements of the original tuple.
49    type FirstNStripped;
50
51    /// Return the first N elements of the tuple as a tuple.
52    fn first_n(this: Self) -> Self::FirstN;
53
54    /// Returns the tuple without the first N elements
55    fn strip_first_n(this: Self) -> Self::FirstNStripped;
56
57    /// Splits the tuple into 2, with the 1st tuple having the 1st N element,
58    /// and the 2nd tuple having the rest.
59    fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped);
60}
61
62/// The trait for a tuple, all elements of which are references to [`Clone`]-able values.
63///
64/// The backbone of the [`Tuple::cloned`] function.
65///
66/// The associated functions are not to be used directly, instead use the equivalent free-standing
67/// functions or methods of the [`Tuple`] trait.
68pub trait CloneableRefs: Tuple {
69    /// The result of [`CloneableRefs::cloned`]
70    type Cloned;
71
72    /// Clone the tuple element-wise, e.g. turn `(&T, &U)` into `(T, U)`
73    fn cloned(this: Self) -> Self::Cloned;
74}
75
76/// The trait for a tuple, all elements of which are references to [`Copy`]-able values.
77///
78/// The backbone of the [`Tuple::copied`] function.
79///
80/// The associated functions are not to be used directly, instead use the equivalent free-standing
81/// functions or methods of the [`Tuple`] trait.
82pub trait CopiableRefs: Tuple {
83    /// The result of [`CopiableRefs::copied`]
84    type Copied;
85
86    /// Copy the tuple element-wise, e.g. turn `(&T, &U)` into `(T, U)`
87    fn copied(this: Self) -> Self::Copied;
88}
89
90macro_rules! impl_nth_methods {
91    ($n:literal, $name:ident, $ref_name:ident, $map_name:ident) => {
92        #[doc = concat!("Returns the ", stringify!($name), " element of the tuple.")]
93        #[doc = "For a more generic function, see [`Tuple::nth`]"]
94        fn $name(self) -> Self::Nth
95        where
96            Self: Index<$n>,
97        {
98            Index::nth(self)
99        }
100
101        #[doc = concat!("Returns a reference to the ", stringify!($name), " element of the tuple.")]
102        #[doc = "For a more generic function, see [`Tuple::nth_ref`]"]
103        fn $ref_name(&self) -> &Self::Nth
104        where
105            Self: Index<$n>,
106        {
107            Index::nth_ref(self)
108        }
109
110        #[doc = concat!("Transforms the ", stringify!($name), " element of the tuple with `f`.")]
111        #[doc = "For a more generic function, see [`Tuple::map_nth`]"]
112        fn $map_name<U>(self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>
113        where
114            Self: Index<$n>,
115        {
116            Index::map_nth(self, f)
117        }
118    };
119}
120
121/// Trait for a generic tuple.
122#[diagnostic::on_unimplemented(
123    message = "`{Self}` is not a tuple or is too long",
124    note = "At the moment, the trait is implemented only for tuples up to length 8"
125)]
126pub trait Tuple: Sized {
127    /// The tuple + a new element at the end, the result of [`Tuple::append`]
128    type Appended<NewElement>;
129
130    /// The tuple + a new element at the start, the result of [`Tuple::prepend`]
131    type Prepended<NewElement>;
132
133    /// The tuple with its elements in reverse order, the result of [`Tuple::rev`]
134    type Reversed;
135
136    /// Adds `new_element` to the end of the tuple.
137    /// Also see [`append`]
138    fn append<NewElement>(self, new_element: NewElement) -> Self::Appended<NewElement>;
139
140    /// Adds `new_element` to the start of the tuple.
141    /// Also see [`prepend`]
142    fn prepend<NewElement>(self, new_element: NewElement) -> Self::Prepended<NewElement>;
143
144    /// Returns the tuple with its elements in reverse order.
145    /// Also see [`rev`]
146    fn rev(self) -> Self::Reversed;
147
148    /// Clones the tuple element-wise, e.g. turn `(&T, &U)` into `(T, U)`
149    /// Also see [`cloned`]
150    fn cloned(self) -> Self::Cloned
151    where
152        Self: CloneableRefs,
153    {
154        CloneableRefs::cloned(self)
155    }
156
157    /// Copies the tuple element-wise, e.g. turn `(&T, &U)` into `(T, U)`
158    /// Also see [`copied`]
159    fn copied(self) -> Self::Copied
160    where
161        Self: CopiableRefs,
162    {
163        CopiableRefs::copied(self)
164    }
165
166    /// Returns the `N`-th element of the tuple.
167    /// For shortcuts see [`Tuple::first`], [`Tuple::second`], [`Tuple::third`]
168    fn nth<const N: usize>(self) -> Self::Nth
169    where
170        Self: Index<N>,
171    {
172        Index::nth(self)
173    }
174
175    /// Returns a reference to the `N`-th element of the tuple.
176    /// For shortcuts see [`Tuple::first_ref`], [`Tuple::second_ref`], [`Tuple::third_ref`]
177    fn nth_ref<const N: usize>(&self) -> &Self::Nth
178    where
179        Self: Index<N>,
180    {
181        Index::nth_ref(self)
182    }
183
184    /// Returns a function that transforms the N-th element of a tuple with `f`.
185    /// For common shortcuts, see [`Tuple::map_first`], [`Tuple::map_second`], [`Tuple::map_third`]
186    fn map_nth<const N: usize, U>(self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U>
187    where
188        Self: Index<N>,
189    {
190        Index::map_nth(self, f)
191    }
192
193    impl_nth_methods!(0, first, first_ref, map_first);
194    impl_nth_methods!(1, second, second_ref, map_second);
195    impl_nth_methods!(2, third, third_ref, map_third);
196
197    /// Returns a tuple that containing the first N elements of the original tuple.
198    /// The other elements are discarded.
199    fn first_n<const N: usize>(self) -> Self::FirstN
200    where
201        Self: Slice<N>,
202    {
203        Slice::first_n(self)
204    }
205
206    /// Returns the original tuple with its first N elements discarded.
207    /// Logical complement of [`Tuple::first_n`]
208    fn strip_first_n<const N: usize>(self) -> Self::FirstNStripped
209    where
210        Self: Slice<N>,
211    {
212        Slice::strip_first_n(self)
213    }
214
215    /// Splits the tuple into one with the first N elements and one with the rest.
216    fn split<const N: usize>(self) -> (Self::FirstN, Self::FirstNStripped)
217    where
218        Self: Slice<N>,
219    {
220        Slice::split(self)
221    }
222}
223
224macro_rules! rev {
225    ($($x:ident,)*) => { rev!(| $($x,)* |) };
226    (| $x:ident, $($rest:ident,)* | $($rev:ident,)*) => { rev!(| $($rest,)* | $x, $($rev,)*) };
227    (| | $($rev:ident,)*) => { ($($rev,)*) };
228}
229
230macro_rules! impl_tuple_traits {
231    ($length:literal - $($n:literal : $t:ident),*) => {
232        impl_tuple_traits!([] [$($n:$t,)*] [$($t),*]);
233
234        impl<$($t),*> Slice<$length> for ($($t,)*) {
235            type FirstN = Self;
236            type FirstNStripped = ();
237
238            fn first_n(this: Self) -> Self::FirstN { this }
239            fn strip_first_n(_: Self) -> Self::FirstNStripped {}
240            fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped) { (this, ()) }
241        }
242
243        #[allow(non_snake_case)]
244        impl<$($t: Clone),*> CloneableRefs for ($(&$t,)*) {
245            type Cloned = ($($t,)*);
246
247            #[allow(clippy::unused_unit)]
248            fn cloned(this: Self) -> Self::Cloned {
249                let ($($t,)*) = this;
250                ($($t.clone(),)*)
251            }
252        }
253
254        #[allow(non_snake_case)]
255        impl<$($t: Copy),*> CopiableRefs for ($(&$t,)*) {
256            type Copied = ($($t,)*);
257
258            #[allow(clippy::unused_unit)]
259            fn copied(this: Self) -> Self::Copied {
260                let ($($t,)*) = this;
261                ($(*$t,)*)
262            }
263        }
264
265        #[allow(non_snake_case)]
266        impl<$($t),*> Tuple for ($($t,)*) {
267            type Appended<NewElement> = ($($t,)* NewElement,);
268            type Prepended<NewElement> = (NewElement, $($t,)*);
269            type Reversed = rev!($($t,)*);
270
271            fn append<NewElement>(self, new_element: NewElement) -> Self::Appended<NewElement> {
272                let ($($t,)*) = self;
273                ($($t,)* new_element,)
274            }
275
276            fn prepend<NewElement>(self, new_element: NewElement) -> Self::Prepended<NewElement> {
277                let ($($t,)*) = self;
278                (new_element, $($t,)*)
279            }
280
281            fn rev(self) -> Self::Reversed {
282                let ($($t,)*) = self;
283                rev!($($t,)*)
284            }
285        }
286    };
287
288    ($prev:tt [] $t:tt) => {};
289
290    ([$($prev:ident),*] [$id:literal : $nth:ident, $($next_id:literal : $next:ident,)*] [$($t:ident),+]) => {
291        #[allow(non_snake_case)]
292        impl<$($t),+> Index<$id> for ($($t,)+) {
293            type Nth = $nth;
294            type NthMapped<U> = ($($prev,)* U, $($next,)*);
295
296            #[allow(unused)]
297            fn nth(this: Self) -> Self::Nth {
298                let ($($t,)+) = this;
299                $nth
300            }
301
302            #[allow(unused)]
303            fn nth_ref(this: &Self) -> &Self::Nth {
304                let ($($t,)+) = this;
305                $nth
306            }
307
308            fn map_nth<U>(this: Self, f: impl FnOnce(Self::Nth) -> U) -> Self::NthMapped<U> {
309                let ($($t,)+) = this;
310                ($($prev,)* f($nth), $($next,)*)
311            }
312        }
313
314        #[allow(non_snake_case)]
315        impl<$($t),+> Slice<$id> for ($($t,)+) {
316            type FirstN = ($($prev,)*);
317            type FirstNStripped = ($nth, $($next,)*);
318
319            #[allow(unused, clippy::unused_unit)]
320            fn first_n(this: Self) -> Self::FirstN {
321                let ($($t,)+) = this;
322                ($($prev,)*)
323            }
324
325            #[allow(unused)]
326            fn strip_first_n(this: Self) -> Self::FirstNStripped {
327                let ($($t,)+) = this;
328                ($nth, $($next,)*)
329            }
330
331            fn split(this: Self) -> (Self::FirstN, Self::FirstNStripped) {
332                let ($($t,)+) = this;
333                (($($prev,)*), ($nth, $($next,)*))
334            }
335        }
336
337        impl_tuple_traits!([$($prev,)* $nth] [$($next_id:$next,)*] [$($t),+]);
338    };
339}
340
341impl_tuple_traits!(0 -);
342impl_tuple_traits!(1 - 0: T0);
343impl_tuple_traits!(2 - 0: T0, 1: T1);
344impl_tuple_traits!(3 - 0: T0, 1: T1, 2: T2);
345impl_tuple_traits!(4 - 0: T0, 1: T1, 2: T2, 3: T3);
346impl_tuple_traits!(5 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4);
347impl_tuple_traits!(6 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5);
348impl_tuple_traits!(7 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6);
349impl_tuple_traits!(8 - 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6, 7: T7);
350
351#[rustfmt::skip]
352macro_rules! impl_nth_fn {
353    ($n:literal, $name:ident, $ref_name:ident, $map_name:ident) => {
354        #[doc = concat!("Returns the ", stringify!($name), " element of the tuple.")]
355        #[doc = "For a more generic function, see [`Tuple::nth`]"]
356        pub fn $name<T: Index<$n>>(tuple: T) -> T::Nth {
357            Index::nth(tuple)
358        }
359
360        #[doc = concat!("Returns a reference to the ", stringify!($name), " element of the tuple.")]
361        #[doc = "For a more generic function, see [`Tuple::nth_ref`]"]
362        pub fn $ref_name<T: Index<$n>>(tuple: &T) -> &T::Nth {
363            Index::nth_ref(tuple)
364        }
365
366        #[doc = concat!("Returns a function that transforms the ", stringify!($name), " element of a tuple with `f`.")]
367        #[doc = "For a more generic function, see [`Tuple::map_nth`]"]
368        pub fn $map_name<T: Index<$n>, U>(
369            mut f: impl FnMut(T::Nth) -> U,
370        ) -> impl FnMut(T) -> T::NthMapped<U> {
371            move |tuple| Index::map_nth(tuple, &mut f)
372        }
373    };
374}
375
376impl_nth_fn!(0, first, first_ref, map_first);
377impl_nth_fn!(1, second, second_ref, map_second);
378impl_nth_fn!(2, third, third_ref, map_third);
379
380/// Adds `new_element` to the end of a tuple and returns the resulting new tuple.
381pub fn append<T: Tuple, U: Clone>(new_element: U) -> impl Fn(T) -> T::Appended<U> {
382    move |tuple| tuple.append(new_element.clone())
383}
384
385/// Adds `new_element` to the beginning of a tuple and returns the resulting new tuple.
386pub fn prepend<U: Clone, T: Tuple>(new_element: U) -> impl Fn(T) -> T::Prepended<U> {
387    move |tuple| tuple.prepend(new_element.clone())
388}
389
390/// Turns `T` into a tuple with 1 element, `T`
391pub const fn tuple<T>(x: T) -> (T,) {
392    (x,)
393}
394
395/// Reverses the tuple.
396pub fn rev<T: Tuple>(x: T) -> T::Reversed {
397    x.rev()
398}
399
400/// Clones the tuple element-wise, e.g. turns `(&T, &U)` into `(T, U)`
401pub fn cloned<T: CloneableRefs>(x: T) -> T::Cloned {
402    CloneableRefs::cloned(x)
403}
404
405/// Copies the tuple element-wise, e.g. turns `(&T, &U)` into `(T, U)`
406pub fn copied<T: CopiableRefs>(x: T) -> T::Copied {
407    CopiableRefs::copied(x)
408}
409
410/// Generates a closure that constructs a struct from a tuple.
411/// The struct fields must be exactly in the order in which they're expected to be in the tuple.
412/// ```rust
413/// # fn main() {
414/// use shrimple_parser::{Parser, pattern::parse_until_ex, from_tuple};
415///
416/// #[derive(Debug, PartialEq, Eq)]
417/// struct Example<'src> { a: &'src str, b: &'src str }
418///
419/// let input = "abc|def|";
420/// let res = parse_until_ex::<_, ()>("|")
421///     .and(parse_until_ex("|"))
422///     .map_out(from_tuple!(Example { a, b }))
423///     .parse(input);
424/// assert_eq!(res, Ok(("", Example { a: "abc", b: "def" })))
425/// # }
426/// ```
427#[macro_export]
428macro_rules! from_tuple {
429    ($name:ident { $($field:ident),* $(,)? }) => { |($($field,)*)| $name { $($field),* } };
430}
431
432#[macro_export]
433#[doc(hidden)]
434macro_rules! last {
435    ($_:tt $($rest:tt)+) => { $($rest)+ };
436    ($last:tt) => { $last };
437}
438
439/// Generates a closure that calls a function with a tuple's contents as it arguments.
440/// The input can be anything as long as the last token contains all the arguments parenthesized.
441/// ```rust
442/// # fn main() {
443/// use shrimple_parser::{Parser, pattern::parse_until_ex, call};
444///
445/// fn len_sum(a: &str, b: &str) -> usize {
446///     a.len() + b.len()
447/// }
448///
449/// let input = "abc|def|";
450/// let res = parse_until_ex::<_, ()>("|")
451///     .and(parse_until_ex("|"))
452///     .map_out(call!(len_sum(a, b)))
453///     .parse(input);
454/// assert_eq!(res, Ok(("", 6)))
455/// # }
456/// ```
457#[macro_export]
458macro_rules! call {
459    ($($args:tt)*) => { |$crate::last!($($args)*)| $($args)* };
460}