An open API service indexing awesome lists of open source software.

https://github.com/mrshiposha/fortuples

Procedural macros to generalize inherent and trait implementations over tuples
https://github.com/mrshiposha/fortuples

crate for generalization impl macro macros metaprogramming proc-macro rust trait tuple tuples

Last synced: 6 months ago
JSON representation

Procedural macros to generalize inherent and trait implementations over tuples

Awesome Lists containing this project

README

          

# fortuples
[![](https://docs.rs/fortuples/badge.svg)](https://docs.rs/fortuples/) [![](https://img.shields.io/crates/v/fortuples.svg)](https://crates.io/crates/fortuples) [![](https://img.shields.io/crates/d/fortuples.svg)](https://crates.io/crates/fortuples)

Procedural macros to generalize inherent and trait implementations over tuples.

* [Introduction](#introduction)
* [Differences from `impl_trait_for_tuples`](#differences-from-impl_trait_for_tuples)
* [Examples](#examples)

## 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!`](https://github.com/dtolnay/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`](https://github.com/bkchr/impl-trait-for-tuples)._

----

## Differences from `impl_trait_for_tuples`

##### You can write inherent implementations
```rust
struct Vector(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!`](https://github.com/dtolnay/quote)-like syntax without extra tokens.

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

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

###### impl_trait_for_tuples

```rust
#[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

```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

###### impl_trait_for_tuples

```rust
#[impl_for_tuples(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!`](https://docs.rs/fortuples/latest/fortuples/macro.fortuples.html) 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),*
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// | 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`](https://docs.rs/fortuples/latest/fortuples/attr.auto_impl.html) documentation to learn about the
attribute's settings and limitations._

```rust
#[fortuples::auto_impl]
trait AutoImplTrait {
fn test(&self, a: i32, b: &f32);
}
```