strum/
lib.rs

1//! # Strum
2//!
3//! [![Build Status](https://travis-ci.org/Peternator7/strum.svg?branch=master)](https://travis-ci.org/Peternator7/strum)
4//! [![Latest Version](https://img.shields.io/crates/v/strum.svg)](https://crates.io/crates/strum)
5//! [![Rust Documentation](https://docs.rs/strum/badge.svg)](https://docs.rs/strum)
6//!
7//! Strum is a set of macros and traits for working with
8//! enums and strings easier in Rust.
9//!
10//! The full version of the README can be found on [GitHub](https://github.com/Peternator7/strum).
11//!
12//! # Including Strum in Your Project
13//!
14//! Import strum and `strum_macros` into your project by adding the following lines to your
15//! Cargo.toml. `strum_macros` contains the macros needed to derive all the traits in Strum.
16//!
17//! ```toml
18//! [dependencies]
19//! strum = "0.25"
20//! strum_macros = "0.25"
21//!
22//! # You can also access strum_macros exports directly through strum using the "derive" feature
23//! strum = { version = "0.25", features = ["derive"] }
24//! ```
25//!
26
27#![cfg_attr(not(feature = "std"), no_std)]
28#![cfg_attr(docsrs, feature(doc_cfg))]
29
30// only for documentation purposes
31pub mod additional_attributes;
32
33#[cfg(feature = "phf")]
34#[doc(hidden)]
35pub use phf as _private_phf_reexport_for_macro_if_phf_feature;
36
37/// The `ParseError` enum is a collection of all the possible reasons
38/// an enum can fail to parse from a string.
39#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
40pub enum ParseError {
41    VariantNotFound,
42}
43
44#[cfg(feature = "std")]
45impl std::fmt::Display for ParseError {
46    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
47        // We could use our macro here, but this way we don't take a dependency on the
48        // macros crate.
49        match self {
50            ParseError::VariantNotFound => write!(f, "Matching variant not found"),
51        }
52    }
53}
54
55#[cfg(feature = "std")]
56impl std::error::Error for ParseError {
57    fn description(&self) -> &str {
58        match self {
59            ParseError::VariantNotFound => {
60                "Unable to find a variant of the given enum matching the string given. Matching \
61                 can be extended with the Serialize attribute and is case sensitive."
62            }
63        }
64    }
65}
66
67/// This trait designates that an `Enum` can be iterated over. It can
68/// be auto generated using `strum_macros` on your behalf.
69///
70/// # Example
71///
72/// ```rust
73/// # use std::fmt::Debug;
74/// // You need to bring the type into scope to use it!!!
75/// use strum::{EnumIter, IntoEnumIterator};
76///
77/// #[derive(EnumIter, Debug)]
78/// enum Color {
79///     Red,
80///     Green { range: usize },
81///     Blue(usize),
82///     Yellow,
83/// }
84///
85/// // Iterate over the items in an enum and perform some function on them.
86/// fn generic_iterator<E, F>(pred: F)
87/// where
88///     E: IntoEnumIterator,
89///     F: Fn(E),
90/// {
91///     for e in E::iter() {
92///         pred(e)
93///     }
94/// }
95///
96/// generic_iterator::<Color, _>(|color| println!("{:?}", color));
97/// ```
98pub trait IntoEnumIterator: Sized {
99    type Iterator: Iterator<Item = Self>;
100
101    fn iter() -> Self::Iterator;
102}
103
104pub trait VariantIterator: Sized {
105    type Iterator: Iterator<Item = Self>;
106
107    fn iter() -> Self::Iterator;
108}
109
110pub trait VariantMetadata {
111    const VARIANT_COUNT: usize;
112    const VARIANT_NAMES: &'static [&'static str];
113
114    fn variant_name(&self) -> &'static str;
115}
116
117/// Associates additional pieces of information with an Enum. This can be
118/// autoimplemented by deriving `EnumMessage` and annotating your variants with
119/// `#[strum(message="...")]`.
120///
121/// # Example
122///
123/// ```rust
124/// # use std::fmt::Debug;
125/// // You need to bring the type into scope to use it!!!
126/// use strum::EnumMessage;
127///
128/// #[derive(PartialEq, Eq, Debug, EnumMessage)]
129/// enum Pet {
130///     #[strum(message="I have a dog")]
131///     #[strum(detailed_message="My dog's name is Spots")]
132///     Dog,
133///     /// I am documented.
134///     #[strum(message="I don't have a cat")]
135///     Cat,
136/// }
137///
138/// let my_pet = Pet::Dog;
139/// assert_eq!("I have a dog", my_pet.get_message().unwrap());
140/// ```
141pub trait EnumMessage {
142    fn get_message(&self) -> Option<&'static str>;
143    fn get_detailed_message(&self) -> Option<&'static str>;
144
145    /// Get the doc comment associated with a variant if it exists.
146    fn get_documentation(&self) -> Option<&'static str>;
147    fn get_serializations(&self) -> &'static [&'static str];
148}
149
150/// `EnumProperty` is a trait that makes it possible to store additional information
151/// with enum variants. This trait is designed to be used with the macro of the same
152/// name in the `strum_macros` crate. Currently, the only string literals are supported
153/// in attributes, the other methods will be implemented as additional attribute types
154/// become stabilized.
155///
156/// # Example
157///
158/// ```rust
159/// # use std::fmt::Debug;
160/// // You need to bring the type into scope to use it!!!
161/// use strum::EnumProperty;
162///
163/// #[derive(PartialEq, Eq, Debug, EnumProperty)]
164/// enum Class {
165///     #[strum(props(Teacher="Ms.Frizzle", Room="201"))]
166///     History,
167///     #[strum(props(Teacher="Mr.Smith"))]
168///     #[strum(props(Room="103"))]
169///     Mathematics,
170///     #[strum(props(Time="2:30"))]
171///     Science,
172/// }
173///
174/// let history = Class::History;
175/// assert_eq!("Ms.Frizzle", history.get_str("Teacher").unwrap());
176/// ```
177pub trait EnumProperty {
178    fn get_str(&self, prop: &str) -> Option<&'static str>;
179    fn get_int(&self, _prop: &str) -> Option<usize> {
180        Option::None
181    }
182
183    fn get_bool(&self, _prop: &str) -> Option<bool> {
184        Option::None
185    }
186}
187
188/// A cheap reference-to-reference conversion. Used to convert a value to a
189/// reference value with `'static` lifetime within generic code.
190#[deprecated(
191    since = "0.22.0",
192    note = "please use `#[derive(IntoStaticStr)]` instead"
193)]
194pub trait AsStaticRef<T>
195where
196    T: ?Sized,
197{
198    fn as_static(&self) -> &'static T;
199}
200
201/// A trait for capturing the number of variants in Enum. This trait can be autoderived by
202/// `strum_macros`.
203pub trait EnumCount {
204    const COUNT: usize;
205}
206
207/// A trait for retrieving the names of each variant in Enum. This trait can
208/// be autoderived by `strum_macros`.
209pub trait VariantNames {
210    /// Names of the variants of this enum
211    const VARIANTS: &'static [&'static str];
212}
213
214#[cfg(feature = "derive")]
215pub use strum_macros::*;
216
217macro_rules! DocumentMacroRexports {
218    ($($export:ident),+) => {
219        $(
220            #[cfg(all(docsrs, feature = "derive"))]
221            #[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
222            pub use strum_macros::$export;
223        )+
224    };
225}
226
227// We actually only re-export these items individually if we're building
228// for docsrs. You can do a weird thing where you rename the macro
229// and then reference it through strum. The renaming feature should be deprecated now that
230// 2018 edition is almost 2 years old, but we'll need to give people some time to do that.
231DocumentMacroRexports! {
232    AsRefStr,
233    AsStaticStr,
234    Display,
235    EnumCount,
236    EnumDiscriminants,
237    EnumIter,
238    EnumMessage,
239    EnumProperty,
240    EnumString,
241    EnumVariantNames,
242    FromRepr,
243    IntoStaticStr,
244    ToString
245}