This is a lot of repetition. Only the type and the maximum value are
actually different between the three implementations. This might not be much
in our case, but imagine doing this for all the integer types (10, as of the
last count.) We can use the duplicate attribute to avoid repeating
ourselves:

The above code will expand to the three implementations before it.
The attribute invocation specifies that the following item should be
substituted by three duplicates of itself. Additionally, each occurrence of
the identifier int_type in the first duplicate should be replaced by u8,
in the second duplicate by u16, and in the last by u32. Likewise, each
occurrence of max_value should be replaced by 255, 65_535, and
4_294_967_295 in the first, second, and third duplicates respectively.

int_type and max_value are called substitution identifiers, while [ u8 ], [ u16 ], and [ u32 ] are each substitutions for int_type and
[255], [65_535], and [4_294_967_295] are substitutions for
max_value. Each pair of substitutions for the identifiers is called a
substitution group. Substitution groups must be seperated by ; and the
number of duplicates made is equal to the number of subsitution groups.

Substitution identifiers must be valid Rust identifiers.
The code inside substitutions can be arbitrary, as long as the expanded code
is valid. Additionally, any "bracket" type is valid; we could have used ()
or {} anywhere [] is used in these examples.

Imagine we have the following trait with the method is_negative that
should return true if the value of the object is negative and false
otherwise:

traitIsNegative {
fnis_negative(&self) ->bool;
}

We want to implement this for the six integer types u8, u16, u32,
i8, i16, and i32. For the first three types, which are all unsigned,
the implementation of this trait should trivially return false as they
can't be negative. However, for the remaining, signed types their
implementations is identical (checking whether they are less than 0), but,
of course, different from the first three:

Notice how the code repetition is split over 2 axes: 1) They all implement
the same trait 2) the method implementations of the first 3 are identical to
each other but different to the next 3, which are also mutually identical.
To implement this using only the syntax we have already seen, we could do
something like this:

However ironically, we here had to repeat ourselves in the macro invocation
instead of the code: we needed to repeat the implementations [ false ] and
[ *self < 0 ] three times each. We can utilize
nested invocation to remove the last bit of repetition:

We use # to invoke the macro inside itself, producing duplicates
of the code inside the following [], {}, or ().
In our example, we have 2 invocations that each produce 3 substitution
groups, inserting the correct implementation for their signed or unsigned
types. The above nested invocation is equivalent to the previous, non-nested
invocation, and actually expands to it as an intermediate step before
expanding the outer-most invocation.

Deeper levels of nested invocation are possible and work as expected.
There is no limit on the depth of nesting, however, as might be clear from
our example, it can get complicated to read.

Lastly, we should note that we can have nested invocations interleaved with
normal substution groups. For example, say we want to implement IsNegative
for i8, but don't want the same for i16 and i32. We could do the
following:

Note that nested invocation is only allowed after the initial list of
substitution identifiers. You also cannot use it between individual
subtitutions in a group, only between whole substitution groups.
Lastly, remember that substitution groups must be seperated by ;, which
means the nested invocation must produce these semi-colons explicitly and
correctly.

The syntax used in the previous examples is the short syntax.
duplicate also accepts a verbose syntax that is less concise, but more
readable in some circumstances. Using the verbose syntax, the very first
example above looks like this:

In the verbose syntax, a substitution group is put inside brackets and
includes a list of substitution identifiers followed by their substitutions.
No ;s are needed. Here is an annotated version of the same code:

Note that in each substitution group every identifier must have exactly one
substitution. All the groups must have the exact same identifiers, though
the order in which they arrive in each group is not important. For example,
in the annotated example, the third group has the max_value identifier
before int_type without having any effect on the expanded code.

The verbose syntax is not very concise but it has some advantages over
the shorter syntax in regards to readability. Using many identifiers and
long substitutions can quickly become unwieldy
in the short syntax. The verbose syntax deals better with both cases as it
will grow horizontally instead of vertically.

The verbose syntax also offer nested invocation. The syntax is exactly the
same, but since there is no initial substitution identifier list, nested
calls can be used anywhere (though still not inside substitution groups.)
The previous IsNegative nested invocation example can be written as
follows:

It's important to notice that the nested invocation doesn't know it
isn't the outer-most invocation and therefore doesn't discriminate between
identifiers. We had to use a different identifier in the nested invocations
(int_type_nested) than in the code (int_type), because otherwise the
nested invocation would substitute the substitution identifier, too, instead
of only substituting in the nested invocation's substitute.

The nested invocations must produce the syntax of their
parent invocation. However, each nested invocation's private syntax is free
to use any syntax type. Notice in our above example, the nested
invocations use short syntax but produce verbose syntax for the outer-most
invocation.

This crate does not try to justify or condone the usage of code duplication
instead of proper abstractions.
This macro should only be used where it is not possible to reduce code
duplication through other means, or where it simply is not worth it.

As an example, libraries that have two or more structs/traits with similar
APIs might use this macro to test them without having to copy-paste test
cases and manually make the needed edits.