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