This can be done in stable rust with generic functions or traits. Here's an example that uses a trait to pass 2-tuples to functions that accept two parameters.
fn main() {
let tuple = (0, "hello");
takes2.call(tuple);
}
fn takes2(a: u8, b: &str) {}
trait Call2<A, B, Z> {
fn call(self, args: (A, B)) -> Z;
}
impl<F, A, B, Z> Call2<A, B, Z> for F
where
F: FnOnce(A, B) -> Z,
{
fn call(self, (a, b): (A, B)) -> Z {
self(a, b)
}
}
This is likely overkill in most cases, but if you need to do this kind of thing in a lot of places, it may be worthwhile to use this generic code.
The same idea can be extended to tuples of any size. If you really want to go nuts, you can even use a macro to define similar traits for arbitrary numbers of parameters:
extern crate paste; // FYI
fn main() {
let pair = (0, "hello");
let triple = (0, "hello", 1024);
let quad = (0, "hello", 1024, 3.14);
takes2.call(pair);
takes3.call(triple);
takes4.call(quad);
}
fn takes2(a: u8, b: &str) {}
fn takes3(a: u8, b: &str, c: usize) {}
fn takes4(a: u8, b: &str, c: usize, d: f64) {}
define_tuple_calls!(A, B, C, D);
macro_rules! define_tuple_calls {
() => {};
($A:ident $(, $T:ident)* $(,)?) => {
paste::paste! {
trait [<Call $A $($T)*>]<$A, $($T,)* Z> {
fn call(self, args: ($A, $($T,)*)) -> Z;
}
impl<F, $A, $($T,)* Z> [<Call $A $($T)*>]<$A, $($T,)* Z> for F
where
F: FnOnce($A, $($T,)*) -> Z,
{
#[allow(non_snake_case)]
fn call(self, ($A, $($T,)*): ($A, $($T,)*)) -> Z {
self($A, $($T,)*)
}
}
}
define_tuple_calls!($($T,)*);
};
}
use define_tuple_calls;
If you'd like to pass a mix of tuples and isolated arguments, as in take4.call((0, "hello"), 1024, 3.14)
, this starts to get pretty hairy. I can see an approach where you would turn the inputs into a nested tuple, ((0, "hello"), 1024, 3.14)
, and pass that into the method like take4.call(((0, "hello"), 1024, 3.14))
. The call method would need to be more generic. Rather than accepting (A, B, C, D)
, it would accept impl FlattensTo<(A, B, C, D)>
, where FlattensTo<T>
is a trait that works like Into<T>
, which you need to define and implement for arbitrary combinations of nested tuples or values. To implement this comprehensively without a ton of redundant code, you would likely need to write a procedural macro.