#[derive(Sub)]
{
// Attributes available to this derive:
#[sub]
}
add only.Expand description
§What #[derive(Add)] generates
NOTE:
Sub,BitAnd,BitOrandBitXorderives are fully equivalent to theAddderive described below.
Deriving Add works by adding two values structurally (field by field, according
to their type structure).
§Structs
The derived Add implementation will allow two structs of the same type to be
added together. This is done by Adding their respective fields together and
creating a new struct with those values.
#[derive(Add)]
struct MyInts(i32, i32);
#[derive(Add)]
struct Point2D {
x: i32,
y: i32,
}This generates code equivalent to:
impl Add for MyInts {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Self(self_0, self_1), Self(rhs_0, rhs_1)) => {
Self(Add::add(self_0, rhs_0), Add::add(self_1, rhs_1))
}
}
}
}
impl Add for Point2D {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Self { x: self_0, y: self_1 }, Self { x: rhs_0, y: rhs_1 }) => {
Self { x: Add::add(self_0, rhs_0), y: Add::add(self_1, rhs_1) }
}
}
}
}The behaviour is similar with more or less fields.
§Ignoring
Sometimes a struct needs to hold a field (most commonly PhantomData) that doesn’t
participate in Add implementation. Such field could be ignored using the #[add(skip)]
attribute.
#[derive(Add)]
struct TupleWithZst<T>(i32, #[add(skip)] PhantomData<T>);
#[derive(Add)]
struct StructWithZst<T> {
x: i32,
#[add(skip)] // or #[add(ignore)]
_marker: PhantomData<T>,
}§Enums
For enums each variant can be Added in a similar way to another instance of the
same variant. There’s one big difference however: it returns a Result<EnumType>,
because an error is returned when two different variants are Added together.
#[derive(Add)]
enum MixedInts {
SmallInt(i32),
BigInt(i64),
TwoSmallInts(i32, i32),
NamedSmallInts { x: i32, y: i32 },
UnsignedOne(u32),
UnsignedTwo(u32),
Unit,
}This generates code equivalent to:
impl Add for MixedInts {
type Output = Result<Self, derive_more::BinaryError>;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Self::SmallInt(self_0), Self::SmallInt(rhs_0)) => {
Ok(Self::SmallInt(Add::add(self_0, rhs_0)))
}
(Self::BigInt(self_0), Self::BigInt(rhs_0)) => {
Ok(Self::BigInt(Add::add(self_0, rhs_0)))
}
(Self::TwoSmallInts(self_0, self_1), Self::TwoSmallInts(rhs_0, rhs_1)) => {
Ok(Self::TwoSmallInts(Add::add(self_0, rhs_0), Add::add(self_1, rhs_1)))
}
(Self::NamedSmallInts { x: self_0, y: self_1 },
Self::NamedSmallInts { x: rhs_0, y: rhs_1 }) => {
Ok(Self::NamedSmallInts {
x: Add::add(self_0, rhs_0),
y: Add::add(self_1, rhs_1),
})
}
(Self::UnsignedOne(self_0), Self::UnsignedOne(rhs_0)) => {
Ok(Self::UnsignedOne(Add::add(self_0, rhs_0)))
}
(Self::UnsignedTwo(self_0), Self::UnsignedTwo(rhs_0)) => {
Ok(Self::UnsignedTwo(Add::add(self_0, rhs_0)))
}
(Self::Unit, Self::Unit) => Err(derive_more::BinaryError::Unit(
derive_more::UnitError::new("add"),
)),
_ => Err(derive_more::BinaryError::Mismatch(
derive_more::WrongVariantError::new("add"),
)),
}
}
}Also note the Unit variant that throws a derive_more::UnitError when Adding it to itself.
§Ignoring
Similarly to structs, enum fields could be ignored using the #[add(skip)] attribute.
struct I32(i32); // doesn't implement `Add`
#[derive(Add)]
enum MixedInts {
TwoSmallInts(i32, #[add(skip)] I32),
NamedSmallInts {
#[add(skip)] // or #[add(ignore)]
x: I32,
y: i32,
},
}NOTE: Ignoring all the fields of a variant or ignoring the variant itself is not allowed (results in a compilation error).