fortuples

Procedural macros to generalize inherent and trait implementations over tuples.
Introduction
When it is a need to implement either a trait or a generalized type for a combination of tuples,
Rust requires separate implementations to be provided for each tuple variety manually.
This crate provides a proc-macro fortuples! to write code templates similar to the quote! macro.
This macro will expand the provided code template for each tuple variety.
Also, an attribute macro #[auto_impl] that implements a given trait for tuple combinations in a completely automatic way.
This crate is inspired by the impl_trait_for_tuples.
Differences from impl_trait_for_tuples
You can write inherent implementations
struct Vector<T>(T);
fortuples! {
#[tuples::member_type(f32)]
#[tuples::min_size(2)]
#[tuples::max_size(3)]
#[tuples::tuple_name(Coords)]
impl Vector<#Coords> {
fn length(&self) -> f32 {
let coords = &self.0;
(#(#coords * #coords)+*).sqrt()
}
}
}
You don't need to use a custom keyword for_tuples! inside the implementation body
Instead, the fortuples! macro follows the quote!-like syntax without extra tokens.
trait Trait {
type Ret;
type Arg;
fn test(arg: Self::Arg) -> Self::Ret;
}
impl_trait_for_tuples
#[impl_for_tuples(5)]
impl Trait for Tuple {
for_tuples!( type Ret = ( #( Tuple::Ret ),* ); );
for_tuples!( type Arg = ( #( Tuple::Arg ),* ); );
fn test(arg: Self::Arg) -> Self::Ret {
for_tuples!( ( #( Tuple::test(arg.Tuple) ),* ) )
}
}
fortuples
fortuples! {
#[tuples::max_size(5)] impl Trait for #Tuple
where
#(#Member: Trait),*
{
type Ret = ( #(#Member::Ret),* );
type Arg = ( #(#Member::Arg),* );
fn test(arg: Self::Arg) -> Self::Ret {
( #(#Member::test(#arg)),* )
}
}
}
Separate attribute macro for full-automatic implementation
impl_trait_for_tuples
#[impl_for_tuples(5)]
trait Notify {
fn notify(&self);
}
fortuples::auto_impl
#[fortuples::auto_impl]
#[tuples::max_size(5)] trait Notify {
fn notify(&self);
}
Examples
fortuples! proc-macro
Here is commented example of fortuples! usage.
See the fortuples! macro documentation to learn about the macro settings (like #[tuples::min_size]).
trait Trait {
type Ret;
type Arg;
type FixedType;
const VALUE: i32;
const LENGTH: usize;
fn test_assoc_fn(arg: Self::Arg) -> Self::Ret;
fn test_self_fn(&self) -> Result<(), ()>;
}
fortuples! {
#[tuples::min_size(1)]
impl Trait for #Tuple
where
#(#Member: Trait<FixedType = i32>),*
{
type Ret = (#(#Member::Ret),*);
type Arg = (#(#Member::Arg),*);
const VALUE: i32 = #(#Member::VALUE)+*;
const LENGTH: usize = #len(Tuple);
type FixedType = i32;
fn test_assoc_fn(arg: Self::Arg) -> Self::Ret {
( #(#Member::test_assoc_fn(#arg)),* )
}
fn test_self_fn(&self) -> Result<(), ()> {
#(#self.test_self_fn()?;)*
Ok(())
}
}
}
fortuples! proc-macro (without comments)
trait Trait {
type Ret;
type Arg;
type FixedType;
const VALUE: i32;
const LENGTH: usize;
fn test_assoc_fn(arg: Self::Arg) -> Self::Ret;
fn test_self_fn(&self) -> Result<(), ()>;
}
fortuples! {
#[tuples::min_size(1)]
impl Trait for #Tuple
where
#(#Member: Trait<FixedType = i32>),*
{
type Ret = (#(#Member::Ret),*);
type Arg = (#(#Member::Arg),*);
const VALUE: i32 = #(#Member::VALUE)+*;
const LENGTH: usize = #len(Tuple);
type FixedType = i32;
fn test_assoc_fn(arg: Self::Arg) -> Self::Ret {
( #(#Member::test_assoc_fn(#arg)),* )
}
fn test_self_fn(&self) -> Result<(), ()> {
#(#self.test_self_fn()?;)*
Ok(())
}
}
}
auto_impl attribute
There is an option to implement a trait
in a completely automatic way using the auto_impl attribute.
This attribute will automatically generate implementations of the given trait
for tuple combinations.
See the auto_impl documentation to learn about the
attribute's settings and limitations.
#[fortuples::auto_impl]
trait AutoImplTrait {
fn test(&self, a: i32, b: &f32);
}