Derivative

This crate provides a set of alternative #[derive] attributes for Rust.

Examples

derivative uses attributes to make it possible to derive more implementations than the built-in derive(Trait). Here are a few examples of stuffs you cannot just derive.

You can derive Default on enumerations:

With derivative

Original


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Default(bound=""))]
pub enum Option<T> {
    #[derivative(Default)]
    /// No value
    None,
    /// Some value `T`
    Some(T),
}
}

#![allow(unused)]
fn main() {
#![no_implicit_prelude]
extern crate core;
use core::default::Default;
use Option::None;

pub enum Option<T> {
    /// No value
    None,
    /// Some value `T`
    Some(T),
}

impl<T> Default for Option<T> {
    /// Returns None.
    #[inline]
    fn default() -> Option<T> {
        None
    }
}
}

You can use different default values for some fields:

With derivative

Original


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Default)]
pub struct RegexOptions {
    pub pats: Vec<String>,
    #[derivative(Default(value="10 * (1 << 20)"))]
    pub size_limit: usize,
    #[derivative(Default(value="2 * (1 << 20)"))]
    pub dfa_size_limit: usize,
    pub case_insensitive: bool,
    pub multi_line: bool,
    pub dot_matches_new_line: bool,
    pub swap_greed: bool,
    pub ignore_whitespace: bool,
    #[derivative(Default(value="true"))]
    pub unicode: bool,
}
}

#![allow(unused)]
fn main() {
pub struct RegexOptions {
    pub pats: Vec<String>,
    pub size_limit: usize,
    pub dfa_size_limit: usize,
    pub case_insensitive: bool,
    pub multi_line: bool,
    pub dot_matches_new_line: bool,
    pub swap_greed: bool,
    pub ignore_whitespace: bool,
    pub unicode: bool,
}

impl Default for RegexOptions {
    fn default() -> Self {
        RegexOptions {
            pats: vec![],
            size_limit: 10 * (1 << 20),
            dfa_size_limit: 2 * (1 << 20),
            case_insensitive: false,
            multi_line: false,
            dot_matches_new_line: false,
            swap_greed: false,
            ignore_whitespace: false,
            unicode: true,
        }
    }
}
}

Want a transparent Debug implementation for your wrapper? We got that:

With derivative

Original


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug="transparent")]
pub struct Wrapping<T>(pub T);
}

#![allow(unused)]
fn main() {
use std::fmt;
pub struct Wrapping<T>(pub T);

impl<T: fmt::Debug> fmt::Debug for Wrapping<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}
}

Need to ignore a field? We got that too:

With derivative

Original


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(PartialEq, Hash)]
struct Identifier;
#[derive(Derivative)]
#[derivative(PartialEq, Hash)]
pub struct Version {
    /// The major version.
    pub major: u64,
    /// The minor version.
    pub minor: u64,
    /// The patch version.
    pub patch: u64,
    /// The pre-release version identifier.
    pub pre: Vec<Identifier>,
    // We should ignore build metadata
    // here, otherwise versions v1 and
    // v2 can exist such that !(v1 < v2)
    // && !(v1 > v2) && v1 != v2, which
    // violate strict total ordering rules.
    #[derivative(PartialEq="ignore")]
    #[derivative(Hash="ignore")]
    /// The build metadata, ignored when
    /// determining version precedence.
    pub build: Vec<Identifier>,
}
}

#![allow(unused)]
fn main() {
use std::{cmp, hash};
#[derive(PartialEq, Hash)]
struct Identifier;
pub struct Version {
    /// The major version.
    pub major: u64,
    /// The minor version.
    pub minor: u64,
    /// The patch version.
    pub patch: u64,
    /// The pre-release version identifier.
    pub pre: Vec<Identifier>,
    /// The build metadata, ignored when
    /// determining version precedence.
    pub build: Vec<Identifier>,
}

impl cmp::PartialEq for Version {
    #[inline]
    fn eq(&self, other: &Version) -> bool {
        // We should ignore build metadata
        // here, otherwise versions v1 and
        // v2 can exist such that !(v1 < v2)
        // && !(v1 > v2) && v1 != v2, which
        // violate strict total ordering rules.
        self.major == other.major &&
        self.minor == other.minor &&
        self.patch == other.patch &&
        self.pre == other.pre
    }
}

impl hash::Hash for Version {
    fn hash<H: hash::Hasher>(&self, into: &mut H) {
        self.major.hash(into);
        self.minor.hash(into);
        self.patch.hash(into);
        self.pre.hash(into);
    }
}
}

Custom attributes

The Copy and Clone traits support the following attributes:

clone_from

The Clone trait has a default implementation for clone_from and derive(Clone) never implements that method. derivative can implement it if asked explicitly.

Note that while the generated implementation is good for structures, it might not be very efficient for enumerations. What it does is check if both self and the clone-from value have the same variant, if they have, use clone_from on the members, otherwise fallback to *self = other.clone();. Ask yourself if you really need this.

Custom bound

As most other traits, Copy and Debug support a custom bound on container and fields. See Debug's documentation for more information.

Limitations

rustc can optimize derive(Clone, Copy) to generate faster, smaller code. So does derivative. But rustc does not know about derivative(Copy) and would not optimize #[derivative(Copy)] #[derive(Clone)]. To avoid that issue, you should avoid deriving Clone using rustc's default derive and Copy using derivative. derivative will error if it detects that, but can't always do it.

Custom attributes

The Debug trait supports the following attributes:

Ignoring a field

You can use derivative to hide fields from a structure or enumeration Debug implementation:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug)]
struct Foo {
    foo: u8,
    #[derivative(Debug="ignore")]
    bar: u8,
}

println!("{:?}", Foo { foo: 42, bar: 1 }); // Foo { foo: 42 }
}

Hiding newtypes

You can use derivative to automatically unwrap newtypes and enumeration variants with only one field:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug="transparent")]
struct A(isize);

#[derive(Derivative)]
#[derivative(Debug)]
enum C {
    Foo(u8),
    #[derivative(Debug="transparent")]
    Bar(u8),
}

println!("{:?}", A(42)); // 42
println!("{:?}", C::Bar(42)); // 42

// But:
println!("{:?}", C::Foo(42)); // Foo(42)
}

Format with

You can pass a field to a format function:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
mod path {
  pub struct SomeTypeThatMightNotBeDebug;
  pub mod to {
    pub fn my_fmt_fn(_: &super::SomeTypeThatMightNotBeDebug, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { unimplemented!() }
  }
}
use path::SomeTypeThatMightNotBeDebug;
#[derive(Derivative)]
#[derivative(Debug)]
struct Foo {
    foo: u32,
    #[derivative(Debug(format_with="path::to::my_fmt_fn"))]
    bar: SomeTypeThatMightNotBeDebug,
}
}

The field bar will be displayed with path::to::my_fmt_fn(&bar, &mut fmt) where fmt is the current Formatter.

The function must the following prototype:

fn fmt(&T, &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>;

Custom bound

Usually, derivative will add a T: Debug bound for each type parameter T of the current type. If you do not want that, you can specify an explicit bound:

  • Either on the type. This replaces all bounds:

#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
trait MyDebug {
  fn my_fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>;
}
use std::fmt::Debug;
#[derive(Derivative)]
#[derivative(Debug(bound="T: Debug, U: MyDebug"))]
struct Foo<T, U> {
    foo: T,
    #[derivative(Debug(format_with="MyDebug::my_fmt"))]
    bar: U,
}
}
  • Or on a field. This replaces the bound derivative guessed for that field. The example below is equivalent to the above:

#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
trait MyDebug {
  fn my_fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>;
}
#[derive(Derivative)]
#[derivative(Debug)]
struct Foo<T, U> {
    foo: T,
    #[derivative(Debug(format_with="MyDebug::my_fmt", bound="U: MyDebug"))]
    bar: U,
}
}

With bound="" it is possible to remove any bound for the type. This is useful if your type contains a Foo<T> that is Debug even if T is not.

Packed structures

You can use derivative to implement Debug on packed structures. Unlike the standard derive(debug), derivative does not require the structure itself to be Copy, but like the standard derive(debug), it requires each (non-ignored) field to be Copy.


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug)]
#[repr(C, packed)]
struct Foo {
    foo: u8,
    // `String` isn't `Copy` so it must be ignored to derive `Debug`
    #[derivative(Debug="ignore")]
    bar: String,
}
}

Custom attributes

The Default trait supports the following attributes:

Default enumeration

You can use derivative to derive a default implementation on enumerations! This does not work with rustc's #[derive(Default)]. All you need is to specify what variant is the default value:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Debug, Derivative)]
#[derivative(Default)]
enum Enum {
    A,
    #[derivative(Default)]
    B,
}

println!("{:?}", Enum::default()); // B
}

Setting the value of a field

You can use derivative to change the default value of a field in a Default implementation:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Debug, Derivative)]
#[derivative(Default)]
struct Foo {
    foo: u8,
    #[derivative(Default(value="42"))]
    bar: u8,
}

println!("{:?}", Foo::default()); // Foo { foo: 0, bar: 42 }
}

new function

You can use derivative to derive a convenience new method for your type that calls Default::default:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Debug, Derivative)]
#[derivative(Default(new="true"))]
struct Foo {
    foo: u8,
    bar: u8,
}

println!("{:?}", Foo::new()); // Foo { foo: 0, bar: 0 }
}

Custom bound

The following does not work because derive adds a T: Default bound on the impl Default for Foo<T>:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Default)]
struct Foo<T> {
    foo: Option<T>,
}

struct NonDefault;

Foo::<NonDefault>::default(); // gives:
// error: no associated item named `default` found for type `Foo<NonDefault>` in the current scope
//  = note: the method `default` exists but the following trait bounds were not satisfied: `NonDefault : std::default::Default`
}

That bound however is useless as Option<T>: Default for any T. derivative allows you to explicitly specify a bound if the inferred one is not correct:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Default(bound=""))] // don't need any bound
struct Foo<T> {
    foo: Option<T>,
}

struct NonDefault;

Foo::<NonDefault>::default(); // works!
}

Custom attributes

The Hash trait supports the following attributes:

Ignoring a field

You can use derivative to ignore fields from a Hash implementation:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Hash)]
struct Foo {
    foo: u8,
    #[derivative(Hash="ignore")]
    bar: i32,
}

#[derive(Hash)]
struct Bar {
    foo: u8,
}

fn hash<T: std::hash::Hash>(t: &T) -> u64 {
    use std::hash::Hasher;
    let mut s = std::collections::hash_map::DefaultHasher::new();
    t.hash(&mut s);
    s.finish()
}

assert_eq!(hash(&Foo { foo: 42, bar: -1337 }), hash(&Bar { foo: 42 }));
}

Hash with

You can pass a field to a hash function:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
mod path {
  pub struct SomeTypeThatMightNotBeHash;
  pub mod to {
    pub fn my_hash_fn<H>(_: &super::SomeTypeThatMightNotBeHash, state: &mut H) where H: std::hash::Hasher { unimplemented!() }
  }
}
use path::SomeTypeThatMightNotBeHash;
#[derive(Derivative)]
#[derivative(Hash)]
struct Foo {
    foo: u32,
    #[derivative(Hash(hash_with="path::to::my_hash_fn"))]
    bar: SomeTypeThatMightNotBeHash,
}
}

The field bar will be hashed with path::to::my_hash_fn(&bar, &mut state) where state is the current Hasher.

The function must the following prototype:

fn my_hash_fn<H>(&T, state: &mut H) where H: Hasher;

Limitations

On structure, derivative(Hash) will produce the same hash as derive(Hash). On unions however, it will produces the same hashes only for unitary variants!

Custom bound

As most other traits, Hash supports a custom bound on container and fields. See Debug's documentation for more information.

Custom attributes

The PartialEq, Eq, PartialOrd and Eq and traits support the following attributes:

The PartialEq, PartialOrd and Ord traits also supports the following attributes:

(These attributes are not relevant for Eq which is just a marker trait.)

Enumerations

Unfortunately, there is no way for derivative to derive PartialOrd or Ord on enumerations as efficiently as the built-in derive(…) yet.

If you want to use derivative on enumerations anyway, you can add

#[derivative(PartialOrd="feature_allow_slow_enum")]

to your enumeration. This acts as a “feature-gate”.

This attribute is also allowed for PartialEq for historical reason. It is not necessary anymore as of v2.1.0. It was never necessary nor allowed for Eq.

Ignoring a field

You can use derivative to ignore a field when comparing:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(PartialEq)]
struct Foo {
    foo: u8,
    #[derivative(PartialEq="ignore")]
    bar: u8,
}

assert!(Foo { foo: 0, bar: 42 } == Foo { foo: 0, bar: 7});
assert!(Foo { foo: 42, bar: 0 } != Foo { foo: 7, bar: 0});
}

Compare with

Usually fields are compared using ==, PartialOrd::partial_cmp or Ord::cmp. You can use an alternative comparison function if you like:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
mod path {
  pub struct SomeTypeThatMightNotBePartialEq;
  pub mod to {
    pub fn my_cmp_fn(_: &super::SomeTypeThatMightNotBePartialEq, _: &super::SomeTypeThatMightNotBePartialEq) -> bool { false }
  }
}
use path::SomeTypeThatMightNotBePartialEq;
#[derive(Derivative)]
#[derivative(PartialEq)]
struct Foo {
    foo: u32,
    #[derivative(PartialEq(compare_with="path::to::my_cmp_fn"))]
    bar: SomeTypeThatMightNotBePartialEq,
}
}

foo will be compared with == and bar will be compared with path::to::my_cmp_fn which must have the following prototype:

TraitSignature
PartialEqfn my_cmp_fn(&T, &T) -> bool;
PartialOrdfn my_cmp_fn(&T, &T) -> std::option::Option<std::cmp::Ordering>;
Ordfn my_cmp_fn(&T, &T) -> std::cmp::Ordering;

Custom bound

Usually if you derive CmpTrait, a T: CmpTrait bound is added for each type parameter T. You can use override this behavior if the inferred bound is not correct for you.

Eg. comparing raw pointers does not require the type to be Eq, so you could use:


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(PartialEq)]
struct WithPtr<T: ?Sized> {
    #[derivative(PartialEq(bound=""))]
    foo: *const T
}
}

See Default's documentation for more details.

Packed structures

You can use derivative to implement the comparison traits on packed structures. Unlike the standard derive, derivative does not require the structure itself to be Copy, but like the standard derive, it requires each (non-ignored) field to be Copy.


#![allow(unused)]
fn main() {
extern crate derivative;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(PartialEq)]
#[repr(C, packed)]
struct Foo {
    f: u32,
    #[derivative(PartialEq = "ignore")]
    t: String,
}
}