#macro-derive #newtype #macro #derive #custom-derive #wrapper #macro-attr

no-std newtype-derive-2018

This crate provides macros for deriving common traits for newtype structures

13 releases

0.2.3 Feb 28, 2024
0.2.1 Sep 22, 2023
0.1.0 Jan 10, 2023
0.0.7 Jun 29, 2022
0.0.3 Jul 20, 2021

#1730 in Rust patterns

Download history 24/week @ 2024-07-20 3/week @ 2024-07-27 5/week @ 2024-08-03 30/week @ 2024-08-10 28/week @ 2024-08-24 53/week @ 2024-08-31 20/week @ 2024-09-07 67/week @ 2024-09-14 81/week @ 2024-09-21 35/week @ 2024-10-05 48/week @ 2024-10-12 54/week @ 2024-10-19 161/week @ 2024-10-26 28/week @ 2024-11-02

299 downloads per month
Used in bsalib

MIT/Apache

105KB
1.5K SLoC

maintenance: actively developed

newtype-derive-2018

The newtype-derive modern fork.

This crate provides macros for deriving common traits for newtype structures.

All of these macros are designed to be used with the macro-attr-2018 crate, though they can be used independent of it.


lib.rs:

This crate provides several macros for deriving implementations of various traits for "newtype" wrappers (i.e. tuple structs with a single non-zero sized element). That is, given a tuple struct with exactly one field (e.g. struct Buckets(i32)), (or exactly one field followed by any number of zero-sized fields) these macros will derive "obvious" implementations of traits such as Add, Neg, Index, Deref, etc.

All of these macros are designed to be used with the macro-attr-2018 crate, though they can be used independent of it.

Example

Create a simple integer wrapper with some arithmetic operators:

use macro_attr_2018::macro_attr;
use newtype_derive_2018::*;

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

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

Create a "deref-transparent" wrapper around a smart pointer:

use macro_attr_2018::macro_attr;
use newtype_derive_2018::*;

macro_attr! {
    #[derive(NewtypeDeref!, NewtypeDerefMut!)]
    pub struct I32Array(Vec<i32>);
}

let arr = I32Array(vec![1, 2, 3]);
assert_eq!(&*arr, &[1, 2, 3]);

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.

All of these macros are named Newtype$Trait.

All these macros support generic newtype structs. By default, no bounds for generic parameters generated. To add constraints, add where clause to the end of macros arguments. For example:


macro_attr! {
    #[derive(NewtypeAdd!(where T: Add<Output=T>))]
    #[derive(NewtypeAdd!(&self, &Self where T: Add<Output=T>))]
    #[derive(NewtypeSub!(* where T: Sub<Output=T>))]
    pub struct Dummy<T: Copy>(T);
}

Binary Arithmetic Operators

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

Attribute Generated implementation
NewtypeAdd impl Add<T, Output=T> for T
NewtypeAdd(&self) impl<'a> Add<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:

Attribute Generated implementation
NewtypeAddAssign impl AddAssign<T> for 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:

Attribute Generated implementation
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. The call is forwarded to the wrapped value's implementation.

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.

Using Without macro_attr!

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

use macro_attr_2018::macro_attr;
use newtype_derive_2018::*;

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

can also be written as

use newtype_derive_2018::*;

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

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

Dependencies

~48KB