Crate microtype[−][src]
Expand description
A library to ease creation of so-called “microtypes”.
A microtype is a thin wrapper around a more primitive type (e.g. String), that can help to provide
safety against logic bugs at compile-time.
For example, consider the following code from an imaginary e-commerce app:
fn handle_order(user_id: String, order_id: String) {
// ...
}
fn main() {
let user_id = retrieve_user_id();
let order_id = retrieve_order_id();
handle_order(order_id, user_id);
}This code compiles, but has a bug: the order_id and user_id are used in the wrong order.
This example is fairly trivial and easy to spot, but the larger a project gets, the harder it
becomes to spot these issues. Not only that, when refactoring, wouldn’t it be nice if the
compiler could highlight all the places you needed to change for you?
For this, we use microtypes. Microtypes are thin wrappers around other types, and tell the compiler about different uses for the same underlying data. For example, if we rewrite our earlier code to use microtypes, it might look like this:
// microtype wrappers around String
microtype!(Stirng => UserId);
microtype!(Stirng => OrderId);
fn handle_order(user_id: UserId, order_id: OrderId) {
// ...
}
fn main() {
let user_id: OrderId = retrieve_user_id();
let order_id: UserId = retrieve_order_id();
handle_order(order_id, user_id); // Error: incompatible types
}To create a microtype, use the microtype macro. Microtypes also implement the Microtype
trait which defines some common behaviours:
microtype!(String => UserId);
microtype!(String => Username);
fn main() {
let user_id = UserId::new("id".into()); // create new UserId
let string = user_id.into_inner(); // consume UserId, return inner String
let username = Username::new(string); // create new Username
// sometimes you need to explicitly change the type of a value:
let user_id: UserId = username.transmute();
}
By default, Debug, Clone, Eq and PartialEq are derived for a microtype. However, this
can be customised by providing a list of traits to derive:
microtype!(f64 => Coord); // Error: f64 doesn't implement EqInstead:
microtype!(f64 => Coord, Clone, Debug, PartialEq); // worksIf you just want to add Copy to the derived traits, you can use the copy_microtype macro
instead:
microtype!(i32 => Foo, Clone, Debug, Eq, PartialEq, Copy);
// behaves the same as:
copy_microtype!(i32 => Bar);Microtypes are also repr(transparent).
Re-exports
Macros
A utility macro to define microtypes that implement Copy
Create a new microtype
Create a secret microtypes
Traits
A trait implemented by microtypes
A trait implemented by secret microtypes