0
votes

I have a lot of lengthy and repetitive trait constraint chains in my implementations that I want to replace. Type aliasing for traits looks great but it is still an unstable feature.

I tried using something like this

trait NumericTrait : Float + FromPrimitive + ToPrimitive + RealField + Copy + Clone + Debug + 'static {}

However this leads to issues since NumericTrait is not explicitly implemented for the types I am concerned with. Rather, all of the base traits are.

I am now thinking macros is the way to go, so I tried the following:

macro_rules! numeric_float_trait {
    () => {
        Float + FromPrimitive + ToPrimitive + RealField + Copy + Clone + Debug + 'static
    };
}

struct SomeStruct;

impl<T> SomeStruct 
where
    T: numeric_float_trait!()
{
    fn do_things(num: T) {
        println!("I got this num {:?}", num);
    }
}

However the syntax is incorrect and the compiler will not accept it. How do I achieve this desired functionality of essentially pasting a list of traits via a macro?

1
With the NumericTrait approach, you can add a generic implementation for all T that satisfy the trait bounds. This requires to write the trait bounds a second time, but that's acceptable in my opinion. - Sven Marnach

1 Answers

1
votes

You can declare the macro that creates a trait you wanted like following:

macro_rules! declare_trait {
    ($trait_type:ident,$trait_name:ident) => {
        trait $trait_name:
            $trait_type
            + num::FromPrimitive
            + num::ToPrimitive
            + alga::general::RealField
            + ::std::marker::Copy
            + ::std::clone::Clone
            + ::std::fmt::Debug
            + 'static
        {
        }

}

In your macro you need to define the implementation of any T that has the following traits given:

impl<T> $trait_name for T where
    T: $trait_type
      + num::FromPrimitive
      + num::ToPrimitive
      + alga::general::RealField
      + ::std::marker::Copy
      + ::std::clone::Clone
      + ::std::fmt::Debug
      + 'static
{
}

Now you only need to call this macro to declare the trait as you desire:

declare_trait!(Float, NumericFloatTrait); // Float is type and NumericFloatTrait is the name here

After you declare your trait you can use it anywhere you like:

struct SomeStruct;

impl SomeStruct {
    fn do_things_with_float<T: NumericFloatTrait>(num: T) {
        println!("I got this float {:?}", num);
    }
}

Playground