Lightweight newtypes without macros.
phantom-newtype
is a library that provides a simple way to define newtypes.
It's not a replacement for the newtype idiom but rather a nice addition to it that covers common use-cases.
Example: ```rust // Amount and Id are "kinds" of newtypes people commonly use. // Let's call them "archetypes". use phantom_newtype::{Amount, Id, Instant};
// CentUnit here is just a marker that should never be constructed.
// It allows us to forge a new type of amounts.
enum CentUnit {}
type Cents = AmountCents
.
// Let's create another type of amounts.
// phantom-newtype is not a replacement for a powerful units library though.
enum YearUnit {}
type Years = Amount
// Instants express the idea of time with respect to some point of reference.
// E.g. year of birth is instant but age is amount.
// Note that it is perfectly fine (and useful in practice) to use the same
// marker type for both instants and corresponding amounts.
type YearAD = Instant
// Any type can be used as a marker, it's not necessary to always define
// fresh empty types.
type UserId = IdId
.
struct User { id: UserId, name: String, balance: Cents, age: Years, }
impl User { fn new() -> Self { Self { id: UserId::from(1), name: "John".tostring(), balance: Cents::from(1000), age: Years::from(28), membersince: YearAD::from(2016), } } }
// Tags used in archetypes can be useful in generic code.
fn loadbyid
phantom-newtype
| Trait\Archetype | Amount<T, Repr>
| Id<T, Repr>
| Instant<T, Repr>
|
|-------------------|:-----------------:|:-------------:|:------------------:|
| Default
| ✘ | ✘ | ✘ |
| Clone
| ✔ | ✔ | ✔ |
| Copy
| ✔ | ✔ | ✔ |
| Debug
| ✔ | ✔ | ✔ |
| Display
| ✔ | ✔ | ✔ |
| Eq
| ✔ | ✔ | ✔ |
| Ord
| ✔ | ✔ | ✔ |
| Hash
| ✔ | ✔ | ✔ |
| From<Repr>
| ✔ | ✔ | ✔ |
| Add<Self>
| ✔ | ✘ | ✘ |
| AddAssign<Self>
| ✔ | ✘ | ✘ |
| Sub<Self>
| ✔ | ✘ | ✔ |
| SubAssign<Self>
| ✔ | ✘ | ✘ |
| Mul<Repr>
| ✔ | ✘ | ✔ |
| MulAssign<Repr>
| ✔ | ✘ | ✔ |
| Div<Self>
| ✔ | ✘ | ✔ |
| Operation | Output type |
|---------------------------------|-----------------------------------------|
| Instant<T, R> - Instant<T, R>
| Amount<Unit, <R as Sub>::Output>
|
| Instant<T, R> - Amount<T, R2>
| Instant<Unit, <R as Sub<R2>>::Output>
|
| Instant<T, R> + Amount<T, R2>
| Instant<Unit, <R as Add<R2>>::Output>
|
The approach taken by the library has some limitations due to design choices made by Rust:
phantom-newtype
.
Every combination of desired traits requires a new archetype.phantom-newtype
, every newtype inherits implementations of its representation (including Debug
and Display
).