1
0
mirror of https://github.com/danog/strum.git synced 2024-11-30 04:28:59 +01:00

Macro renames (#46)

* Updating the README

* Did lots of updates for the documentation

* Improving formatting in a few places

* Consolidated docs to make it easier to keep up to date

* Updating workspace

* Revved version in docs
This commit is contained in:
Peter Glotfelty 2019-03-26 20:44:39 -07:00 committed by GitHub
parent 1f4a3b2534
commit 970b5cec40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 487 additions and 874 deletions

View File

@ -1,5 +1,19 @@
# 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

View File

@ -2,5 +2,7 @@
members = [
"strum",
"strum_macros",
"strum_tests",
"strum_tests"
]
exclude = [ "strum_tests_rename" ]

View File

@ -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

111
README.md
View File

@ -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,8 +55,22 @@ 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"`
| 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<MyEnum> 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. |
## 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.
@ -102,8 +121,10 @@ Strum has implemented the following macros:
`#[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
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:
1. If there is a `to_string` property, this value will be used. There can only be one per variant.
@ -111,13 +132,11 @@ Strum has implemented the following macros:
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.
**`ToString` exists for legacy reasons. You should prefer using `Display`. All types that implement `std::fmt::Display` have a default implementation of `ToString`.**
```rust
// You need to bring the type into scope to use it!!!
use std::string::ToString;
#[derive(ToString,Debug)]
#[derive(Display, Debug)]
enum Color {
#[strum(serialize="redred")]
Red,
@ -137,13 +156,17 @@ Strum has implemented the following macros:
}
```
3. `AsRefStr`: this derive implements `AsRef<str>` on your enum using the same rules as
## AsRefStr
Implements `AsRef<str>` 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.
4. `IntoStaticStr`: this trait implements `From<YourEnum>` 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`.
## IntoStaticStr
Implements `From<YourEnum>` 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;
@ -168,33 +191,11 @@ Strum has implemented the following macros:
}
```
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<str>` which adds a method `.to_static()` that
returns a `&'static str`.
## EnumIter
```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
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
@ -221,11 +222,11 @@ Strum has implemented the following macros:
}
```
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.
## 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:
@ -282,8 +283,9 @@ Strum has implemented the following macros:
*/
```
## EnumProperty
6. `EnumProperty`: Enables the encoding of arbitary constants into enum variants. This method
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
@ -323,9 +325,10 @@ Strum has implemented the following macros:
}
```
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
## 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.
@ -407,7 +410,9 @@ Strum has implemented the following macros:
}
```
8. `EnumCount`: for a given enum generates implementation of `strum::EnumCount`,
## 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.).
@ -437,6 +442,14 @@ Strum has implemented the following macros:
}
```
## 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
Strum supports several custom attributes to modify the generated code. At the enum level, the

View File

@ -1,6 +1,6 @@
[package]
name = "strum"
version = "0.14.0"
version = "0.15.0"
authors = ["Peter Glotfelty <peglotfe@microsoft.com>"]
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" }

View File

@ -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<Color, Self::Err> {
//! 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<str>` 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<YourEnum>` 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::<Vec<_>>()
//! );
//! }
//! ```
//!
//! The derived enum also has the following trait implementations:
//!
//! * `impl From<MyEnum> 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::<Vec<_>>();
//!
//! 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<MyEnum> 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

View File

@ -1,6 +1,6 @@
[package]
name = "strum_macros"
version = "0.14.0"
version = "0.15.0"
authors = ["Peter Glotfelty <peglotfe@microsoft.com>"]
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 = []

View File

@ -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);

View File

@ -1,8 +1,8 @@
[package]
name = "strum_tests"
version = "0.14.0"
version = "0.15.0"
authors = ["Peter Glotfelty <peglotfe@microsoft.com>"]
[dependencies]
strum = { path = "../strum" }
strum_macros = { path = "../strum_macros" }
strum_macros = { path = "../strum_macros", features = [] }

View File

@ -0,0 +1,23 @@
[package]
name = "strum_tests_rename"
version = "0.15.0"
authors = ["Peter Glotfelty <peglotfe@microsoft.com>"]
[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"
]

View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@ -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
}

View File

@ -8,3 +8,8 @@ cargo build --verbose
cargo test --verbose
cd ..
cd ./strum_tests_rename
cargo build --verbose
cargo test --verbose
cd ..