diff --git a/CHANGELOG.md b/CHANGELOG.md index bf22885..2bbc217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,24 @@ # Changelog +## 0.15.0 + +### Added + +* Added Feature flags to rename macros. This is to improve compatibility with older versions of rust. [Wiki](https://github.com/Peternator7/strum/wiki/Macro-Renames) + +## 0.14.0 + +### Added + +* Allow Missing Docs on EnumCount. [PR #43](https://github.com/Peternator7/strum/pull/43) +* Fix serialize_all in `AsRefStr`, `AsStaticStr` and `IntoStaticStr`. [PR #42](https://github.com/Peternator7/strum/pull/42) + * This is a bug fix, but it may break code that was relying on the incorrect behavior. + ## 0.13.0 ### Added -* Added a derive to implement `From` for `&'static str`. This deprecates `AsStaticStr` since +* Added a derive to implement `From` for `&'static str`. This deprecates `AsStaticStr` since the new solution doesn't require a `strum` specific trait to use. ## 0.12.0 diff --git a/Cargo.toml b/Cargo.toml index e60aa5b..619d955 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,7 @@ members = [ "strum", "strum_macros", - "strum_tests", -] \ No newline at end of file + "strum_tests" +] + +exclude = [ "strum_tests_rename" ] \ No newline at end of file diff --git a/LICENSE b/LICENSE index a4bb911..588b4a7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Peter Glotfelty +Copyright (c) 2019 Peter Glotfelty Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 59203ec..3b696a3 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Strum is compatible with versions of rustc >= 1.26.0. That's the earliest versio impl trait. Pull Requests that improve compatibility with older versions are welcome, but new feature work will focus on the current version of rust with an effort to avoid breaking compatibility with older versions. +Versions of rust prior to 1.31.0 don't support importing procedural macros by path. See [this wiki page](https://github.com/Peternator7/strum/wiki/Macro-Renames) if you are finding that one of Strum's macros collides with a macro being imported by a different crate. *You do not need this in versions of rust >= 1.31.0* + # Including Strum in Your Project Import strum and strum_macros into your project by adding the following lines to your @@ -20,8 +22,8 @@ Cargo.toml. Strum_macros contains the macros needed to derive all the traits in ```toml [dependencies] -strum = "0.14.0" -strum_macros = "0.14.0" +strum = "0.15.0" +strum_macros = "0.15.0" ``` And add these lines to the root of your project, either lib.rs or main.rs. @@ -31,6 +33,9 @@ And add these lines to the root of your project, either lib.rs or main.rs. extern crate strum; #[macro_use] extern crate strum_macros; + +// Instead of #[macro_use], newer versions of rust should prefer +use strum_macros::{Display, EnumIter}; // etc. ``` # Contributing @@ -50,392 +55,400 @@ only dump the code generated on a type named `YourType`. Strum has implemented the following macros: -1. `EnumString`: auto-derives `std::str::FromStr` on the enum. Each variant of the enum will match on it's - own name. This can be overridden using `serialize="DifferentName"` or `to_string="DifferentName"` - on the attribute as shown below. - Multiple deserializations can be added to the same variant. If the variant contains additional data, - they will be set to their default values upon deserialization. +| Macro | Description | +| --- | ----------- | +| [EnumString](#EnumString) | Converts strings to enum variants based on their name | +| [Display](#Display) | Converts enum variants to strings | +| [AsRefStr](#AsRefStr) | Converts enum variants to `&'static str` | +| [IntoStaticStr](#IntoStaticStr) | Implements `From for &'static str` on an enum | +| [EnumIter](#EnumIter) | Creates a new type that iterates of the variants of an enum. | +| [EnumProperty](#EnumProperty) | Add custom properties to enum variants. | +| [EnumMessage](#EnumMessage) | Add a verbose message to an enum variant. | +| [EnumDiscriminants](#EnumDiscriminants) | Generate a new type with only the discriminant names. | +| [EnumCount](#EnumCount) | Add a constant `usize` equal to the number of variantes. | - The `default` attribute can be applied to a tuple variant with a single data parameter. When a match isn't - found, the given variant will be returned and the input string will be captured in the parameter. +## EnumString - Here is an example of the code generated by deriving `EnumString`. +auto-derives `std::str::FromStr` on the enum. Each variant of the enum will match on it's own name. +This can be overridden using `serialize="DifferentName"` or `to_string="DifferentName"` +on the attribute as shown below. +Multiple deserializations can be added to the same variant. If the variant contains additional data, +they will be set to their default values upon deserialization. - ```rust - extern crate strum; - #[macro_use] extern crate strum_macros; - #[derive(EnumString)] - enum Color { - Red, +The `default` attribute can be applied to a tuple variant with a single data parameter. When a match isn't +found, the given variant will be returned and the input string will be captured in the parameter. - // The Default value will be inserted into range if we match "Green". - Green { range:usize }, +Here is an example of the code generated by deriving `EnumString`. - // We can match on multiple different patterns. - #[strum(serialize="blue",serialize="b")] - Blue(usize), +```rust +extern crate strum; +#[macro_use] extern crate strum_macros; +#[derive(EnumString)] +enum Color { + Red, - // Notice that we can disable certain variants from being found - #[strum(disabled="true")] - Yellow, - } + // The Default value will be inserted into range if we match "Green". + Green { range:usize }, - /* - //The generated code will look like: - impl std::str::FromStr for Color { - type Err = ::strum::ParseError; + // We can match on multiple different patterns. + #[strum(serialize="blue",serialize="b")] + Blue(usize), - fn from_str(s: &str) -> ::std::result::Result { - match s { - "Red" => ::std::result::Result::Ok(Color::Red), - "Green" => ::std::result::Result::Ok(Color::Green { range:Default::default() }), - "blue" | "b" => ::std::result::Result::Ok(Color::Blue(Default::default())), - _ => ::std::result::Result::Err(::strum::ParseError::VariantNotFound), - } + // Notice that we can disable certain variants from being found + #[strum(disabled="true")] + Yellow, +} + +/* +//The generated code will look like: +impl std::str::FromStr for Color { + type Err = ::strum::ParseError; + + fn from_str(s: &str) -> ::std::result::Result { + match s { + "Red" => ::std::result::Result::Ok(Color::Red), + "Green" => ::std::result::Result::Ok(Color::Green { range:Default::default() }), + "blue" | "b" => ::std::result::Result::Ok(Color::Blue(Default::default())), + _ => ::std::result::Result::Err(::strum::ParseError::VariantNotFound), } } - */ - ``` +} +*/ +``` - Note that the implementation of `FromStr` by default only matches on the name of the - variant. There is an option to match on different case conversions through the - `#[strum(serialize_all = "snake_case")]` type attribute. See the **Additional Attributes** - Section for more information on using this feature. +Note that the implementation of `FromStr` by default only matches on the name of the +variant. There is an option to match on different case conversions through the +`#[strum(serialize_all = "snake_case")]` type attribute. See the **Additional Attributes** +Section for more information on using this feature. -2. `Display` / `ToString`: prints out the given enum. This enables you to perform round trip - style conversions from enum into string and back again for unit style variants. `ToString` and - `Display` choose which serialization to used based on the following criteria: +## Display - 1. If there is a `to_string` property, this value will be used. There can only be one per variant. - 2. Of the various `serialize` properties, the value with the longest length is chosen. If that - behavior isn't desired, you should use `to_string`. - 3. The name of the variant will be used if there are no `serialize` or `to_string` attributes. +Print out the given enum. This enables you to perform round trip style conversions +from enum into string and back again for unit style variants. +`Display` choose which serialization to used based on the following criteria: - **`ToString` exists for legacy reasons. You should prefer using `Display`. All types that implement `std::fmt::Display` have a default implementation of `ToString`.** +1. If there is a `to_string` property, this value will be used. There can only be one per variant. +2. Of the various `serialize` properties, the value with the longest length is chosen. If that + behavior isn't desired, you should use `to_string`. +3. The name of the variant will be used if there are no `serialize` or `to_string` attributes. - ```rust - // You need to bring the type into scope to use it!!! - use std::string::ToString; +```rust +// You need to bring the type into scope to use it!!! +use std::string::ToString; - #[derive(ToString,Debug)] - enum Color { - #[strum(serialize="redred")] - Red, - Green { range:usize }, - Blue(usize), - Yellow, +#[derive(Display, Debug)] +enum Color { + #[strum(serialize="redred")] + Red, + Green { range:usize }, + Blue(usize), + Yellow, +} + +// It's simple to iterate over the variants of an enum. +fn debug_colors() { + let red = Color::Red; + assert_eq!(String::from("redred"), red.to_string()); +} + +fn main() { + debug_colors(); +} +``` + +## AsRefStr + +Implements `AsRef` on your enum using the same rules as +`ToString` for determining what string is returned. The difference is that `as_ref()` returns +a `&str` instead of a `String` so you don't allocate any additional memory with each call. + +## IntoStaticStr + +Implements `From` and `From<&'a YourEnum>` for `&'static str`. This is +useful for turning an enum variant into a static string. +The Rust `std` provides a blanket impl of the reverse direction - i.e. `impl Into<&'static str> for YourEnum`. + +```rust +extern crate strum; +#[macro_use] extern crate strum_macros; + +#[derive(IntoStaticStr)] +enum State<'a> { + Initial(&'a str), + Finished +} + +fn print_state<'a>(s:&'a str) { + let state = State::Initial(s); + // The following won't work because the lifetime is incorrect so we can use.as_static() instead. + // let wrong: &'static str = state.as_ref(); + let right: &'static str = state.into(); + println!("{}", right); +} + +fn main() { + print_state(&"hello world".to_string()) +} +``` + +## EnumIter + +Iterate over the variants of an Enum. Any additional data on your variants will be set to `Default::default()`. +The macro implements `strum::IntoEnumIter` on your enum and creates a new type called `YourEnumIter` that is the iterator object. +You cannot derive `EnumIter` on any type with a lifetime bound (`<'a>`) because the iterator would surely +create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html). + +```rust +// You need to bring the type into scope to use it!!! +use strum::IntoEnumIterator; + +#[derive(EnumIter,Debug)] +enum Color { + Red, + Green { range:usize }, + Blue(usize), + Yellow, +} + +// It's simple to iterate over the variants of an enum. +fn debug_colors() { + for color in Color::iter() { + println!("My favorite color is {:?}", color); } +} - // It's simple to iterate over the variants of an enum. - fn debug_colors() { - let red = Color::Red; - assert_eq!(String::from("redred"), red.to_string()); - } +fn main() { + debug_colors(); +} +``` - fn main() { - debug_colors(); - } - ``` +## EnumMessage -3. `AsRefStr`: this derive implements `AsRef` on your enum using the same rules as - `ToString` for determining what string is returned. The difference is that `as_ref()` returns - a `&str` instead of a `String` so you don't allocate any additional memory with each call. +Encode strings into the enum itself. This macro implements the `strum::EnumMessage` trait. +`EnumMessage` looks for `#[strum(message="...")]` attributes on your variants. +You can also provided a `detailed_message="..."` attribute to create a seperate more detailed message than the first. -4. `IntoStaticStr`: this trait implements `From` and `From<&'a YourEnum>` for `&'static str`. This is - useful for turning an enum variant into a static string. The Rust `std` provides a blanket impl of the - reverse direction - i.e. `impl Into<&'static str> for YourEnum`. +The generated code will look something like: - ```rust - extern crate strum; - #[macro_use] extern crate strum_macros; +```rust +// You need to bring the type into scope to use it!!! +use strum::EnumMessage; - #[derive(IntoStaticStr)] - enum State<'a> { - Initial(&'a str), - Finished - } +#[derive(EnumMessage,Debug)] +enum Color { + #[strum(message="Red",detailed_message="This is very red")] + Red, + #[strum(message="Simply Green")] + Green { range:usize }, + #[strum(serialize="b",serialize="blue")] + Blue(usize), +} - fn print_state<'a>(s:&'a str) { - let state = State::Initial(s); - // The following won't work because the lifetime is incorrect so we can use.as_static() instead. - // let wrong: &'static str = state.as_ref(); - let right: &'static str = state.into(); - println!("{}", right); - } - - fn main() { - print_state(&"hello world".to_string()) - } - ``` - -4. `AsStaticStr`: **Deprecated since version 0.13.0. Prefer IntoStaticStr instead.** - This is similar to `AsRefStr`, but returns a `'static` reference to a string which is helpful - in some scenarios. This macro implements `strum::AsStaticRef` which adds a method `.to_static()` that - returns a `&'static str`. - - ```rust - extern crate strum; - #[macro_use] extern crate strum_macros; - - use strum::AsStaticRef; - - #[derive(AsStaticStr)] - enum State<'a> { - Initial(&'a str), - Finished - } - - fn print_state<'a>(s:&'a str) { - let right: &'static str = State::Initial(s).as_static(); - println!("{}", right); - } - ``` - -4. `EnumIter`: iterate over the variants of an Enum. Any additional data on your variants will be - set to `Default::default()`. The macro implements `strum::IntoEnumIter` on your enum and - creates a new type called `YourEnumIter` that is the iterator object. You cannot derive - `EnumIter` on any type with a lifetime bound (`<'a>`) because the iterator would surely - create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html). - - ```rust - // You need to bring the type into scope to use it!!! - use strum::IntoEnumIterator; - - #[derive(EnumIter,Debug)] - enum Color { - Red, - Green { range:usize }, - Blue(usize), - Yellow, - } - - // It's simple to iterate over the variants of an enum. - fn debug_colors() { - for color in Color::iter() { - println!("My favorite color is {:?}", color); +/* +// Generated code +impl ::strum::EnumMessage for Color { + fn get_message(&self) -> ::std::option::Option<&str> { + match self { + &Color::Red => ::std::option::Option::Some("Red"), + &Color::Green {..} => ::std::option::Option::Some("Simply Green"), + _ => None } } - fn main() { - debug_colors(); - } - ``` - -5. `EnumMessage`: encode strings into the enum itself. This macro implements - the `strum::EnumMessage` trait. `EnumMessage` looks for - `#[strum(message="...")]` attributes on your variants. - You can also provided a `detailed_message="..."` attribute to create a - seperate more detailed message than the first. - - The generated code will look something like: - - ```rust - // You need to bring the type into scope to use it!!! - use strum::EnumMessage; - - #[derive(EnumMessage,Debug)] - enum Color { - #[strum(message="Red",detailed_message="This is very red")] - Red, - #[strum(message="Simply Green")] - Green { range:usize }, - #[strum(serialize="b",serialize="blue")] - Blue(usize), - } - - /* - // Generated code - impl ::strum::EnumMessage for Color { - fn get_message(&self) -> ::std::option::Option<&str> { - match self { - &Color::Red => ::std::option::Option::Some("Red"), - &Color::Green {..} => ::std::option::Option::Some("Simply Green"), - _ => None - } - } - - fn get_detailed_message(&self) -> ::std::option::Option<&str> { - match self { - &Color::Red => ::std::option::Option::Some("This is very red"), - &Color::Green {..}=> ::std::option::Option::Some("Simply Green"), - _ => None - } - } - - fn get_serializations(&self) -> &[&str] { - match self { - &Color::Red => { - static ARR: [&'static str; 1] = ["Red"]; - &ARR - }, - &Color::Green {..}=> { - static ARR: [&'static str; 1] = ["Green"]; - &ARR - }, - &Color::Blue (..) => { - static ARR: [&'static str; 2] = ["b", "blue"]; - &ARR - }, - } + fn get_detailed_message(&self) -> ::std::option::Option<&str> { + match self { + &Color::Red => ::std::option::Option::Some("This is very red"), + &Color::Green {..}=> ::std::option::Option::Some("Simply Green"), + _ => None } } - */ - ``` - -6. `EnumProperty`: Enables the encoding of arbitary constants into enum variants. This method - currently only supports adding additional string values. Other types of literals are still - experimental in the rustc compiler. The generated code works by nesting match statements. - The first match statement matches on the type of the enum, and the inner match statement - matches on the name of the property requested. This design works well for enums with a small - number of variants and properties, but scales linearly with the number of variants so may not - be the best choice in all situations. - - Here's an example: - - ```rust - # extern crate strum; - # #[macro_use] extern crate strum_macros; - # use std::fmt::Debug; - // You need to bring the type into scope to use it!!! - use strum::EnumProperty; - - #[derive(EnumProperty,Debug)] - enum Color { - #[strum(props(Red="255",Blue="255",Green="255"))] - White, - #[strum(props(Red="0",Blue="0",Green="0"))] - Black, - #[strum(props(Red="0",Blue="255",Green="0"))] - Blue, - #[strum(props(Red="255",Blue="0",Green="0"))] - Red, - #[strum(props(Red="0",Blue="0",Green="255"))] - Green, - } - - fn main() { - let my_color = Color::Red; - let display = format!("My color is {:?}. It's RGB is {},{},{}", my_color - , my_color.get_str("Red").unwrap() - , my_color.get_str("Green").unwrap() - , my_color.get_str("Blue").unwrap()); - } - ``` - -7. `EnumDiscriminants`: Given an enum named `MyEnum`, generates another enum called - `MyEnumDiscriminants` with the same variants, without any data fields. This is useful when you - wish to determine the variant of an enum from a String, but the variants contain any - non-`Default` fields. By default, the generated enum has the following derives: - `Clone, Copy, Debug, PartialEq, Eq`. You can add additional derives using the - `#[strum_discriminants(derive(AdditionalDerive))]` attribute. - - Here's an example: - - ```rust - extern crate strum; - #[macro_use] extern crate strum_macros; - - // Bring trait into scope - use std::str::FromStr; - - #[derive(Debug)] - struct NonDefault; - - #[allow(dead_code)] - #[derive(Debug, EnumDiscriminants)] - #[strum_discriminants(derive(EnumString))] - enum MyEnum { - Variant0(NonDefault), - Variant1 { a: NonDefault }, + fn get_serializations(&self) -> &[&str] { + match self { + &Color::Red => { + static ARR: [&'static str; 1] = ["Red"]; + &ARR + }, + &Color::Green {..}=> { + static ARR: [&'static str; 1] = ["Green"]; + &ARR + }, + &Color::Blue (..) => { + static ARR: [&'static str; 2] = ["b", "blue"]; + &ARR + }, + } } +} +*/ +``` - fn main() { - assert_eq!( - MyEnumDiscriminants::Variant0, - MyEnumDiscriminants::from_str("Variant0").unwrap() - ); - } - ``` +## EnumProperty - You can also rename the generated enum using the `#[strum_discriminants(name(OtherName))]` - attribute: +Enables the encoding of arbitary constants into enum variants. This method +currently only supports adding additional string values. Other types of literals are still +experimental in the rustc compiler. The generated code works by nesting match statements. +The first match statement matches on the type of the enum, and the inner match statement +matches on the name of the property requested. This design works well for enums with a small +number of variants and properties, but scales linearly with the number of variants so may not +be the best choice in all situations. - ```rust - extern crate strum; - #[macro_use] extern crate strum_macros; - // You need to bring the type into scope to use it!!! - use strum::IntoEnumIterator; +Here's an example: - #[allow(dead_code)] - #[derive(Debug, EnumDiscriminants)] - #[strum_discriminants(derive(EnumIter))] - #[strum_discriminants(name(MyVariants))] - enum MyEnum { - Variant0(bool), - Variant1 { a: bool }, - } +```rust +# extern crate strum; +# #[macro_use] extern crate strum_macros; +# use std::fmt::Debug; +// You need to bring the type into scope to use it!!! +use strum::EnumProperty; - fn main() { - assert_eq!( - vec![MyVariants::Variant0, MyVariants::Variant1], - MyVariants::iter().collect::>() - ); - } - ``` +#[derive(EnumProperty,Debug)] +enum Color { + #[strum(props(Red="255",Blue="255",Green="255"))] + White, + #[strum(props(Red="0",Blue="0",Green="0"))] + Black, + #[strum(props(Red="0",Blue="255",Green="0"))] + Blue, + #[strum(props(Red="255",Blue="0",Green="0"))] + Red, + #[strum(props(Red="0",Blue="0",Green="255"))] + Green, +} - The derived enum also has the following trait implementations: +fn main() { + let my_color = Color::Red; + let display = format!("My color is {:?}. It's RGB is {},{},{}", my_color + , my_color.get_str("Red").unwrap() + , my_color.get_str("Green").unwrap() + , my_color.get_str("Blue").unwrap()); +} +``` - * `impl From for MyEnumDiscriminants` - * `impl<'_enum> From<&'_enum MyEnum> for MyEnumDiscriminants` +## EnumDiscriminants - These allow you to get the *Discriminants* enum variant from the original enum: +Given an enum named `MyEnum`, generates another enum called `MyEnumDiscriminants` with the same variants, without any data fields. +This is useful when you wish to determine the variant of an enum from a String, but the variants contain any +non-`Default` fields. By default, the generated enum has the following derives: +`Clone, Copy, Debug, PartialEq, Eq`. You can add additional derives using the +`#[strum_discriminants(derive(AdditionalDerive))]` attribute. - ```rust - extern crate strum; - #[macro_use] extern crate strum_macros; +Here's an example: - #[derive(Debug, EnumDiscriminants)] - #[strum_discriminants(name(MyVariants))] - enum MyEnum { - Variant0(bool), - Variant1 { a: bool }, - } +```rust +extern crate strum; +#[macro_use] extern crate strum_macros; - fn main() { - assert_eq!(MyVariants::Variant0, MyEnum::Variant0(true).into()); - } - ``` +// Bring trait into scope +use std::str::FromStr; -8. `EnumCount`: for a given enum generates implementation of `strum::EnumCount`, - which returns number of variants via `strum::EnumCount::count` method, - also for given `enum MyEnum` generates `const MYENUM_COUNT: usize` - which gives the same value as `strum::EnumCount` (which is usefull for array sizes, etc.). +#[derive(Debug)] +struct NonDefault; - ```rust - extern crate strum; - #[macro_use] - extern crate strum_macros; +#[allow(dead_code)] +#[derive(Debug, EnumDiscriminants)] +#[strum_discriminants(derive(EnumString))] +enum MyEnum { + Variant0(NonDefault), + Variant1 { a: NonDefault }, +} - use strum::{IntoEnumIterator, EnumCount}; +fn main() { + assert_eq!( + MyEnumDiscriminants::Variant0, + MyEnumDiscriminants::from_str("Variant0").unwrap() + ); +} +``` - #[derive(Debug, EnumCount, EnumIter)] - enum Week { - Sunday, - Monday, - Tuesday, - Wednesday, - Thursday, - Friday, - Saturday, - } +You can also rename the generated enum using the `#[strum_discriminants(name(OtherName))]` +attribute: - fn main() { - assert_eq!(7, Week::count()); - assert_eq!(Week::count(), WEEK_COUNT); - assert_eq!(Week::iter().count(), WEEK_COUNT); - } - ``` +```rust +extern crate strum; +#[macro_use] extern crate strum_macros; +// You need to bring the type into scope to use it!!! +use strum::IntoEnumIterator; + +#[allow(dead_code)] +#[derive(Debug, EnumDiscriminants)] +#[strum_discriminants(derive(EnumIter))] +#[strum_discriminants(name(MyVariants))] +enum MyEnum { + Variant0(bool), + Variant1 { a: bool }, +} + +fn main() { + assert_eq!( + vec![MyVariants::Variant0, MyVariants::Variant1], + MyVariants::iter().collect::>() + ); +} +``` + +The derived enum also has the following trait implementations: + +* `impl From for MyEnumDiscriminants` +* `impl<'_enum> From<&'_enum MyEnum> for MyEnumDiscriminants` + +These allow you to get the *Discriminants* enum variant from the original enum: + +```rust +extern crate strum; +#[macro_use] extern crate strum_macros; + +#[derive(Debug, EnumDiscriminants)] +#[strum_discriminants(name(MyVariants))] +enum MyEnum { + Variant0(bool), + Variant1 { a: bool }, +} + +fn main() { + assert_eq!(MyVariants::Variant0, MyEnum::Variant0(true).into()); +} +``` + +## EnumCount + +For a given enum generates implementation of `strum::EnumCount`, +which returns number of variants via `strum::EnumCount::count` method, +also for given `enum MyEnum` generates `const MYENUM_COUNT: usize` +which gives the same value as `strum::EnumCount` (which is usefull for array sizes, etc.). + +```rust +extern crate strum; +#[macro_use] +extern crate strum_macros; + +use strum::{IntoEnumIterator, EnumCount}; + +#[derive(Debug, EnumCount, EnumIter)] +enum Week { + Sunday, + Monday, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday, +} + +fn main() { + assert_eq!(7, Week::count()); + assert_eq!(Week::count(), WEEK_COUNT); + assert_eq!(Week::iter().count(), WEEK_COUNT); +} +``` + +## ToString + +**Deprecated** Prefer using [`Display`](#Display). All types that implement `std::fmt::Display` have a default implementation of `ToString`.** + +## AsStaticStr + +**Deprecated since version 0.13.0.** Prefer [IntoStaticStr](#IntoStaticStr) instead. # Additional Attributes diff --git a/strum/Cargo.toml b/strum/Cargo.toml index 8d68e37..59ba2e8 100644 --- a/strum/Cargo.toml +++ b/strum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strum" -version = "0.14.0" +version = "0.15.0" authors = ["Peter Glotfelty "] license = "MIT" @@ -13,7 +13,7 @@ homepage = "https://github.com/Peternator7/strum" readme = "../README.md" [dev-dependencies] -strum_macros = { path = "../strum_macros", version = "0.14.0" } +strum_macros = { path = "../strum_macros", version = "0.15.0" } [badges] travis-ci = { repository = "Peternator7/strum" } \ No newline at end of file diff --git a/strum/src/lib.rs b/strum/src/lib.rs index e4c4ad9..f566afa 100644 --- a/strum/src/lib.rs +++ b/strum/src/lib.rs @@ -7,6 +7,8 @@ //! Strum is a set of macros and traits for working with //! enums and strings easier in Rust. //! +//! The full version of the README can be found on [Github](https://github.com/Peternator7/strum). +//! //! # Including Strum in Your Project //! //! Import strum and strum_macros into your project by adding the following lines to your @@ -14,8 +16,8 @@ //! //! ```toml //! [dependencies] -//! strum = "0.13.0" -//! strum_macros = "0.13.0" +//! strum = "0.15.0" +//! strum_macros = "0.15.0" //! ``` //! //! And add these lines to the root of your project, either lib.rs or main.rs. @@ -32,517 +34,17 @@ //! //! Strum has implemented the following macros: //! -//! 1. `EnumString`: auto-derives `std::str::FromStr` on the enum. Each variant of the enum will match on it's -//! own name. This can be overridden using `serialize="DifferentName"` or `to_string="DifferentName"`on the attribute as shown below. -//! Multiple deserializations can be added to the same variant. If the variant contains additional data, -//! they will be set to their default values upon deserialization. -//! -//! The `default` attribute can be applied to a tuple variant with a single data parameter. When a match isn't -//! found, the given variant will be returned and the input string will be captured in the parameter. -//! -//! Here is an example of the code generated by deriving `EnumString`. -//! -//! ``` -//! # extern crate strum; -//! # #[macro_use] extern crate strum_macros; -//! #[derive(EnumString)] -//! enum Color { -//! Red, -//! -//! // The Default value will be inserted into range if we match "Green". -//! Green { range:usize }, -//! -//! // We can match on multiple different patterns. -//! #[strum(serialize="blue",serialize="b")] -//! Blue(usize), -//! -//! // Notice that we can disable certain variants from being found -//! #[strum(disabled="true")] -//! Yellow, -//! } -//! -//! /* -//! //The generated code will look like: -//! impl ::std::str::FromStr for Color { -//! type Err = ::strum::ParseError; -//! -//! fn from_str(s: &str) -> ::std::result::Result { -//! match s { -//! "Red" => ::std::result::Result::Ok(Color::Red), -//! "Green" => ::std::result::Result::Ok(Color::Green { range:Default::default() }), -//! "blue" | "b" => ::std::result::Result::Ok(Color::Blue(Default::default())), -//! _ => ::std::result::Result::Err(strum::ParseError::VariantNotFound), -//! } -//! } -//! } -//! */ -//! # fn main() {} -//! ``` -//! -//! Note that the implementation of `FromStr` by default only matches on the name of the -//! variant. There is an option to match on different case conversions through the -//! `#[strum(serialize_all = "snake_case")]` type attribute. See the **Additional Attributes** -//! Section for more information on using this feature. -//! -//! 2. `Display`, `ToString`: both derives print out the given enum variant. This enables you to perform round trip -//! style conversions from enum into string and back again for unit style variants. `ToString` and `Display` -//! choose which serialization to used based on the following criteria: -//! -//! 1. If there is a `to_string` property, this value will be used. There can only be one per variant. -//! 2. Of the various `serialize` properties, the value with the longest length is chosen. If that -//! behavior isn't desired, you should use `to_string`. -//! 3. The name of the variant will be used if there are no `serialize` or `to_string` attributes. -//! -//! **`Display` should be preferred to `ToString`. All types that implement `::std::fmt::Display` have a default `ToString` implementation.** -//! -//! ```rust -//! # extern crate strum; -//! # #[macro_use] extern crate strum_macros; -//! // You need to bring the type into scope to use it!!! -//! use std::string::ToString; -//! -//! #[derive(Display, Debug)] -//! enum Color { -//! #[strum(serialize="redred")] -//! Red, -//! Green { range:usize }, -//! Blue(usize), -//! Yellow, -//! } -//! -//! // It's simple to iterate over the variants of an enum. -//! fn debug_colors() { -//! let red = Color::Red; -//! assert_eq!(String::from("redred"), red.to_string()); -//! } -//! -//! fn main () { debug_colors(); } -//! ``` -//! -//! 3. `AsRefStr`: this derive implements `AsRef` on your enum using the same rules as -//! `ToString` for determining what string is returned. The difference is that `as_ref()` returns -//! a borrowed `str` instead of a `String` so you can save an allocation. -//! -//! 4. `IntoStaticStr`: this trait implements `From` and `From<&'a YourEnum>` for `&'static str`. This is -//! useful for turning an enum variant into a static string. The Rust `std` provides a blanket impl of the -//! reverse direction - i.e. `impl Into<&'static str> for YourEnum`. -//! -//! ```rust -//! extern crate strum; -//! #[macro_use] extern crate strum_macros; -//! -//! #[derive(IntoStaticStr)] -//! enum State<'a> { -//! Initial(&'a str), -//! Finished -//! } -//! -//! fn print_state<'a>(s:&'a str) { -//! let state = State::Initial(s); -//! // The following won't work because the lifetime is incorrect so we can use.as_static() instead. -//! // let wrong: &'static str = state.as_ref(); -//! let right: &'static str = state.into(); -//! println!("{}", right); -//! } -//! -//! fn main() { -//! print_state(&"hello world".to_string()) -//! } -//! ``` -//! -//! 4. `EnumIter`: iterate over the variants of an Enum. Any additional data on your variants will be -//! set to `Default::default()`. The macro implements `strum::IntoEnumIter` on your enum and -//! creates a new type called `YourEnumIter` that implements both `Iterator` and `ExactSizeIterator`. -//! You cannot derive `EnumIter` on any type with a lifetime bound (`<'a>`) because the iterator would surely -//! create [unbounded lifetimes] (https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html). -//! -//! ```rust -//! # extern crate strum; -//! # #[macro_use] extern crate strum_macros; -//! # use std::fmt::Debug; -//! // You need to bring the type into scope to use it!!! -//! use strum::IntoEnumIterator; -//! -//! #[derive(EnumIter,Debug)] -//! enum Color { -//! Red, -//! Green { range:usize }, -//! Blue(usize), -//! Yellow, -//! } -//! -//! // It's simple to iterate over the variants of an enum. -//! fn debug_colors() { -//! for color in Color::iter() { -//! println!("My favorite color is {:?}", color); -//! } -//! } -//! -//! fn main() { -//! debug_colors(); -//! } -//! ``` -//! -//! 5. `EnumMessage`: encode strings into the enum itself. This macro implements -//! the `strum::EnumMessage` trait. `EnumMessage` looks for -//! `#[strum(message="...")]` attributes on your variants. -//! You can also provided a `detailed_message="..."` attribute to create a -//! seperate more detailed message than the first. -//! -//! The generated code will look something like: -//! -//! ```rust -//! # extern crate strum; -//! # #[macro_use] extern crate strum_macros; -//! // You need to bring the type into scope to use it!!! -//! use strum::EnumMessage; -//! -//! #[derive(EnumMessage,Debug)] -//! enum Color { -//! #[strum(message="Red",detailed_message="This is very red")] -//! Red, -//! #[strum(message="Simply Green")] -//! Green { range:usize }, -//! #[strum(serialize="b",serialize="blue")] -//! Blue(usize), -//! } -//! -//! /* -//! // Generated code -//! impl ::strum::EnumMessage for Color { -//! fn get_message(&self) -> ::std::option::Option<&str> { -//! match self { -//! &Color::Red => ::std::option::Option::Some("Red"), -//! &Color::Green {..} => ::std::option::Option::Some("Simply Green"), -//! _ => None -//! } -//! } -//! -//! fn get_detailed_message(&self) -> ::std::option::Option<&str> { -//! match self { -//! &Color::Red => ::std::option::Option::Some("This is very red"), -//! &Color::Green {..}=> ::std::option::Option::Some("Simply Green"), -//! _ => None -//! } -//! } -//! -//! fn get_serializations(&self) -> &[&str] { -//! match self { -//! &Color::Red => { -//! static ARR: [&'static str; 1] = ["Red"]; -//! &ARR -//! }, -//! &Color::Green {..}=> { -//! static ARR: [&'static str; 1] = ["Green"]; -//! &ARR -//! }, -//! &Color::Blue (..) => { -//! static ARR: [&'static str; 2] = ["b", "blue"]; -//! &ARR -//! }, -//! } -//! } -//! } -//! */ -//! # fn main() {} -//! ``` -//! -//! 6. `EnumProperty`: Enables the encoding of arbitary constants into enum variants. This method -//! currently only supports adding additional string values. Other types of literals are still -//! experimental in the rustc compiler. The generated code works by nesting match statements. -//! The first match statement matches on the type of the enum, and the inner match statement -//! matches on the name of the property requested. This design works well for enums with a small -//! number of variants and properties, but scales linearly with the number of variants so may not -//! be the best choice in all situations. -//! -//! Here's an example: -//! -//! ```rust -//! # extern crate strum; -//! # #[macro_use] extern crate strum_macros; -//! # use std::fmt::Debug; -//! // You need to bring the type into scope to use it!!! -//! use strum::EnumProperty; -//! -//! #[derive(EnumProperty,Debug)] -//! enum Color { -//! #[strum(props(Red="255",Blue="255",Green="255"))] -//! White, -//! #[strum(props(Red="0",Blue="0",Green="0"))] -//! Black, -//! #[strum(props(Red="0",Blue="255",Green="0"))] -//! Blue, -//! #[strum(props(Red="255",Blue="0",Green="0"))] -//! Red, -//! #[strum(props(Red="0",Blue="0",Green="255"))] -//! Green, -//! } -//! -//! fn main() { -//! let my_color = Color::Red; -//! let display = format!("My color is {:?}. It's RGB is {},{},{}", my_color -//! , my_color.get_str("Red").unwrap() -//! , my_color.get_str("Green").unwrap() -//! , my_color.get_str("Blue").unwrap()); -//! # let expected = String::from("My color is Red. It's RGB is 255,0,0"); -//! # assert_eq!(expected, display); -//! } -//! ``` -//! -//! 7. `EnumDiscriminants`: Given an enum named `MyEnum`, generates another enum called -//! `MyEnumDiscriminants` with the same variants, without any data fields. This is useful when you -//! wish to determine the variant of an enum from a String, but the variants contain any -//! non-`Default` fields. By default, the generated enum has the following derives: -//! `Clone, Copy, Debug, PartialEq, Eq`. You can add additional derives using the -//! `#[strum_discriminants(derive(AdditionalDerive))]` attribute. -//! -//! Here's an example: -//! -//! ```rust -//! # extern crate strum; -//! # #[macro_use] extern crate strum_macros; -//! -//! // Bring trait into scope -//! use std::str::FromStr; -//! -//! #[derive(Debug)] -//! struct NonDefault; -//! -//! #[allow(dead_code)] -//! #[derive(Debug, EnumDiscriminants)] -//! #[strum_discriminants(derive(EnumString))] -//! enum MyEnum { -//! Variant0(NonDefault), -//! Variant1 { a: NonDefault }, -//! } -//! -//! fn main() { -//! assert_eq!( -//! MyEnumDiscriminants::Variant0, -//! MyEnumDiscriminants::from_str("Variant0").unwrap() -//! ); -//! } -//! ``` -//! -//! You can also rename the generated enum using the `#[strum_discriminants(name(OtherName))]` -//! attribute: -//! -//! ```rust -//! # extern crate strum; -//! # #[macro_use] extern crate strum_macros; -//! // You need to bring the type into scope to use it!!! -//! use strum::IntoEnumIterator; -//! -//! #[allow(dead_code)] -//! #[derive(Debug, EnumDiscriminants)] -//! #[strum_discriminants(name(MyVariants), derive(EnumIter))] -//! enum MyEnum { -//! Variant0(bool), -//! Variant1 { a: bool }, -//! } -//! -//! fn main() { -//! assert_eq!( -//! vec![MyVariants::Variant0, MyVariants::Variant1], -//! MyVariants::iter().collect::>() -//! ); -//! } -//! ``` -//! -//! The derived enum also has the following trait implementations: -//! -//! * `impl From for MyEnumDiscriminants` -//! * `impl<'_enum> From<&'_enum MyEnum> for MyEnumDiscriminants` -//! -//! These allow you to get the *Discriminants* enum variant from the original enum: -//! -//! ```rust -//! extern crate strum; -//! #[macro_use] extern crate strum_macros; -//! -//! #[derive(Debug, EnumDiscriminants)] -//! #[strum_discriminants(name(MyVariants))] -//! enum MyEnum { -//! Variant0(bool), -//! Variant1 { a: bool }, -//! } -//! -//! fn main() { -//! assert_eq!(MyVariants::Variant0, MyEnum::Variant0(true).into()); -//! } -//! ``` -//! -//! 8. `EnumCount`: for a given enum generates implementation of `strum::EnumCount`, -//! which returns number of variants via `strum::EnumCount::count` method, -//! also for given `enum MyEnum` generates `const MYENUM_COUNT: usize` -//! which gives the same value as `strum::EnumCount` (which is usefull for array sizes, etc.). -//! -//! ```rust -//! extern crate strum; -//! #[macro_use] extern crate strum_macros; -//! -//! use strum::{IntoEnumIterator, EnumCount}; -//! -//! #[derive(Debug, EnumCount, EnumIter)] -//! enum Week { -//! Sunday, -//! Monday, -//! Tuesday, -//! Wednesday, -//! Thursday, -//! Friday, -//! Saturday, -//! } -//! -//! fn main() { -//! assert_eq!(7, Week::count()); -//! assert_eq!(Week::count(), WEEK_COUNT); -//! assert_eq!(Week::iter().count(), WEEK_COUNT); -//! } -//! ``` -//! -//! # Additional Attributes -//! -//! Strum supports several custom attributes to modify the generated code. At the enum level, the -//! `#[strum(serialize_all = "snake_case")]` attribute can be used to change the case used when -//! serializing to and deserializing from strings: -//! -//! ```rust -//! extern crate strum; -//! #[macro_use] -//! extern crate strum_macros; -//! -//! #[derive(Debug, Eq, PartialEq, ToString)] -//! #[strum(serialize_all = "snake_case")] -//! enum Brightness { -//! DarkBlack, -//! Dim { -//! glow: usize, -//! }, -//! #[strum(serialize = "bright")] -//! BrightWhite, -//! } -//! -//! fn main() { -//! assert_eq!( -//! String::from("dark_black"), -//! Brightness::DarkBlack.to_string().as_ref() -//! ); -//! assert_eq!( -//! String::from("dim"), -//! Brightness::Dim { glow: 0 }.to_string().as_ref() -//! ); -//! assert_eq!( -//! String::from("bright"), -//! Brightness::BrightWhite.to_string().as_ref() -//! ); -//! } -//! ``` -//! -//! Custom attributes are applied to a variant by adding `#[strum(parameter="value")]` to the variant. -//! -//! - `serialize="..."`: Changes the text that `FromStr()` looks for when parsing a string. This attribute can -//! be applied multiple times to an element and the enum variant will be parsed if any of them match. -//! -//! - `default="true"`: Applied to a single variant of an enum. The variant must be a Tuple-like -//! variant with a single piece of data that can be create from a `&str` i.e. `T: From<&str>`. -//! The generated code will now return the variant with the input string captured as shown below -//! instead of failing. -//! -//! ```ignore -//! // Replaces this: -//! _ => Err(strum::ParseError::VariantNotFound) -//! // With this in generated code: -//! default => Ok(Variant(default.into())) -//! ``` -//! The plugin will fail if the data doesn't implement From<&str>. You can only have one `default` -//! on your enum. -//! -//! - `disabled="true"`: removes variant from generated code. -//! -//! - `message=".."`: Adds a message to enum variant. This is used in conjunction with the `EnumMessage` -//! trait to associate a message with a variant. If `detailed_message` is not provided, -//! then `message` will also be returned when get_detailed_message() is called. -//! -//! - `detailed_message=".."`: Adds a more detailed message to a variant. If this value is omitted, then -//! `message` will be used in it's place. -//! -//! - `props(key="value")`: Used by EnumProperty to add additional information to an enum variant. Multiple -//! properties can be added in a single nested block. -//! -//! # Examples -//! -//! Using `EnumMessage` for quickly implementing `Error` -//! -//! ```rust -//! extern crate strum; -//! #[macro_use] -//! extern crate strum_macros; -//! # use std::error::Error; -//! # use std::fmt::*; -//! use strum::EnumMessage; -//! -//! #[derive(Debug, EnumMessage)] -//! enum ServerError { -//! #[strum(message="A network error occured")] -//! #[strum(detailed_message="Try checking your connection.")] -//! NetworkError, -//! #[strum(message="User input error.")] -//! #[strum(detailed_message="There was an error parsing user input. Please try again.")] -//! InvalidUserInputError, -//! } -//! -//! impl Display for ServerError { -//! fn fmt(&self, f: &mut Formatter) -> Result { -//! write!(f, "{}", self.get_message().unwrap()) -//! } -//! } -//! -//! impl Error for ServerError { -//! fn description(&self) -> &str { -//! self.get_detailed_message().unwrap() -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! Using `EnumString` to tokenize a series of inputs: -//! -//! ```rust -//! extern crate strum; -//! #[macro_use] -//! extern crate strum_macros; -//! use std::str::FromStr; -//! -//! #[derive(Eq, PartialEq, Debug, EnumString)] -//! enum Tokens { -//! #[strum(serialize="fn")] -//! Function, -//! #[strum(serialize="(")] -//! OpenParen, -//! #[strum(serialize=")")] -//! CloseParen, -//! #[strum(default="true")] -//! Ident(String) -//! } -//! -//! fn main() { -//! let toks = ["fn", "hello_world", "(", ")"].iter() -//! .map(|tok| Tokens::from_str(tok).unwrap()) -//! .collect::>(); -//! -//! assert_eq!(toks, vec![Tokens::Function, -//! Tokens::Ident(String::from("hello_world")), -//! Tokens::OpenParen, -//! Tokens::CloseParen]); -//! } -//! ``` -//! -//! # Debugging -//! -//! To see the generated code, set the STRUM_DEBUG environment variable before compiling your code. -//! `STRUM_DEBUG=1` will dump all of the generated code for every type. `STRUM_DEBUG=YourType` will -//! only dump the code generated on a type named YourType. +//! | Macro | Description | +//! | --- | ----------- | +//! | [EnumString](https://github.com/Peternator7/strum#EnumString) | Converts strings to enum variants based on their name | +//! | [Display](https://github.com/Peternator7/strum#Display) | Converts enum variants to strings | +//! | [AsRefStr](https://github.com/Peternator7/strum#AsRefStr) | Converts enum variants to `&'static str` | +//! | [IntoStaticStr](https://github.com/Peternator7/strum#IntoStaticStr) | Implements `From for &'static str` on an enum | +//! | [EnumIter](https://github.com/Peternator7/strum#EnumIter) | Creates a new type that iterates of the variants of an enum. | +//! | [EnumProperty](https://github.com/Peternator7/strum#EnumProperty) | Add custom properties to enum variants. | +//! | [EnumMessage](https://github.com/Peternator7/strum#EnumMessage) | Add a verbose message to an enum variant. | +//! | [EnumDiscriminants](https://github.com/Peternator7/strum#EnumDiscriminants) | Generate a new type with only the discriminant names. | +//! | [EnumCount](https://github.com/Peternator7/strum#EnumCount) | Add a constant `usize` equal to the number of variantes. | //! /// The ParseError enum is a collection of all the possible reasons diff --git a/strum_macros/Cargo.toml b/strum_macros/Cargo.toml index 6994a69..af3d40d 100644 --- a/strum_macros/Cargo.toml +++ b/strum_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strum_macros" -version = "0.14.0" +version = "0.15.0" authors = ["Peter Glotfelty "] license = "MIT" @@ -21,3 +21,16 @@ heck = "0.3" proc-macro2 = "0.4" quote = "0.6" syn = { version = "0.15", features = ["parsing", "extra-traits"] } + +[features] +verbose-enumstring-name = [] +verbose-asrefstr-name = [] +verbose-asstaticstr-name = [] +verbose-intostaticstr-name = [] +verbose-tostring-name = [] +verbose-display-name = [] +verbose-enumiter-name = [] +verbose-enummessage-name = [] +verbose-enumproperty-name = [] +verbose-enumdiscriminants-name = [] +verbose-enumcount-name = [] \ No newline at end of file diff --git a/strum_macros/src/lib.rs b/strum_macros/src/lib.rs index b428212..a9925ef 100644 --- a/strum_macros/src/lib.rs +++ b/strum_macros/src/lib.rs @@ -45,7 +45,8 @@ fn debug_print_generated(ast: &syn::DeriveInput, toks: &TokenStream) { } } -#[proc_macro_derive(EnumString, attributes(strum))] +#[cfg_attr(not(feature = "verbose-enumstring-name"), proc_macro_derive(EnumString, attributes(strum)))] +#[cfg_attr(feature = "verbose-enumstring-name", proc_macro_derive(StrumEnumString, attributes(strum)))] pub fn from_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -54,7 +55,8 @@ pub fn from_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { toks.into() } -#[proc_macro_derive(AsRefStr, attributes(strum))] +#[cfg_attr(not(feature = "verbose-asrefstr-name"), proc_macro_derive(AsRefStr, attributes(strum)))] +#[cfg_attr(feature = "verbose-asrefstr-name", proc_macro_derive(StrumAsRefStr, attributes(strum)))] pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -63,7 +65,8 @@ pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { toks.into() } -#[proc_macro_derive(AsStaticStr, attributes(strum))] +#[cfg_attr(feature = "verbose-asstaticstr-name", proc_macro_derive(StrumAsStaticStr, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-asstaticstr-name"), proc_macro_derive(AsStaticStr, attributes(strum)))] pub fn as_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -72,7 +75,8 @@ pub fn as_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream toks.into() } -#[proc_macro_derive(IntoStaticStr, attributes(strum))] +#[cfg_attr(feature = "verbose-intostaticstr-name", proc_macro_derive(StrumIntoStaticStr, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-intostaticstr-name"), proc_macro_derive(IntoStaticStr, attributes(strum)))] pub fn into_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -81,7 +85,8 @@ pub fn into_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStrea toks.into() } -#[proc_macro_derive(ToString, attributes(strum))] +#[cfg_attr(feature = "verbose-tostring-name", proc_macro_derive(StrumToString, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-tostring-name"), proc_macro_derive(ToString, attributes(strum)))] pub fn to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -90,7 +95,8 @@ pub fn to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { toks.into() } -#[proc_macro_derive(Display, attributes(strum))] +#[cfg_attr(feature = "verbose-display-name", proc_macro_derive(StrumDisplay, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-display-name"), proc_macro_derive(Display, attributes(strum)))] pub fn display(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -99,7 +105,8 @@ pub fn display(input: proc_macro::TokenStream) -> proc_macro::TokenStream { toks.into() } -#[proc_macro_derive(EnumIter, attributes(strum))] +#[cfg_attr(feature = "verbose-enumiter-name", proc_macro_derive(StrumEnumIter, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-enumiter-name"), proc_macro_derive(EnumIter, attributes(strum)))] pub fn enum_iter(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -108,7 +115,8 @@ pub fn enum_iter(input: proc_macro::TokenStream) -> proc_macro::TokenStream { toks.into() } -#[proc_macro_derive(EnumMessage, attributes(strum))] +#[cfg_attr(feature = "verbose-enummessage-name", proc_macro_derive(StrumEnumMessage, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-enummessage-name"), proc_macro_derive(EnumMessage, attributes(strum)))] pub fn enum_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -117,7 +125,8 @@ pub fn enum_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream toks.into() } -#[proc_macro_derive(EnumProperty, attributes(strum))] +#[cfg_attr(feature = "verbose-enumproperty-name", proc_macro_derive(StrumEnumProperty, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-enumproperty-name"), proc_macro_derive(EnumProperty, attributes(strum)))] pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -126,7 +135,8 @@ pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStrea toks.into() } -#[proc_macro_derive(EnumDiscriminants, attributes(strum, strum_discriminants))] +#[cfg_attr(feature = "verbose-enumdiscriminants-name", proc_macro_derive(StrumEnumDiscriminants, attributes(strum, strum_discriminants)))] +#[cfg_attr(not(feature = "verbose-enumdiscriminants-name"), proc_macro_derive(EnumDiscriminants, attributes(strum, strum_discriminants)))] pub fn enum_discriminants(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); @@ -135,7 +145,8 @@ pub fn enum_discriminants(input: proc_macro::TokenStream) -> proc_macro::TokenSt toks.into() } -#[proc_macro_derive(EnumCount, attributes(strum))] +#[cfg_attr(feature = "verbose-enumcount-name", proc_macro_derive(StrumEnumCount, attributes(strum)))] +#[cfg_attr(not(feature = "verbose-enumcount-name"), proc_macro_derive(EnumCount, attributes(strum)))] pub fn enum_count(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); let toks = enum_count::enum_count_inner(&ast); diff --git a/strum_tests/Cargo.toml b/strum_tests/Cargo.toml index 87e700f..9458b9e 100644 --- a/strum_tests/Cargo.toml +++ b/strum_tests/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "strum_tests" -version = "0.14.0" +version = "0.15.0" authors = ["Peter Glotfelty "] [dependencies] strum = { path = "../strum" } -strum_macros = { path = "../strum_macros" } \ No newline at end of file +strum_macros = { path = "../strum_macros", features = [] } \ No newline at end of file diff --git a/strum_tests_rename/Cargo.toml b/strum_tests_rename/Cargo.toml new file mode 100644 index 0000000..0c71212 --- /dev/null +++ b/strum_tests_rename/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "strum_tests_rename" +version = "0.15.0" +authors = ["Peter Glotfelty "] + +[dependencies] +strum = { path = "../strum" } + +[dependencies.strum_macros] +path = "../strum_macros" +features = [ + "verbose-enumcount-name", + "verbose-enumstring-name", + "verbose-asrefstr-name", + "verbose-asstaticstr-name", + "verbose-intostaticstr-name", + "verbose-tostring-name", + "verbose-display-name", + "verbose-enumiter-name", + "verbose-enummessage-name", + "verbose-enumproperty-name", + "verbose-enumdiscriminants-name" +] \ No newline at end of file diff --git a/strum_tests_rename/src/main.rs b/strum_tests_rename/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/strum_tests_rename/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/strum_tests_rename/tests/color.rs b/strum_tests_rename/tests/color.rs new file mode 100644 index 0000000..3984058 --- /dev/null +++ b/strum_tests_rename/tests/color.rs @@ -0,0 +1,27 @@ +extern crate strum; +#[macro_use] +extern crate strum_macros; + +#[derive(StrumEnumString, + StrumAsRefStr, + StrumAsStaticStr, + StrumIntoStaticStr, + StrumDisplay, + StrumEnumIter, + StrumEnumMessage, + StrumEnumProperty, + StrumEnumDiscriminants, + StrumEnumCount)] +pub enum Color { + Red, + Blue, + Green, +} + +// You can't have ToString and Display on the same type. +#[derive(StrumToString)] +pub enum Color2 { + Red, + Blue, + Green +} \ No newline at end of file diff --git a/travis.sh b/travis.sh index a3b02d8..ac335e7 100755 --- a/travis.sh +++ b/travis.sh @@ -8,3 +8,8 @@ cargo build --verbose cargo test --verbose cd .. +cd ./strum_tests_rename +cargo build --verbose +cargo test --verbose + +cd .. \ No newline at end of file