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

```rust struct Vector(T);

fortuples! { #[tuples::membertype(f32)] #[tuples::minsize(2)] #[tuples::maxsize(3)] #[tuples::tuplename(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.

```rust trait Trait { type Ret; type Arg;

fn test(arg: Self::Arg) -> Self::Ret;

} ```

impltraitfor_tuples

```rust

[implfortuples(5)]

impl Trait for Tuple { fortuples!( type Ret = ( #( Tuple::Ret ),* ); ); fortuples!( type Arg = ( #( Tuple::Arg ),* ); );

fn test(arg: Self::Arg) -> Self::Ret {
    for_tuples!( ( #( Tuple::test(arg.Tuple) ),* ) )
}

} ```

fortuples

```rust fortuples! { #[tuples::max_size(5)] // <-- optional, default = 16 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
impltraitfor_tuples

```rust

[implfortuples(5)]

trait Notify { fn notify(&self); } ```

fortuples::auto_impl

```rust

[fortuples::auto_impl]

[tuples::max_size(5)] // <-- optional, default = 16

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]).

```rust 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)] // +----- ^^^^^^^^^^^ // | The fortuples! macro will generate implementations starting with the empty tuple. // | // | Due to the min_size setting, // | the implementations will start from the (Member0,) tuple.

impl Trait for #Tuple
// +----------- ^^^^^
// | a meta-variable that will expand to
// | `(Member0,)`, `(Member0, Member1)`, and so on.

where
    #(#Member: Trait<FixedType = i32>),*
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// | A repetition -- the code inside the `#(...),*`
// | will expand as many times as many elements are in the current #Tuple.
// |
// | Inside the i-th code fragment, the #Member meta-variable will be substituted
// | by the i-th member type of the current #Tuple.
{
    // The `Ret` type will be a tuple consisting of the `Ret` types
    // from the current #Tuple member types
    type Ret = (#(#Member::Ret),*);

    // The `Arg` type will be a tuple consisting of the `Arg` types
    // from the current #Tuple member types
    type Arg = (#(#Member::Arg),*);

    // The `VALUE` will be a sum of all `VALUE`s of the #Tuple member types.
    const VALUE: i32 = #(#Member::VALUE)+*;
    // +------------------------------- ^
    // | Note that a `+` sign separates the `VALUE`s.

    const LENGTH: usize = #len(Tuple);
    // +----------------- ^^^^^^^^^^^
    // | This expands to the current #Tuple length.

    type FixedType = i32;

    fn test_assoc_fn(arg: Self::Arg) -> Self::Ret {
        ( #(#Member::test_assoc_fn(#arg)),* )
        // +----------------------- ^^^
        // | Any identifier after the `#` sign that is neither
        // | #Tuple, #Member, nor #len(Tuple)
        // | is interpreted as a tuple variable.
        // |
        // | So the above code will expand like this:
        // | ```
        // |    (
        // |        Member0::test_assoc_fn(arg.0),
        // |        Member1::test_assoc_fn(arg.1),
        // |        ...
        // |        MemberN::test_assoc_fn(arg.N),
        // |    )
        // | ```
        // | where `N` equals `#len(Tuple)`
    }

    fn test_self_fn(&self) -> Result<(), ()> {
        #(#self.test_self_fn()?;)*
        // +-------------------- ^
        // | Note that there is no separator here.

        Ok(())
    }
}

} ```

Show the example without comments

fortuples! proc-macro (without comments)

```rust 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),* { 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.

```rust

[fortuples::auto_impl]

trait AutoImplTrait { fn test(&self, a: i32, b: &f32); } ```