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
31 pub mod additional_attributes;
32 
33 #[cfg(feature = "phf")]
34 #[doc(hidden)]
35 pub 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)]
40 pub enum ParseError {
41     VariantNotFound,
42 }
43 
44 #[cfg(feature = "std")]
45 impl std::fmt::Display for ParseError {
fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>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")]
56 impl std::error::Error for ParseError {
description(&self) -> &str57     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 /// ```
98 pub trait IntoEnumIterator: Sized {
99     type Iterator: Iterator<Item = Self>;
100 
iter() -> Self::Iterator101     fn iter() -> Self::Iterator;
102 }
103 
104 pub trait VariantIterator: Sized {
105     type Iterator: Iterator<Item = Self>;
106 
iter() -> Self::Iterator107     fn iter() -> Self::Iterator;
108 }
109 
110 pub trait VariantMetadata {
111     const VARIANT_COUNT: usize;
112     const VARIANT_NAMES: &'static [&'static str];
113 
variant_name(&self) -> &'static str114     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 /// ```
141 pub trait EnumMessage {
get_message(&self) -> Option<&'static str>142     fn get_message(&self) -> Option<&'static str>;
get_detailed_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.
get_documentation(&self) -> Option<&'static str>146     fn get_documentation(&self) -> Option<&'static str>;
get_serializations(&self) -> &'static [&'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 /// ```
177 pub trait EnumProperty {
get_str(&self, prop: &str) -> Option<&'static str>178     fn get_str(&self, prop: &str) -> Option<&'static str>;
get_int(&self, _prop: &str) -> Option<usize>179     fn get_int(&self, _prop: &str) -> Option<usize> {
180         Option::None
181     }
182 
get_bool(&self, _prop: &str) -> Option<bool>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 )]
194 pub trait AsStaticRef<T>
195 where
196     T: ?Sized,
197 {
as_static(&self) -> &'static T198     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`.
203 pub 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`.
209 pub trait VariantNames {
210     /// Names of the variants of this enum
211     const VARIANTS: &'static [&'static str];
212 }
213 
214 #[cfg(feature = "derive")]
215 pub use strum_macros::*;
216 
217 macro_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.
231 DocumentMacroRexports! {
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 }
246