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"
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
andPartialEq
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.
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>
}
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
andPartialEq
implementations to differ, so you must remember to keep them in sync ifVar
changes - You must remember to update the string names of the
Debug
impl if you ever rename the fields orVar
itself