[][src]Attribute Macro duplicate::duplicate

#[duplicate]

Duplicates and substitutes given identifiers for different code in each duplicate.

Substitution identifiers can be inserted into the code, which will be substituted with the different given code in each duplicate version of the original code.

Short Syntax

use duplicate::duplicate;
trait IsMax {
  fn is_max(&self) -> bool;
}

#[duplicate(
  int_type  [ u8 ]  [ u16 ]    [ u32 ]
  max_value [ 255 ] [ 65_535 ] [ 4_294_967_295 ]
)]
impl IsMax for int_type {
  fn is_max(&self) -> bool {
    *self == max_value
  }
}

assert!(!42u8.is_max());
assert!(!42u16.is_max());
assert!(!42u32.is_max());

The implementation of IsMax is duplicated 3 times:

  1. For the type u8 and the its maximum value 255.
  2. For the type u16 and the its maximum value 65_535 .
  3. For the type u32 and the its maximum value 4_294_967_295 .

This syntax must start with an identifier and then provice a set of substitutions for it. The substitutions must be enclosed in [], {}, or (), but are otherwise free. Then another substituion identifier with the same number of substitutions as the previous identifier. Repeat as many as necessary.

Verbose Syntax

use duplicate::duplicate;
trait IsMax {
  fn is_max(&self) -> bool;
}

#[duplicate(
  [
    int_type  [ u8 ]
    max_value [ 255 ]
  ]
  [
    int_type  [ u16 ]
    max_value [ 65_535 ]
  ]
  [
    max_value [ 4_294_967_295 ]
    int_type  [ u32 ]
  ]
)]
impl IsMax for int_type {
  fn is_max(&self) -> bool {
    *self == max_value
  }
}

assert!(!42u8.is_max());
assert!(!42u16.is_max());
assert!(!42u32.is_max());

Has the same functionality as the previous short-syntax example.

For each duplicate needed, a substitution group must be given enclosed in [], {}, or (). A substitution group is a set of identifiers and substitution pairs, like in the short syntax, but there can only be one substitution per identifier. All substitution groups must have the same identifiers, however their order is unimportant, as can be seen from the last substitution group above, where max_value comes before int_type.

Nested Invocation

use duplicate::duplicate;
trait IsNegative {
  fn is_negative(&self) -> bool;
}

#[duplicate(
  #[                                  // -+
    int_type_nested [u8] [u16] [u32]  //  |
  ][                                  //  |
    [                                 //  | Nested invocation producing 3
      int_type [ int_type_nested ]    //  | substitution groups
      implementation [ false ]        //  |
    ]                                 //  |
  ]                                   // -+
  [                                   // -+
    int_type [ i8 ]                   //  | Substitution group 4
    implementation [ *self < 0 ]      //  |
  ]                                   // -+
)]
impl IsNegative for int_type {
  fn is_negative(&self) -> bool {
    implementation
  }
}

assert!(!42u8.is_negative());
assert!(!42u16.is_negative());
assert!(!42u32.is_negative());
assert!(!42i8.is_negative());

This implements IsNegative 4 times:

  1. For the type u8 with the implementation of the method simply returning false. 2. For the type u16 the same way as u8.
  2. For the type u32 the same way as u8 and u16.
  3. For i8 with the implementation of the method checking whether it's less than 0.

We used # to start a nested invocation of the macro. In it, we use the identifier int_type_nested to substitute the 3 unsigned integer types into the body of the nested invocation, which is a substitution group for the outer macro invocation. This therefore produces the three substitution groups that makes the outer macro make the duplicates for the unsigned integers.

This code is identical to the following, which doesn't use nested invocation:

#[duplicate(
  [
    int_type [ u8 ]
    implementation [ false ]
  ]
  [
    int_type [ u16 ]
    implementation [ false ]
  ]
  [
    int_type [ u32 ]
    implementation [ false ]
  ]
  [
    int_type [ i8 ]
    implementation [ *self < 0 ]
  ]
)]
impl IsNegative for int_type {
  fn is_negative(&self) -> bool {
    implementation
  }
}