Crate newtype_derive

Source
Expand description

This crate provides several macros for deriving implementations of various traits for “newtype” wrappers (i.e. tuple structs with a single element). That is, given a tuple struct with exactly one field (e.g. struct Buckets(i32)), these macros will derive “obvious” implementations of traits such as Add, Neg, Index, Deref, From, etc.

All of these macros are designed to be used with the custom_derive crate, though they can be used independent of it.

§Example

Create a simple integer wrapper with some arithmetic operators:

#[macro_use] extern crate custom_derive;
#[macro_use] extern crate newtype_derive;

custom_derive! {
    #[derive(NewtypeFrom, NewtypeAdd, NewtypeMul(i32))]
    pub struct Happy(i32);
}

// Let's add some happy little ints.
let a = Happy::from(6);
let b = Happy::from(7);
let c = (a + b) * 3;
let d: i32 = c.into();
assert_eq!(d, 39);

Create a “deref-transparent” wrapper around a type:

#[macro_use] extern crate custom_derive;
#[macro_use] extern crate newtype_derive;

custom_derive! {
    #[derive(NewtypeFrom,
        NewtypeDeref, NewtypeDerefMut,
        NewtypeIndex(usize), NewtypeIndexMut(usize)
        )]
    pub struct I32Array(Vec<i32>);
}

let mut arr = I32Array::from(vec![1, 2, 3]);
arr.push(4);
arr[2] = 5;
assert_eq!(&**arr, &[1, 2, 5, 4]);
assert_eq!(arr.len(), 4);

§Overview

This crate provides macros to derive implementations of the following traits for newtype structs:

  • Binary Arithmetic Operators: Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Sub, Shl, Shr, plus the corresponding *Assign traits.
  • Unary Arithmetic Operators: Neg, Not.
  • Other Operators: Deref, DerefMut, Index, IndexMut.
  • Formatting: Binary, Debug, Display, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex.
  • Miscellaneous: From.
  • Unstable: One, Product, Sum, Zero (requires the std-unstable feature).

All of these macros are named Newtype$Trait.

None of these macros currently support generic newtype structs.

§Binary Arithmetic Operators

Each of the binary arithmetic operators accept several deriving forms. To use Add on a struct T as an example:

  • NewtypeAdd: impl Add<T, Output=T> for T
  • NewtypeAdd(&self): impl<'a> Add<&'a T, Output=T> for &'a T
  • NewtypeAdd(U): impl Add<U, Output=T> for T
  • NewtypeAdd(&self, U): impl<'a> Add<U, Output=T> for &'a T
  • NewtypeAdd(*): All four combinations of T and &T

The *Assign variants accept zero or one argument only. For example:

  • NewtypeAddAssign: impl AddAssign<T> for T
  • NewtypeAddAssign(&Self): impl<'a> Add<&'a T> for &'a T
  • NewtypeAddAssign(U): impl Add<U> for T
  • NewtypeAddAssign(*): Implements for T and &T.

In all cases, the implementation unwraps the newtype (where necessary), forwards to the wrapped value’s implementation, then re-wraps the result in the newtype.

§Unary Arithmetic Operators

Each of the binary arithmetic operators accept several deriving forms. To use Neg on a struct T as an example:

  • NewtypeNeg: impl Neg<Output=T> for T
  • NewtypeNeg(&self): impl<'a> Neg<Output=T> for &'a T
  • NewtypeNeg(*): both of the above

In all cases, the implementation unwraps the newtype, forwards to the wrapped value’s implementation, then re-wraps the result in the newtype.

§Other Operators

NewtypeDeref and NewtypeDerefMut only support the argument-less form, and implements the corresponding trait such that the newtype structure derefs to a pointer to the wrapped value.

NewtypeIndex and NewtypeIndexMut must be used as NewtypeIndex(usize), where the argument is the type to use for indexing. The call is forwarded to the wrapped value’s implementation.

§Formatting

The deriving macros for the formatting traits in std::fmt forward to the wrapped value’s implementation.

§Miscellaneous

NewtypeFrom implements std::convert::From twice: once for converting from the wrapped type to the newtype, and once for converting from the newtype to the wrapped type.

NewtypeProduct and NewtypeSum optionally support specifying &Self as an argument to generate an implementation that accepts an iterator of borrowed pointers (e.g. NewtypeSum(&Self)).

§Using Without custom_derive!

Although designed to be used with custom_derive!, all of the macros in this crate can be used without it. The following:

custom_derive! {
    #[derive(Copy, Clone, Debug, NewtypeFrom, NewtypeAdd, NewtypeAdd(f32))]
    pub struct Meters(f32);
}

Can also be written as:

#[derive(Copy, Clone, Debug)]
pub struct Meters(f32);

NewtypeFrom! { () pub struct Meters(f32); }
NewtypeAdd! { () pub struct Meters(f32); }
NewtypeAdd! { (f32) pub struct Meters(f32); }

Macros§