0

Let say for example that this is a Json parser and to represent each variant of the possible data which contains I use an enum.

#[derive(Copy, Clone, PartialEq)]
enum JsonObject {
    Invalid,
    Null,
    Bool(boo),
    /// etc
}

Now the in some part of the code I compare two JsonObjects

let type1 = JsonObject::Bool(true);
let type2 = JsonObject::Bool(false);

if type1 == type2 {
    // do stufff
}

The problem is that type1 != type2 because JsonObject::Bool(true) != JsonObject::Bool(false), What I want is that the enum does not compare the inner data of the variant and just the variant itself. JsonObject::Bool(_) == JsonObject::Bool(_)

2 Answers2

4

Derived PartialEq by default will compare everything, including wrapped values as you have noticed.

For custom behaviour, you must implement it manually.

Luckily, Rust 1.21.0 and up has a function for this, std::mem::discriminant:

use std::{
    cmp::PartialEq,
    mem::discriminant,
};

impl PartialEq for JsonObject {
    fn eq(&self, other: &Self) -> bool {
        discriminant(self) == discriminant(other)
    }
}

Older answer

use std::cmp::PartialEq;

impl PartialEq for JsonObject {
    fn eq(&self, other: &Self) -> bool {
        use JsonObject::*;
        match (self, other) {
            (Invalid, Invalid) => true,
            (Null, Null) => true,
            (Bool(_), Bool(_)) => true,
            _ => false
        }
    }
}
Yamirui
  • 169
  • 6
  • 3
    You can use `mem::discriminant` for this. See https://stackoverflow.com/questions/32554285/compare-enums-only-by-variant-not-value – trent Aug 18 '20 at 11:05
  • @trentcl thank you, I updated my answer, although what you linked to looks more complete as an `QA`, wouldn't it be better to close this as dupe altogether? – Yamirui Aug 18 '20 at 11:19
  • Mmm, arguable, your answer explains why deriving `PartialEq` is wrong, but it could go either way IMO. I'll vote it and we'll see what the community thinks. – trent Aug 18 '20 at 11:38
2

With strum crate you can do like that

extern crate strum;
#[macro_use]
extern crate strum_macros;

#[derive(Copy, Clone, EnumDiscriminants)]
enum JsonObject {
    Invalid,
    Null,
    Bool(bool),
    // etc
}

impl std::cmp::PartialEq for JsonObject {
    fn eq(&self, other: &Self) -> bool {
        JsonObjectDiscriminants::from(self) == other.into()
    }
}

EDIT: Thanks to trentcl, works perfectly without additional dependencies

#[derive(Copy, Clone)]
enum JsonObject {
    Invalid,
    Null,
    Bool(bool),
    // etc
}

impl std::cmp::PartialEq for JsonObject {
    fn eq(&self, other: &Self) -> bool {
        use std::mem::discriminant;
        discriminant(self) == discriminant(other)
    }
}

fn main() {
    assert!(JsonObject::Bool(true) == JsonObject::Bool(false));
}
Alexey S. Larionov
  • 6,555
  • 1
  • 18
  • 37