Macro new_type::newtype

source ·
macro_rules! newtype {
    ( $( $newtype:ident $( : $default:ty )? ),* ) => { ... };
}
Expand description

Implements its arguments as newtypes.

The macro is meant to provide easy means to enhance the semantics of language built-ins.

Newtypes come with Deref, DerefMut, AsRef, AsMut, and From traits. Further they implement almost all std::ops and std::cmp of the type they wrap if the operants have value semantics and return Self. Exceptions are std::ops::{Drop, Fn, FnMut, FnOnce, Index, IndexMut, RangeBounds}.

Usually one obtains instances of the newtype by the public constructor but Default is available if the wrapped type implements it. It is not as ergonomic as it should be though, see examples below.

Examples

Operations are available on newtypes:

newtype!(Count);
let count_one = Count(100);
let count_two = Count(50);
// We can add 'Count' because we can add i32!
assert_eq!(count_one + count_two, Count(150))

Newtypes can be simple function arguments with default types:

// We specify default type here!
newtype!(Count: usize);

fn add_count(a: Count, b: Count) -> Count {
    a + b
}

// We can add 'Count' because we can add usize!
assert_eq!(add_count(Count(100), Count(50)), Count(150))

Functions and defaults are available on newtypes:

newtype!(Humans: HashSet<&'static str>);
// Sadly we need to specify `Humans` as type in order to get access to `Default`.
let mut some_humans: Humans = Humans::default();
some_humans.insert("Maria");
some_humans.insert("Peter");
let mut other_humans: Humans = Humans::default();
other_humans.insert("Kim");
other_humans.insert("Mia");
// We can extend Humans with Humans!
some_humans.extend(other_humans.iter());
// We can ask for '.len()' on Humans because we can ask for '.len()' on HashSet!
assert_eq!(some_humans.len(), 4)

Newtypes can be nested:

newtype!(A, B, C);
let abc_one = A(B(C(5)));
let abc_two = A(B(C(5)));
// We can add nested newtypes because we can add the wrapped type!
assert_eq!(abc_one + abc_two, A(B(C(10))))