[−][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:
- For the type
u8
and the its maximum value255
. - For the type
u16
and the its maximum value65_535
. - For the type
u32
and the its maximum value4_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:
- For the type
u8
with the implementation of the method simply returningfalse
. 2. For the typeu16
the same way asu8
. - For the type
u32
the same way asu8
andu16
. - For
i8
with the implementation of the method checking whether it's less than0
.
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 } }