3 unstable releases
Uses old Rust 2015
0.2.0 | Jul 14, 2019 |
---|---|
0.1.1 | Nov 23, 2018 |
0.1.0 | Jul 25, 2018 |
#2557 in Rust patterns
599 downloads per month
17KB
221 lines
sum_type
A convenience macro for creating a wrapper enum which may be one of several distinct types
lib.rs
:
A convenience macro for creating a wrapper enum which may be one of several distinct types. In type theory, this is often referred to as a sum type.
This crate will work with no_std
code.
Examples
Using the sum_type!()
macro is rather straightforward. You just define a
normal enum
inside it and the macro will automatically add a bunch of
handy trait implementations.
For convenience, all attributes are passed through and the macro will
derive From
for each variant.
#[macro_use]
extern crate sum_type;
sum_type! {
#[derive(Debug, Clone, PartialEq)]
pub enum MySumType {
/// The first variant.
First(u32),
/// The second variant.
Second(String),
/// A list of bytes.
Third(Vec<u8>),
}
}
let first: MySumType = 52.into();
assert_eq!(first, MySumType::First(52));
You can also be lazy and omit the variant name. This will name the variant the same thing as its type.
sum_type!{
pub enum Lazy {
f32, u32, String,
}
}
let s = Lazy::String("Hello World!".to_string());
The SumType
trait is also implemented, allowing a basic level of
introspection and dynamic typing.
use sum_type::SumType;
let first = MySumType::First(52);
assert_eq!(first.variant(), "First");
assert_eq!(first.variants(), &["First", "Second", "Third"]);
assert!(first.variant_is::<u32>());
assert_eq!(first.downcast_ref::<u32>(), Some(&52));
Assumptions
You need to make sure your type has more than one variant, meaning the following example will fail to compile.
#[macro_use]
extern crate sum_type;
sum_type!{
pub enum OneVariant {
First(String),
}
}
The compile_error!()
macro is used to give a (hopefully) useful error
message.
error: The `OneVariant` type must have more than one variant
--> src/lib.rs:37:1
|
7 | / sum_type!{
8 | | pub enum OneVariant {
9 | | First(String),
10 | | }
11 | | }
| |_^
|
= note: this error originates in a macro outside of the current crate
Sum types containing generics, including lifetimes, or which are using
visibility modifiers (e.g. pub(crate)
) aren't (yet!) supported. That
means this will fail:
sum_type!{
TypeWithLifetime<'a> {
First(&'a str),
Second(usize),
}
}
And so will this:
sum_type!{
pub(crate) ModifiedVisibility {
First(u32),
Second(String),
}
}
Try From
TryFrom
is automatically implemented on your sum type to convert it back to one of its variant types.
#[macro_use]
extern crate sum_type;
use std::convert::TryFrom;
let first = MySumType::First(52);
let as_u32 = u32::try_from(first);
assert_eq!(as_u32, Ok(52));
let second = MySumType::Second(String::from("Not a Vec<u8>"));
let as_vec_u8 = Vec::<u8>::try_from(second);
assert!(as_vec_u8.is_err());
let err = as_vec_u8.unwrap_err();
assert_eq!(err.expected_variant, "Third");
assert_eq!(err.actual_variant, "Second");
The generated_example
feature flag will create an example of our
MySumType
which can be viewed using rustdoc
.