Expand description
§Newtype Tools
A lightweight library (~1K lines of code with minimum dependencies) designed to make the newtype idiom more ergonomic to use.
§Motivation
Instead of trying to be everything or deriving dozens of unused trait implementations,
this crate provides unique, simple, yet powerful tools for the newtypes.
The crate focuses on three main areas to make newtype usage more enjoyable:
- Conversions between types.
- Operations on
newtypes. - Iteration over
newtyperanges.
§Usage
cargo add newtype-tools§Examples
The simplest way to use the crate is to declare a tuple struct as a newtype kind:
// Derive `newtype` with `Amount` properties (see below for more details).
#[newtype_tools::newtype(Amount)]
// More traits can be easily derived:
#[derive(serde::Serialize)]
struct Apples(u64);
// The `newtype` can also be easily extended:
impl core::fmt::Display for Apples {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(&self.0, f)
}
}
// Now the `Apples`behave pretty much as their inner type `u64`:
let apple1 = Apples(2);
// `Apples` can be converted from the inner type:
let apple2 = Apples::from(3);
// `Apples` can be added, subtracted and compared:
assert_eq!(apple1 + apple2, Apples(5));
// `Apples` can be multiplied by the inner factor:
assert_eq!(apple1 * 2_u64, Apples(4));
// `Apples` can be divided, returning a inner ratio:
assert_eq!(apple2 / apple1 , 1);The crate supports two kinds of newtypes: Amount and Id. See below for more details.
Rather than using the predefined sets of derives, the implementation allows for the derivation of only the necessary traits. Conversion between types:
use newtype_tools::Newtype;
#[derive(Newtype)]
#[newtype(
into(Oranges, with = |apples| Oranges((apples.0 / 2) as u32))
)]
struct Apples(u64);
struct Oranges(u32);
let apples = Apples(42);
// `Oranges` can now be created from `Apples`:
let oranges = Oranges::from(apples);
assert_eq!(oranges.0, 21);Operations on newtypes:
use newtype_tools::Newtype;
#[derive(Debug, Newtype)]
#[newtype(
partial_eq(Oranges, with = |apples, oranges| apples.0 == oranges.0 as u64 * 2)
)]
struct Apples(u64);
struct Oranges(u32);
let apples = Apples(42);
let oranges = Oranges(21);
// `Apples` and `Oranges` can now be compared:
assert!(apples == oranges);Iterations over newtype ranges:
use newtype_tools::{Newtype, Iter};
#[derive(Debug, Newtype)]
struct Apples(u64);
let range = Apples(0)..Apples(42);
// The range of `Apples` can now be iterated:
for apple in range.iter() {
println!("{apple:?}");
}This will become even more ergonomic once the Step trait is stabilized.
§Newtype Kinds
The crate supports predefined sets of newtype properties. The concept is similar
to the phantom_newtype crate but avoids its limitations, as the newtype
generated here is a distinct Rust type. This allows new traits
to be implemented easily for the type and makes the set of derived traits
simple to extend.
The supported newtype kinds are:
| Trait | #[newtype(Amount)] | #[newtype(Id)] |
|---|---|---|
Clone | ✔ | ✔ |
Copy | ✔ | ✔ |
Debug | ✔ | ✔ |
Default | ✔ | ✔ |
Eq¹ | ✔ | ✔ |
Hash¹ | ✔ | ✔ |
Ord¹ | ✔ | ✔ |
PartialEq | ✔ | ✔ |
PartialOrd | ✔ | ✔ |
From<Repr> | ✔ | ✔ |
Add<Self> | ✔ | ✘ |
AddAssign<Self> | ✔ | ✘ |
Sub<Self> | ✔ | ✘ |
SubAssign<Self> | ✔ | ✘ |
Mul<Repr> | ✔ | ✘ |
MulAssign<Repr> | ✔ | ✘ |
Div<Self> | ✔ | ✘ |
Eq,OrdandHashare only implemented for integer inner types.
§Alternatives
nutype– An impressive 12.5k lines of code, with 7.5k lines in proc-macros alone. After trying to extend it, I realized it would be faster to simply write a new crate.phantom_newtype– Provides 19 trait implementations out of the box, but lacks a mechanism for providing custom trait implementations.newtype_derive– Outdated and relies on the legacycustom_derive!declarative macro.newtype-derive-2018– Less outdated, but it’s 2026.
§References
- Rust newtype idiom.
- Rust Step trait.
Re-exports§
Modules§
Traits§
- Newtype
Newtypetrait defines the internal representation of anewtype.
Attribute Macros§
- newtype
- Parses and expands a
newtypeattribute kind into a token stream.
Derive Macros§
- Newtype
- Parses and expands a
Newtypederive into a token stream.