Attribute Macro substrate::type_dispatch::duplicate::duplicate_item
#[duplicate_item]
Expand description
Duplicates the item and substitutes specific identifiers for different code snippets in each duplicate.
§Short Syntax
use duplicate::duplicate_item;
trait IsMax {
fn is_max(&self) -> bool;
}
#[duplicate_item(
int_type max_value;
[ u8 ] [ 255 ];
[ u16 ] [ 65_535 ];
[ u32 ] [ 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 a list of all identifiers followed by ;
.
Then a ;
seperated list of substitution groups must be given (at least 1
group). Every group is a list of substitutions, one for each substitution
identifier given in the first line.
The substitutions must be enclosed in []
but are otherwise
free.
§Verbose Syntax
use duplicate::duplicate_item;
trait IsMax {
fn is_max(&self) -> bool;
}
#[duplicate_item(
[
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
[]
. 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
.
§Parameterized Substitutoin
use duplicate::duplicate_item;
struct VecWrap<T>(Vec<T>);
impl<T> VecWrap<T> {
#[duplicate_item(
method reference(lifetime, type);
[get] [& 'lifetime type];
[get_mut] [& 'lifetime mut type];
)]
pub fn method<'a>(self: reference([a],[Self]),idx: usize) -> Option<reference([a],[T])> {
self.0.method(idx)
}
}
let mut vec = VecWrap(vec![1,2,3]);
assert_eq!(*vec.get(0).unwrap(), 1);
*vec.get_mut(1).unwrap() = 5;
assert_eq!(*vec.get(1).unwrap(), 5);
This implements two versions of the method:
get
: Borrowsself
immutably and return a shared reference.get_mut
: Borrowsself
mutably and returns a mutable reference.
If an identifier is followed by parenthises (in both its declaration and its
use), a set of parameters can be provided to customize the subtituion for
each use. In the declaration a list of identifiers is given, which can be
used in its substitutions. When using the identifier, argument code snippets
must be given in a comma separated list, with each argument being inclosed
in []
.
Parameterized substitution is also available for the verbose syntax:
impl<T> VecWrap<T> {
#[duplicate_item(
[
method [get]
reference(lifetime, type) [& 'lifetime type]
]
[
method [get_mut]
reference(lifetime, type) [& 'lifetime mut type]
]
)]
pub fn method<'a>(self: reference([a],[Self]),idx: usize) -> Option<reference([a],[T])> {
self.0.method(idx)
}
}
§Nested Invocation
use duplicate::duplicate_item;
trait IsNegative {
fn is_negative(&self) -> bool;
}
#[duplicate_item(
int_type implementation;
duplicate!{
[ // -+
int_type_nested;[u8];[u16];[u32] // | Nested invocation producing 3
] // | substitution groups
[ int_type_nested ] [ false ]; // |
} // -+
[ i8 ] [ *self < 0 ] // -- Substitution group 4
)]
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
. 1. 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_item(
int_type implementation;
[ u8 ] [ false ];
[ u16 ] [ false ];
[ u32 ] [ false ];
[ i8 ] [ *self < 0 ]
)]
impl IsNegative for int_type {
fn is_negative(&self) -> bool {
implementation
}
}
Nested invocation is also available for the verbose syntax:
use duplicate::duplicate_item;
trait IsNegative {
fn is_negative(&self) -> bool;
}
#[duplicate_item(
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());
§Global Substitution
#[duplicate_item(
typ1 [Some<Complex<()>, Type<WeDont<Want, To, Repeat>>>];
typ2 [Some<Other, Complex<Type<(To, Repeat)>>>];
method reference(type);
[get] [& type];
[get_mut] [&mut type];
)]
fn method(
arg0: reference([Type<()>]),
arg1: typ1,
arg2: typ2)
-> (reference([typ1]), reference([typ2]))
{
...
}
The global substitutions (typ1
and typ2
) are substituted in both
duplicates of the function. Global substitutions have the same syntax as
verbose syntax substitutions, are ;
separated (even from following
substitutions groups), must all be defined at the beginning, and aren’t
usable in the invocation itself but only in the code being duplicated.