strum 0.2.0

Helpful macros for working with enums and strings
Documentation
//! # Strum
//!
//! [![Build Status](https://travis-ci.org/Peternator7/strum.svg?branch=master)](https://travis-ci.org/Peternator7/strum)
//! [![Latest Version](https://img.shields.io/crates/v/strum.svg)](https://crates.io/crates/strum)
//! [![Rust Documentation](https://docs.rs/strum/badge.svg)](https://docs.rs/strum)
//!
//! Strum is a set of macros and traits for working with
//! enums and strings easier in Rust.
//!
//! # Including Strum in Your Project
//!
//! Import strum and strum_macros into your project by adding the following lines to your
//! Cargo.toml. Strum_macros contains the macros needed to derive all the traits in Strum.
//!
//! ```toml
//! [dependencies]
//! strum = "*"
//! strum_macros = "*"
//! ```
//!
//! And add these lines to the root of your project, either lib.rs or main.rs.
//!
//! ```rust
//! // Strum contains all the trait definitions
//! extern crate strum;
//! #[macro_use]
//! extern crate strum_macros;
//! # fn main() {}
//! ```
//!
//! # Strum Macros
//!
//! Strum has implemented the following macros:
//!
//! 1. `EnumString`: auto-derives `std::str::FromStr` on the enum. Each variant of the enum will match on it's
//!     own name. This can be overridden using `serialize="DifferentName"` on the attribute as shown below.
//!     Multiple deserializations can be added to the same variant. If the variant contains additional data,
//!     they will be set to their default values upon deserialization.
//!
//!     The `default` attribute can be applied to a tuple variant with a single data parameter. When a match isn't
//!     found, the given variant will be returned and the input string will be captured in the parameter.
//!
//!     Here is an example of the code generated by deriving `EnumString`.
//!
//!     ```
//!     # extern crate strum;
//!     # #[macro_use] extern crate strum_macros;
//!     #[derive(EnumString)]
//!     enum Color {
//!         Red,
//!
//!         // The Default value will be inserted into range if we match "Green".
//!         Green { range:usize },
//!
//!         // We can match on multiple different patterns.
//!         #[strum(serialize="blue",serialize="b")]
//!         Blue(usize),
//!
//!         // Notice that we can disable certain variants from being found
//!         #[strum(disabled="true")]
//!         Yellow,
//!     }
//!
//!     /*
//!     //The generated code will look like:
//!     impl ::std::str::FromStr for Color {
//!         type Err = strum::ParseError;
//!
//!         fn from_str(s: &str) -> Result<Color, Self::Error> {
//!             match s {
//!                 "Red" => ::std::result::Result::Ok(Color::Red),
//!                 "Green" => ::std::result::Result::Ok(Color::Green { range:Default::default() }),
//!                 "blue" | "b" => ::std::result::Result::Ok(Color::Blue(Default::default())),
//!                 _ => ::std::result::Result::Err(strum::ParseError::VariantNotFound),
//!             }
//!         }
//!     }
//!     */
//!     # fn main() {}
//!     ```
//!
//!     Note that the implementation of `FromStr` only matches on the name of the variant.
//!     Strum, where possible, avoids operations that have an unknown runtime cost, and parsing strings
//!     is potentially an expensive operation. If you do need that behavior, consider the more powerful
//!     Serde library for your serialization.
//!
//! 2. `EnumIter`: iterate over the variants of an Enum. Any additional data on your variants will be
//!     set to `Default::default()`. The macro implements `strum::IntoEnumIter` on your enum and
//!     creates a new type called `YourEnumIter` that is the iterator object. You cannot derive
//!     `EnumIter` on any type with a lifetime bound (`<'a>`) because the iterator would surely
//!     create [unbounded lifetimes] (https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html).
//!
//!     ```rust
//!     # extern crate strum;
//!     # #[macro_use] extern crate strum_macros;
//!     # use std::fmt::Debug;
//!     // You need to bring the type into scope to use it!!!
//!     use strum::IntoEnumIterator;
//!
//!     #[derive(EnumIter,Debug)]
//!     enum Color {
//!         Red,
//!         Green { range:usize },
//!         Blue(usize),
//!         Yellow,
//!     }
//!
//!     // It's simple to iterate over the variants of an enum.
//!     fn debug_colors() {
//!         for color in Color::iter() {
//!             println!("My favorite color is {:?}", color);
//!         }
//!     }
//!
//!     fn main() {
//!         debug_colors();
//!     }
//!     ```
//!
//! 3. `EnumMessage`: encode strings into the enum itself. This macro implements
//!     the `strum::EnumMessage` trait. `EnumMessage` looks for
//!     `#[strum(message="...")]` attributes on your variants.
//!     You can also provided a `detailed_message="..."` attribute to create a
//!     seperate more detailed message than the first.
//!
//!     The generated code will look something like:
//!
//!     ```rust
//!     # extern crate strum;
//!     # #[macro_use] extern crate strum_macros;
//!     // You need to bring the type into scope to use it!!!
//!     use strum::EnumMessage;
//!
//!     #[derive(EnumMessage,Debug)]
//!     enum Color {
//!         #[strum(message="Red",detailed_message="This is very red")]
//!         Red,
//!         #[strum(message="Simply Green")]
//!         Green { range:usize },
//!         #[strum(serialize="b",serialize="blue")]
//!         Blue(usize),
//!     }
//!
//!     /*
//!     // Generated code
//!     impl ::strum::EnumMessage for Color {
//!         fn get_message(&self) -> ::std::option::Option<&str> {
//!             match self {
//!                 &Color::Red => ::std::option::Option::Some("Red"),
//!                 &Color::Green {..} => ::std::option::Option::Some("Simply Green"),
//!                 _ => None
//!             }
//!         }
//!
//!         fn get_detailed_message(&self) -> ::std::option::Option<&str> {
//!             match self {
//!                 &Color::Red => ::std::option::Option::Some("This is very red"),
//!                 &Color::Green {..}=> ::std::option::Option::Some("Simply Green"),
//!                 _ => None
//!             }
//!         }
//!
//!         fn get_serializations(&self) -> &[&str] {
//!             match self {
//!                 &Color::Red => {
//!                     static ARR: [&'static str; 1] = ["Red"];
//!                     &ARR
//!                 },
//!                 &Color::Green {..}=> {
//!                     static ARR: [&'static str; 1] = ["Green"];
//!                     &ARR
//!                 },
//!                 &Color::Blue (..) => {
//!                     static ARR: [&'static str; 2] = ["b", "blue"];
//!                     &ARR
//!                 },
//!             }
//!         }
//!     }
//!     */
//!     # fn main() {}
//!     ```
//!
//! # Additional Attributes
//!
//! Strum supports several custom attributes to modify the generated code. Custom attributes are
//! applied to a variant by adding #[strum(parameter="value")] to the variant.
//!
//! - `serialize="..."`: Changes the text that `FromStr()` looks for when parsing a string. This attribute can
//!    be applied multiple times to an element and the enum variant will be parsed if any of them match.
//!
//! - `default="true"`: Applied to a single variant of an enum. The variant must be a Tuple-like
//!    variant with a single piece of data that can be create from a `&str` i.e. `T: From<&str>`.
//!    The generated code will now return the variant with the input string captured as shown below
//!    instead of failing.
//!
//!     ```ignore
//!     // Replaces this:
//!     _ => Err(strum::ParseError::VariantNotFound)
//!     // With this in generated code:
//!     default => Ok(Variant(default.into()))
//!     ```
//!     The plugin will fail if the data doesn't implement From<&str>. You can only have one `default`
//!     on your enum.
//!
//! - `disabled="true"`: removes variant from generated code.
//!
//! - `message=".."`: Adds a message to enum variant. This is used in conjunction with the `EnumMessage`
//!    trait to associate a message with a variant. If `detailed_message` is not provided,
//!    then `message` will also be returned when get_detailed_message() is called.
//!
//! - `detailed_message=".."`: Adds a more detailed message to a variant. If this value is omitted, then
//!    `message` will be used in it's place.
//!
//! # Examples
//!
//! Using `EnumMessage` for quickly implementing `Error`
//!
//! ```rust
//! extern crate strum;
//! #[macro_use]
//! extern crate strum_macros;
//! # use std::error::Error;
//! # use std::fmt::*;
//! use strum::EnumMessage;
//!
//! #[derive(Debug, EnumMessage)]
//! enum ServerError {
//!     #[strum(message="A network error occured")]
//!     #[strum(detailed_message="Try checking your connection.")]
//!     NetworkError,
//!     #[strum(message="User input error.")]
//!     #[strum(detailed_message="There was an error parsing user input. Please try again.")]
//!     InvalidUserInputError,
//! }
//!
//! impl Display for ServerError {
//!     fn fmt(&self, f: &mut Formatter) -> Result {
//!         write!(f, "{}", self.get_message().unwrap())
//!     }
//! }
//!
//! impl Error for ServerError {
//!     fn description(&self) -> &str {
//!         self.get_detailed_message().unwrap()
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Using `EnumString` to tokenize a series of inputs:
//!
//! ```rust
//! extern crate strum;
//! #[macro_use]
//! extern crate strum_macros;
//! use std::str::FromStr;
//!
//! #[derive(Eq, PartialEq, Debug, EnumString)]
//! enum Tokens {
//!     #[strum(serialize="fn")]
//!     Function,
//!     #[strum(serialize="(")]
//!     OpenParen,
//!     #[strum(serialize=")")]
//!     CloseParen,
//!     #[strum(default="true")]
//!     Ident(String)
//! }
//!
//! fn main() {
//!     let toks = ["fn", "hello_world", "(", ")"].iter()
//!                    .map(|tok| Tokens::from_str(tok).unwrap())
//!                    .collect::<Vec<_>>();
//!
//!     assert_eq!(toks, vec![Tokens::Function,
//!                           Tokens::Ident(String::from("hello_world")),
//!                           Tokens::OpenParen,
//!                           Tokens::CloseParen]);
//! }
//! ```
//!
//! # Debugging
//!
//! To see the generated code, set the DEBUG_STRUM environment variable before compiling your code.
//! `DEBUG_STRUM=1` will dump all of the generated code for every type. `DEBUG_STRUM=YourType` will
//! only dump the code generated on a type named YourType.
//!
//! # Name
//!
//! Strum is short for STRing enUM because it's a library for augmenting enums with additional
//! information through strings.
//!
//! Strumming is also a very whimsical motion, much like writing Rust code.

/// The ParseError enum is a collection of all the possible reasons
/// an enum can fail to parse from a string.
#[derive(Debug,Clone,Copy,Eq,PartialEq,Hash)]
pub enum ParseError {
    VariantNotFound,
}

impl std::fmt::Display for ParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match self {
            &ParseError::VariantNotFound => write!(f, "Matching variant not found"),
        }
    }
}

impl std::error::Error for ParseError {
    fn description(&self) -> &str {
        match self {
            &ParseError::VariantNotFound => {
                "Unable to find a variant of the given enum matching the string given. Matching \
                 can be extended with the Serialize attribute and is case sensitive."
            }
        }
    }
}

/// This trait designates that an `Enum` can be iterated over. It can
/// be auto generated using `strum_macros` on your behalf.
///
/// # Example
///
/// ```rust
/// # extern crate strum;
/// # #[macro_use] extern crate strum_macros;
/// # use std::fmt::Debug;
/// // You need to bring the type into scope to use it!!!
/// use strum::IntoEnumIterator;
///
/// #[derive(EnumIter,Debug)]
/// enum Color {
///         Red,
///         Green { range:usize },
///         Blue(usize),
///         Yellow,
/// }
///
/// // Iterating over any enum requires 2 type parameters
/// // A 3rd is used in this example to allow passing a predicate
/// fn generic_iterator<E, I, F>(pred: F)
///                      where E: IntoEnumIterator<Iterator=I>,
///                            I: Iterator<Item=E>,
///                            F: Fn(E) {
///     for e in E::iter() {
///         pred(e)
///     }
/// }
///
/// fn main() {
///     generic_iterator::<Color,_, _>(|color| println!("{:?}", color));
/// }
/// ```
pub trait IntoEnumIterator {
    type Iterator;

    fn iter() -> Self::Iterator;
}

/// Associates additional pieces of information with an Enum. This can be
/// autoimplemented by deriving `EnumMessage` and annotating your variants with
/// `#[strum(message="...")].
///
/// # Example
///
/// ```rust
/// # extern crate strum;
/// # #[macro_use] extern crate strum_macros;
/// # use std::fmt::Debug;
/// // You need to bring the type into scope to use it!!!
/// use strum::EnumMessage;
///
/// #[derive(PartialEq, Eq, Debug, EnumMessage)]
/// enum Pet {
///     #[strum(message="I have a dog")]
///     #[strum(detailed_message="My dog's name is Spots")]
///     Dog,
///     #[strum(message="I don't have a cat")]
///     Cat,
/// }
///
/// fn main() {
///     let my_pet = Pet::Dog;
///     assert_eq!("I have a dog", my_pet.get_message().unwrap());
/// }
/// ```
pub trait EnumMessage {
    fn get_message(&self) -> Option<&str>;
    fn get_detailed_message(&self) -> Option<&str>;
    fn get_serializations(&self) -> &[&str];
}