mirror of
https://github.com/danog/strum.git
synced 2024-11-26 12:04:38 +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:
parent
1f4a3b2534
commit
970b5cec40
16
CHANGELOG.md
16
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<YourEnum>` for `&'static str`. This deprecates `AsStaticStr` since
|
||||
* Added a derive to implement `From<YourEnum>` for `&'static str`. This deprecates `AsStaticStr` since
|
||||
the new solution doesn't require a `strum` specific trait to use.
|
||||
|
||||
## 0.12.0
|
||||
|
@ -2,5 +2,7 @@
|
||||
members = [
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"strum_tests",
|
||||
]
|
||||
"strum_tests"
|
||||
]
|
||||
|
||||
exclude = [ "strum_tests_rename" ]
|
2
LICENSE
2
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
|
||||
|
695
README.md
695
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<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. |
|
||||
|
||||
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<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),
|
||||
}
|
||||
// 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),
|
||||
}
|
||||
}
|
||||
*/
|
||||
```
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
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<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.
|
||||
|
||||
## 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;
|
||||
#[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<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.
|
||||
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<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`.
|
||||
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<str>` 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::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
```
|
||||
#[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<MyEnum> 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::<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());
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
|
@ -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" }
|
528
strum/src/lib.rs
528
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<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
|
||||
|
@ -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 = []
|
@ -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);
|
||||
|
@ -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 = [] }
|
23
strum_tests_rename/Cargo.toml
Normal file
23
strum_tests_rename/Cargo.toml
Normal 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"
|
||||
]
|
3
strum_tests_rename/src/main.rs
Normal file
3
strum_tests_rename/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
27
strum_tests_rename/tests/color.rs
Normal file
27
strum_tests_rename/tests/color.rs
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user