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);
    }
}
}