The typle crate provides the ability to constrain generic arguments to be
tuples and supports manipulation of the tuple components.
For example, to define a function to zip a pair of tuples into a tuple of pairs:
#[typle(Tuple for 0..=12)]
pub fn zip<A: Tuple, B: Tuple>(a: A, b: B) -> (typle! {
i in .. => (A<{i}>, B<{i}>)
}) {
(typle! {
i in .. => (a[[i]], b[[i]])
})
}The types A and B are generic but are constrained to be tuples. The tuples
can have 0 to 12 components of any (sized) type, but both tuples must have the
same length.
The typle! macro loops over an index returning a new tuple with the
specified components. For the function return type it creates a type tuple:
((A<0>, B<0>), (A<1>, B<1>),...). In the function body it creates a value tuple:
((a.0, b.0), (a.1, b.1),...).
assert_eq!(
zip(("LHR", "FCO", "ZRH"), (51.5, 41.8, 47.5)),
(("LHR", 51.5), ("FCO", 41.8), ("ZRH", 47.5))
);
assert_eq!(
zip((2.0, "test"), (Some(9u8), ('a', 'b'))),
((2.0, Some(9u8)), ("test", ('a', 'b')))
);
assert_eq!(
zip((), ()),
()
);A common use of typle is to implement a trait for tuples of multiple lengths.
Compared to using declarative macros, the typle code looks more Rust-like and
provides access to individual components and their position.
trait HandleStuff {
type Output;
fn handle_stuff(&self, input: Input) -> Self::Output;
}
struct MultipleHandlers<T> {
handlers: T,
}
#[typle(Tuple for 1..=3)]
impl<T> HandleStuff for MultipleHandlers<T>
where
T: Tuple, // `T` is a tuple with 1 to 3 components.
T<_>: HandleStuff, // All components implement `HandleStuff`.
{
// Return a tuple of output from each handler applied to the same input.
type Output = (typle! {i in .. => T<{i}>::Output});
fn handle_stuff(&self, input: Input) -> Self::Output {
(
typle! {
i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())
},
// Avoid expensive clone for the last handler.
self.handlers[[T::LAST]].handle_stuff(input),
)
}
}This generates the implementations
impl<T0> HandleStuff for MultipleHandlers<(T0,)>
where
T0: HandleStuff,
{
type Output = (T0::Output,);
fn handle_stuff(&self, input: Input) -> Self::Output {
(self.handlers.0.handle_stuff(input),)
}
}
impl<T0, T1> HandleStuff for MultipleHandlers<(T0, T1)>
where
T0: HandleStuff,
T1: HandleStuff,
{
type Output = (T0::Output, T1::Output);
fn handle_stuff(&self, input: Input) -> Self::Output {
(
self.handlers.0.handle_stuff(input.clone()),
self.handlers.1.handle_stuff(input),
)
}
}
impl<T0, T1, T2> HandleStuff for MultipleHandlers<(T0, T1, T2)>
where
T0: HandleStuff,
T1: HandleStuff,
T2: HandleStuff,
{
type Output = (T0::Output, T1::Output, T2::Output);
fn handle_stuff(&self, input: Input) -> Self::Output {
(
self.handlers.0.handle_stuff(input.clone()),
self.handlers.1.handle_stuff(input.clone()),
self.handlers.2.handle_stuff(input),
)
}
}See the crate documentation for more examples.