[][src]Crate enum_derive_2018

This crate provides several macros for deriving some useful methods for unitary enums (i.e. enums where variants do not have payloads).

All of these macros are designed to be used with the macro-attr-2018 crate, though they can be used independent of it.

Example

Derive iterators that yield all variants of an enum.

use macro_attr_2018::macro_attr;
use enum_derive_2018::{IterVariants, IterVariantNames};

macro_attr! {
    #[derive(Debug, PartialEq, Eq,
        IterVariants!(CandyVariants), IterVariantNames!(CandyVariantNames))]
    pub enum Candy { Musk, FruitRock, BoPeeps, LemonSherbert }
}

let vars: CandyVariants = Candy::iter_variants();
let names: CandyVariantNames = Candy::iter_variant_names();
assert_eq!(&*vars.zip(names).collect::<Vec<_>>(), &[
    (Candy::Musk, "Musk"),
    (Candy::FruitRock, "FruitRock"),
    (Candy::BoPeeps, "BoPeeps"),
    (Candy::LemonSherbert, "LemonSherbert"),
]);

Alternately, derive next_variant and prev_variant methods.

use macro_attr_2018::macro_attr;
use enum_derive_2018::{NextVariant, PrevVariant};

use Hanagami::*;

macro_attr! {
    #[derive(Debug, PartialEq, Eq, NextVariant!, PrevVariant!)]
    pub enum Hanagami { Sakigami, Hasugami, Tsutagami }
}

assert_eq!(Sakigami.next_variant(), Some(Hasugami));
assert_eq!(Hasugami.next_variant(), Some(Tsutagami));
assert_eq!(Tsutagami.next_variant(), None);

assert_eq!(Sakigami.prev_variant(), None);
assert_eq!(Hasugami.prev_variant(), Some(Sakigami));
assert_eq!(Tsutagami.prev_variant(), Some(Hasugami));

Overview

This crate provides macros to derive the following methods for unitary variant enums:

  • EnumDisplay! derives Display, which outputs the name of the variant. Note that for unitary variants, this is identical to the behaviour of a derived Debug implementation.
  • EnumFromStr! derives FromStr, allowing str::parse to be used. It requires an exact match of the variant name.
  • IterVariants! derives iter_variants(), which returns an iterator over the variants of the enum in lexical order.
  • IterVariantNames! derives iter_variant_names(), which returns an iterator over the string names of the variants of the enum in lexical order.
  • NextVariant! derives next_variant(&self), which returns the next variant, or None when called for the last.
  • PrevVariant! derives prev_variant(&self), which returns the previous variant, or None when called for the first.
  • EnumFromInner! derives From<T> for each variant's payload, assuming all variants are unary.
  • EnumInnerAsTrait! derives a method to return a borrowed pointer to the inner value, cast to a trait object.

Both of the IterVariant*! macros accept a single deriving form. Taking IterVariants! as an example, it must be invoked like so:

macro_attr! {
    #[derive(IterVariants!(GetVariants))]
    pub enum Get { Up, Down, AllAround }
}

The argument is the name of the iterator type that will be generated. Neither macro imposes any naming requirements, save the obvious: the name must not conflict with any other types.

EnumInnerAsTrait! accepts a single deriving form that specifies the name of the method to be derived, whether the borrow should be mutable, and the trait of interest. For example:

macro_attr! {
    #[derive(EnumInnerAsTrait!(pub as_display -> &dyn std::fmt::Display))]
    enum Value {
        U32(u32),
        U64(u64),
    }
}

let s = format!("{}", Value::U64(42).as_display());
assert_eq!(&s[..], "42");

The other macros take no arguments.

The methods and iterator types generated will be public if the enum itself is public; otherwise, they will be private.

Using Without macro_attr!

Although designed to be used with macro_attr!, all of the macros in this crate can be used without it. The following:

macro_attr! {
    #[derive(Copy, Clone, Debug, IterVariants!(Vars))]
    enum ItAintRight { BabeNo, NoNo, BoyBoy }
}

Can also be written as:

#[derive(Copy, Clone, Debug)]
enum ItAintRight { BabeNo, NoNo, BoyBoy }

IterVariants! { (Vars) enum ItAintRight { BabeNo, NoNo, BoyBoy } }

Other Examples

This shows how to use Display and FromStr to perform string round-tripping of enums.

use macro_attr_2018::macro_attr;
use enum_derive_2018::{EnumDisplay, EnumFromStr};

macro_attr! {
    #[derive(Debug, PartialEq, EnumDisplay!, EnumFromStr!)]
    pub enum TrollDigit { One, Two, Three, Many, Lots }
}

fn to_troll(mut n: u32) -> String {
    use std::fmt::Write;
    let mut s = String::new();

    if n == 0 {
        panic!("I dun' see nuffin'; how's I s'posed to count it?!");
    }

    while n > 0 {
        let (del, dig) = match n {
            n if n >= 16 => (16, TrollDigit::Lots),
            n if n >= 4 => (4, TrollDigit::Many),
            n if n >= 3 => (3, TrollDigit::Three),
            n if n >= 2 => (2, TrollDigit::Two),
            _ => (1, TrollDigit::One),
        };
        n -= del;
        if s.len() > 0 { s.push_str(" "); }
        write!(&mut s, "{}", dig).unwrap();
    }

    s
}

fn from_troll(s: &str) -> Result<u32, enum_derive_2018::ParseEnumError> {
    let mut n = 0;
    for word in s.split_whitespace() {
        n += match word.parse()? {
            TrollDigit::One => 1,
            TrollDigit::Two => 2,
            TrollDigit::Three => 3,
            TrollDigit::Many => 4,
            TrollDigit::Lots => 16,
        };
    }
    if n == 0 {
        Err(enum_derive_2018::ParseEnumError)
    } else {
        Ok(n)
    }
}

let number = 42;
let troll_number = to_troll(number);
assert_eq!(troll_number, "Lots Lots Many Many Two");
assert_eq!(from_troll(&troll_number), Ok(number));

Macros

EnumDisplay
EnumFromInner
EnumFromStr
EnumInnerAsTrait
IterVariantNames
IterVariants
NextVariant
PrevVariant

Structs

ParseEnumError

This is the error type used for derived implementations of FromStr for unitary enums.