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