| 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.27" |
| 20 | //! strum_macros = "0.27" |
| 21 | //! |
| 22 | //! # You can also access strum_macros exports directly through strum using the "derive" feature |
| 23 | //! strum = { version = "0.27", 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 | use core::iter::FusedIterator; |
| 34 | |
| 35 | #[cfg (feature = "phf" )] |
| 36 | #[doc (hidden)] |
| 37 | pub 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)] |
| 42 | pub enum ParseError { |
| 43 | VariantNotFound, |
| 44 | } |
| 45 | |
| 46 | #[cfg (feature = "std" )] |
| 47 | impl 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" )] |
| 58 | impl 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 | /// ``` |
| 100 | pub 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 | |
| 110 | pub trait VariantIterator: Sized { |
| 111 | type Iterator: Iterator<Item = Self>; |
| 112 | |
| 113 | fn iter() -> Self::Iterator; |
| 114 | } |
| 115 | |
| 116 | pub 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 | /// ``` |
| 147 | pub 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 string, integer and bool literals |
| 159 | /// are supported in attributes. |
| 160 | /// |
| 161 | /// # Example |
| 162 | /// |
| 163 | /// ```rust |
| 164 | /// # use std::fmt::Debug; |
| 165 | /// // You need to bring the type into scope to use it!!! |
| 166 | /// use strum::EnumProperty; |
| 167 | /// |
| 168 | /// #[derive(PartialEq, Eq, Debug, EnumProperty)] |
| 169 | /// enum Class { |
| 170 | /// #[strum(props(Teacher="Ms.Frizzle" , Room="201" , students=16, mandatory=true))] |
| 171 | /// History, |
| 172 | /// #[strum(props(Teacher="Mr.Smith" ))] |
| 173 | /// #[strum(props(Room="103" , students=10))] |
| 174 | /// Mathematics, |
| 175 | /// #[strum(props(Time="2:30" , mandatory=true))] |
| 176 | /// Science, |
| 177 | /// } |
| 178 | /// |
| 179 | /// let history = Class::History; |
| 180 | /// assert_eq!("Ms.Frizzle" , history.get_str("Teacher" ).unwrap()); |
| 181 | /// assert_eq!(16, history.get_int("students" ).unwrap()); |
| 182 | /// assert!(history.get_bool("mandatory" ).unwrap()); |
| 183 | /// ``` |
| 184 | pub trait EnumProperty { |
| 185 | fn get_str(&self, prop: &str) -> Option<&'static str>; |
| 186 | fn get_int(&self, _prop: &str) -> Option<i64>; |
| 187 | fn get_bool(&self, _prop: &str) -> Option<bool>; |
| 188 | } |
| 189 | |
| 190 | /// A cheap reference-to-reference conversion. Used to convert a value to a |
| 191 | /// reference value with `'static` lifetime within generic code. |
| 192 | #[deprecated ( |
| 193 | since = "0.22.0" , |
| 194 | note = "please use `#[derive(IntoStaticStr)]` instead" |
| 195 | )] |
| 196 | pub trait AsStaticRef<T> |
| 197 | where |
| 198 | T: ?Sized, |
| 199 | { |
| 200 | fn as_static(&self) -> &'static T; |
| 201 | } |
| 202 | |
| 203 | /// A trait for capturing the number of variants in Enum. This trait can be autoderived by |
| 204 | /// `strum_macros`. |
| 205 | pub trait EnumCount { |
| 206 | const COUNT: usize; |
| 207 | } |
| 208 | |
| 209 | /// A trait for retrieving the names of each variant in Enum. This trait can |
| 210 | /// be autoderived by `strum_macros`. |
| 211 | pub trait VariantNames { |
| 212 | /// Names of the variants of this enum |
| 213 | const VARIANTS: &'static [&'static str]; |
| 214 | } |
| 215 | |
| 216 | /// A trait for retrieving the enum generated by [`EnumDiscriminants`] from an associated |
| 217 | /// Type on the original enumeration. This trait can be autoderived by `strum_macros`. |
| 218 | pub trait IntoDiscriminant { |
| 219 | /// Enum listing the same variants as this enum but without any data fields |
| 220 | type Discriminant; |
| 221 | |
| 222 | fn discriminant(&self) -> Self::Discriminant; |
| 223 | } |
| 224 | |
| 225 | /// A trait for retrieving a static array containing all the variants in an Enum. |
| 226 | /// This trait can be autoderived by `strum_macros`. For derived usage, all the |
| 227 | /// variants in the enumerator need to be unit-types, which means you can't autoderive |
| 228 | /// enums with inner data in one or more variants. Consider using it alongside |
| 229 | /// [`EnumDiscriminants`] if you require inner data but still want to have an |
| 230 | /// static array of variants. |
| 231 | pub trait VariantArray: ::core::marker::Sized + 'static { |
| 232 | const VARIANTS: &'static [Self]; |
| 233 | } |
| 234 | |
| 235 | #[cfg (feature = "derive" )] |
| 236 | pub use strum_macros::*; |
| 237 | |
| 238 | macro_rules! DocumentMacroRexports { |
| 239 | ($($export:ident),+) => { |
| 240 | $( |
| 241 | #[cfg(all(docsrs, feature = "derive" ))] |
| 242 | #[cfg_attr(docsrs, doc(cfg(feature = "derive" )))] |
| 243 | pub use strum_macros::$export; |
| 244 | )+ |
| 245 | }; |
| 246 | } |
| 247 | |
| 248 | // We actually only re-export these items individually if we're building |
| 249 | // for docsrs. You can do a weird thing where you rename the macro |
| 250 | // and then reference it through strum. The renaming feature should be deprecated now that |
| 251 | // 2018 edition is almost 2 years old, but we'll need to give people some time to do that. |
| 252 | DocumentMacroRexports! { |
| 253 | AsRefStr, |
| 254 | Display, |
| 255 | EnumCount, |
| 256 | EnumDiscriminants, |
| 257 | EnumIter, |
| 258 | EnumMessage, |
| 259 | EnumProperty, |
| 260 | EnumString, |
| 261 | VariantNames, |
| 262 | FromRepr, |
| 263 | IntoStaticStr, |
| 264 | VariantArray |
| 265 | } |
| 266 | |