1 //! # Strum 2 //! 3 //! [](https://travis-ci.org/Peternator7/strum) 4 //! [](https://crates.io/crates/strum) 5 //! [](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