Crate sum_type

source ·
Expand description

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

Feature Flags

The try_from feature flag (disabled by default) will implement TryFrom to convert a from your sum type back 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.

Modules

An example of the generated sum type.

Macros

Execute an operation on each enum variant.
The entire point.

Structs

The result of a failed conversion from TryFrom.

Traits

Various methods for introspection and dynamic typing.