# Using `#[derive(Eq)]` and `#[derive(PartialEq)]`
Deriving `Eq`/`PartialEq` works by checking whether two values are equal according
to their type structure.
## Structural equality
Deriving `Eq`/`PartialEq` for enums/structs works in a similar way to the one in `std`,
by comparing all the available fields, but, in the contrast:
1. Does not overconstrain generic parameters.
2. Implements `PartialEq::ne()` method as well, to propagate possible efficient
implementations of this method from the underlying types.
### Structs
For structs all the available fields are checked for equality.
```rust
# use std::marker::PhantomData;
# use derive_more::{Eq, PartialEq};
#
trait Trait {
type Assoc;
}
impl<T: ?Sized> Trait for T {
type Assoc = u8;
}
#[derive(Debug, Eq, PartialEq)]
struct Foo<A, B, C: Trait + ?Sized> {
a: A,
b: PhantomData<B>,
c: C::Assoc,
}
#[derive(Debug)]
struct NoEq;
assert_eq!(Foo::<_, NoEq, NoEq> { a: 3, b: PhantomData, c: 0 }, Foo { a: 3, b: PhantomData, c: 0 });
assert_ne!(Foo::<_, NoEq, NoEq> { a: 3, b: PhantomData, c: 0 }, Foo { a: 0, b: PhantomData, c: 3 });
```
This generates code equivalent to:
```rust
# use std::marker::PhantomData;
#
# trait Trait {
# type Assoc;
# }
# impl<T: ?Sized> Trait for T {
# type Assoc = u8;
# }
#
# struct Foo<A, B, C: Trait + ?Sized> {
# a: A,
# b: PhantomData<B>,
# c: C::Assoc,
# }
#
impl<A, B, C: Trait + ?Sized> PartialEq for Foo<A, B, C>
where
A: PartialEq,
PhantomData<B>: PartialEq, // `B: PartialEq` is generated by `std` instead
C::Assoc: PartialEq, // `C: PartialEq` is generated by `std` instead
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self { a: self_0, b: self_1, c: self_2 }, Self { a: other_0, b: other_1, c: other_2 }) => {
self_0 == other_0 && self_1 == other_1 && self_2 == other_2
}
}
}
fn ne(&self, other: &Self) -> bool {
match (self, other) {
(Self { a: self_0, b: self_1, c: self_2 }, Self { a: other_0, b: other_1, c: other_2 }) => {
self_0 != other_0 || self_1 != other_1 || self_2 != other_2
}
}
}
}
impl<A, B, C: Trait + ?Sized> Eq for Foo<A, B, C>
where
Self: PartialEq,
A: Eq,
PhantomData<B>: Eq, // `B: Eq` is generated by `std` instead
C::Assoc: Eq, // `C: Eq` is generated by `std` instead
{}
```
### Enums
For enums the first check is whether these two values represent the same variant,
and after that we check fields equality.
```rust
# use std::marker::PhantomData;
# use derive_more::{Eq, PartialEq};
#
# trait Trait {
# type Assoc;
# }
# impl<T: ?Sized> Trait for T {
# type Assoc = u8;
# }
#
#[derive(Debug, Eq, PartialEq)]
enum Foo<A, B, C: Trait + ?Sized> {
A(A),
B { b: PhantomData<B> },
C(C::Assoc),
}
#
# #[derive(Debug)]
# struct NoEq;
assert_eq!(Foo::<_, NoEq, NoEq>::A(3), Foo::A(3));
assert_ne!(Foo::<_, NoEq, NoEq>::A(3), Foo::A(0));
assert_eq!(Foo::<u16, NoEq, NoEq>::B { b: PhantomData }, Foo::B { b: PhantomData });
assert_eq!(Foo::<i32, NoEq, NoEq>::C(3), Foo::C(3));
assert_ne!(Foo::<i32, NoEq, NoEq>::C(3), Foo::C(0));
```
This generates code equivalent to:
```rust
# use std::marker::PhantomData;
#
# trait Trait {
# type Assoc;
# }
# impl<T: ?Sized> Trait for T {
# type Assoc = u8;
# }
#
# enum Foo<A, B, C: Trait + ?Sized> {
# A(A),
# B { b: PhantomData<B> },
# C(C::Assoc),
# }
#
impl<A, B, C: Trait + ?Sized> PartialEq for Foo<A, B, C>
where
A: PartialEq,
PhantomData<B>: PartialEq, // `B: PartialEq` is generated by `std` instead
C::Assoc: PartialEq, // `C: PartialEq` is generated by `std` instead
{
fn eq(&self, other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(other) &&
match (self, other) {
(Self::A(self_0), Self::A(other_0)) => { self_0 == other_0 }
(Self::B { b: self_0 }, Self::B { b: other_0 }) => { self_0 == other_0 }
(Self::C(self_0), Self::C(other_0)) => { self_0 == other_0 }
_ => unsafe { std::hint::unreachable_unchecked() }
}
}
fn ne(&self, other: &Self) -> bool {
std::mem::discriminant(self) != std::mem::discriminant(other) ||
match (self, other) {
(Self::A(self_0), Self::A(other_0)) => { self_0 != other_0 }
(Self::B { b: self_0 }, Self::B { b: other_0 }) => { self_0 != other_0 }
(Self::C(self_0), Self::C(other_0)) => { self_0 != other_0 }
_ => unsafe { std::hint::unreachable_unchecked() }
}
}
}
impl<A, B, C: Trait + ?Sized> Eq for Foo<A, B, C>
where
Self: PartialEq,
A: Eq,
PhantomData<B>: Eq, // `B: Eq` is generated by `std` instead
C::Assoc: Eq, // `C: Eq` is generated by `std` instead
{}
```
### Ignoring
Both `#[eq(skip)]` and `#[partial_eq(skip)]` attributes could be used to ignore
fields, a whole struct or enum variants in the expansion.
```rust
# use derive_more::{Eq, PartialEq};
#
#[derive(Debug)]
struct NoEq; // doesn't implement `Eq`/`PartialEq`
#[derive(Debug, Eq, PartialEq)]
struct Foo {
num: i32,
// This attribute is seen by both `Eq` and `PartialEq` macros,
// so the repetition is unnecessary.
#[eq(skip)] // or #[eq(ignore)]
ignored: f32,
}
#[derive(Debug, Eq, PartialEq)]
// This attribute is also seen by both `Eq` and `PartialEq` macros.
// Makes all fields of this struct being ignored.
#[partial_eq(skip)] // or #[partial_eq(ignore)]
struct Bar(f32, NoEq);
#[derive(Debug, Eq, PartialEq)]
enum Enum {
Foo(i32, #[eq(skip)] NoEq),
#[eq(skip)]
Bar(NoEq),
Baz,
}
assert_eq!(Foo { num: 0, ignored: 1.0 }, Foo { num: 0, ignored: 1.0 });
assert_eq!(Foo { num: 0, ignored: 1.0 }, Foo { num: 0, ignored: 2.0 });
assert_ne!(Foo { num: 0, ignored: 1.0 }, Foo { num: 1, ignored: 1.0 });
assert_eq!(Bar(0.0, NoEq), Bar(0.0, NoEq));
assert_eq!(Bar(0.0, NoEq), Bar(1.0, NoEq));
assert_eq!(Enum::Foo(0, NoEq), Enum::Foo(0, NoEq));
assert_ne!(Enum::Foo(0, NoEq), Enum::Foo(1, NoEq));
assert_eq!(Enum::Bar(NoEq), Enum::Bar(NoEq));
assert_eq!(Enum::Baz, Enum::Baz);
// NOTE: Different variants are still not equal despite being ignored!
// Ignoring a variant only ignores all its fields during comparison.
assert_ne!(Enum::Foo(0, NoEq), Enum::Bar(NoEq));
assert_ne!(Enum::Foo(0, NoEq), Enum::Baz);
assert_ne!(Enum::Bar(NoEq), Enum::Baz);
```
This generates code equivalent to:
```rust
# struct NoEq;
#
# struct Foo { num: i32, ignored: f32 }
#
impl PartialEq for Foo {
fn eq(&self, __other: &Self) -> bool {
match (self, __other) {
(Self { num: __self_0, .. }, Self { num: __other_0, .. }) => { __self_0 == __other_0 }
}
}
fn ne(&self, __other: &Self) -> bool {
match (self, __other) {
(Self { num: __self_0, .. }, Self { num: __other_0, .. }) => { __self_0 != __other_0 }
}
}
}
impl Eq for Foo
where
i32: Eq,
{}
# struct Bar(i32, NoEq);
#
impl PartialEq for Bar {
fn eq(&self, __other: &Self) -> bool { true }
}
impl Eq for Bar {}
# enum Enum {
# Foo(i32, NoEq),
# Bar(NoEq),
# Baz,
# }
#
impl PartialEq for Enum {
fn eq(&self, __other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(__other) &&
match (self, __other) {
(Self::Foo(__self_0, _, ), Self::Foo(__other_0, _, )) => { __self_0 == __other_0 }
_ => true,
}
}
fn ne(&self, __other: &Self) -> bool {
std::mem::discriminant(self) != std::mem::discriminant(__other) ||
match (self, __other) {
(Self::Foo(__self_0, _, ), Self::Foo(__other_0, _, )) => { __self_0 != __other_0 }
_ => false,
}
}
}
```