Sub

Derive Macro Sub 

Source
#[derive(Sub)]
{
    // Attributes available to this derive:
    #[sub]
}
Available on crate feature add only.
Expand description

§What #[derive(Add)] generates

NOTE: Sub, BitAnd, BitOr and BitXor derives are fully equivalent to the Add derive 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).