#sum #variant #enum #either #type

no-std sum_type

A convenience macro for creating a wrapper enum which may be one of several distinct types

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

#1120 in Rust patterns

Download history 144/week @ 2021-08-10 130/week @ 2021-08-17 162/week @ 2021-08-24 177/week @ 2021-08-31 228/week @ 2021-09-07 247/week @ 2021-09-14 207/week @ 2021-09-21 114/week @ 2021-09-28 131/week @ 2021-10-05 156/week @ 2021-10-12 112/week @ 2021-10-19 109/week @ 2021-10-26 124/week @ 2021-11-02 202/week @ 2021-11-09 321/week @ 2021-11-16 191/week @ 2021-11-23

849 downloads per month

MIT license

16KB
221 lines

sum_type

Build Status license Crates.io Docs.rs

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>),
    }
}

# fn main() {
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.

# #[macro_use]
# extern crate sum_type;
sum_type!{
    pub enum Lazy {
        f32, u32, String,
    }
}
# fn main() {
let s = Lazy::String("Hello World!".to_string());
# }

The SumType trait is also implemented, allowing a basic level of introspection and dynamic typing.

# #[macro_use]
# extern crate sum_type;
use sum_type::SumType;
# sum_type! { #[derive(Debug, Clone, PartialEq)] pub enum MySumType {
#         First(u32), Second(String), Third(Vec<u8>), } }

# fn main() {
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.

# fn main() {}
#[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:

# fn main() {}
# #[macro_use]
# extern crate sum_type;
sum_type!{
    TypeWithLifetime<'a> {
        First(&'a str),
        Second(usize),
    }
}

And so will this:

# fn main() {}
# #[macro_use]
# extern crate sum_type;
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;
# fn main() {
# sum_type! { #[derive(Debug, Clone, PartialEq)] pub enum MySumType {
#         First(u32), Second(String), Third(Vec<u8>), } }
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.

No runtime deps

Features

  • generated_example