Crate ignorable

Crate ignorable 

Source
Expand description

crates.io docs.rs license msrv github

This crate provides 5 derives that are just like the standard library’s, but they allow to ignore fields when deriving. Inspired by RFC 3869

[dependencies]
ignorable = "0.1"

§Usage

This crate provides 5 derive macros:

  • PartialEq
  • PartialOrd
  • Ord
  • Debug
  • Hash

The advantage of these derives over the standard library’s is that they support the #[ignored] attribute to ignore individual fields when deriving the respective traits.

use ignorable::{PartialEq, Hash};

// `PartialEq` and `Hash` impls will only check
// the `id` field of 2 `User`s
#[derive(Clone, PartialEq, Eq, Hash)]
struct User {
    #[ignored(PartialEq, Hash)]
    name: String,
    #[ignored(PartialEq, Hash)]
    age: u8,
    id: u64
}

Advantages:

  • Significantly less boilerplate
  • Less maintenance overhead, it’s not your responsibility to remember to update manual implementations of traits, keep traits like Hash and PartialEq in sync. We’ve got that covered!
  • This might become a language feature in the future (RFC 3869), so you’ll be able to transition away from this crate once that time comes!

Remember that it is a logic error for the implementations of Hash and PartialEq to differ, and if you need to manually implement the traits to skip certain fields, you must remember to keep them in sync because you can’t use the derive anymore.

§With ignorable

Uses derives provided by this crate.

use ignorable::{Debug, PartialEq, Hash};

#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Var<T> {
    pub ns: Symbol,
    pub sym: Symbol,
    #[ignored(PartialEq, Hash)]
    meta: RefCell<protocols::IPersistentMap>,
    #[ignored(PartialEq, Hash)]
    pub root: RefCell<Rc<Value>>,
    #[ignored(Debug)]
    _phantom: PhantomData<T>
}

§Without

You must manually implement each trait.

#[derive(Clone)]
pub struct Var<T> {
    pub ns: Symbol,
    pub sym: Symbol,
    meta: RefCell<protocols::IPersistentMap>,
    pub root: RefCell<Rc<Value>>,
    _phantom: PhantomData<T>
}

impl<T> fmt::Debug for Var<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Var")
            .field("ns", &self.ns)
            .field("sym", &self.sym)
            .field("meta", &self.meta)
            .field("root", &self.root)
            .finish()
    }
}

impl<T> PartialEq for Var<T> {
    fn eq(&self, other: &Self) -> bool {
        self.ns == other.ns && self.sym == other.sym
    }
}

impl<T> Hash for Var<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (&self.ns, &self.sym).hash(state);
    }
}

Notes:

  • It is logically incorrect for Hash and PartialEq implementations to differ, so you must remember to keep them in sync if Var changes
  • You must remember to update the string names of the Debug impl if you ever rename the fields or Var itself

Derive Macros§

Debug
Derives an Debug implementation.
Hash
Derives an Hash implementation.
Ord
Derives an Ord implementation.
PartialEq
Derives an PartialEq implementation.
PartialOrd
Derives an PartialOrd implementation.