From b6e4e6615788ab5d958ba7bbedd2fb55a069c323 Mon Sep 17 00:00:00 2001 From: Peter Glotfelty Date: Tue, 26 Jun 2018 08:22:19 -0700 Subject: [PATCH] Did a little bit of refactoring and added some docs around AsStaticStr (#28) * Did a little bit of refactoring and added some docs around AsStaticStr * Revving the version in the cargoo.toml * Managing Cargo.toml is a bit tedious when deploying packages that depend on each other * Updated Cargo.toml --- README.md | 33 +++++++++++++++++++++++++-- strum/Cargo.toml | 5 ++-- strum/src/lib.rs | 30 +++++++++++++++++++++++- strum_macros/Cargo.toml | 2 +- strum_macros/src/as_ref_str.rs | 26 ++++++++++++++++----- strum_macros/src/lib.rs | 9 ++++++++ strum_tests/Cargo.toml | 2 +- strum_tests/tests/as_ref_no_strum.rs | 34 ++++++++++++++++++++++++++++ strum_tests/tests/as_ref_str.rs | 22 +++++------------- 9 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 strum_tests/tests/as_ref_no_strum.rs diff --git a/README.md b/README.md index da05473..b7b6331 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Cargo.toml. Strum_macros contains the macros needed to derive all the traits in ```toml [dependencies] -strum = "0.9.0" -strum_macros = "0.9.0" +strum = "0.10.0" +strum_macros = "0.10.0" ``` And add these lines to the root of your project, either lib.rs or main.rs. @@ -135,6 +135,35 @@ Strum has implemented the following macros: `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. `AsStaticStr`: this is similar to `AsRefStr`, but returns a `'static` reference to a string which is helpful + in some scenarios. This macro implements `strum::AsStaticRef` which adds a method `.to_static()` that + returns a `&'static str`. + + ```rust + extern crate strum; + #[macro_use] extern crate strum_macros; + + use strum::AsStaticRef; + + #[derive(AsStaticStr)] + enum State<'a> { + Initial(&'a str), + Finished + } + + fn print_state<'a>(s:&'a str) { + let 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.as_static(); + 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 is the iterator object. You cannot derive diff --git a/strum/Cargo.toml b/strum/Cargo.toml index 19af2aa..99aab30 100644 --- a/strum/Cargo.toml +++ b/strum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strum" -version = "0.9.0" +version = "0.10.0" authors = ["Peter Glotfelty "] license = "MIT" @@ -13,9 +13,8 @@ homepage = "https://github.com/Peternator7/strum" readme = "../README.md" [dev-dependencies] -strum_macros = "0.9.0" +strum_macros = "0.10.0" # strum_macros = { path = "../strum_macros" } - [badges] travis-ci = { repository = "Peternator7/strum" } \ No newline at end of file diff --git a/strum/src/lib.rs b/strum/src/lib.rs index 15061b3..2c1388d 100644 --- a/strum/src/lib.rs +++ b/strum/src/lib.rs @@ -121,8 +121,36 @@ //! //! 3. `AsRefStr`: this derive implements `AsRef` on your enum using the same rules as //! `ToString` for determining what string is returned. The difference is that `as_ref()` returns -//! a `&str` instead of a `String` so you don't allocate any additional memory with each call. +//! a borrowed `str` instead of a `String` so you can save an allocation. //! +//! 4. `AsStaticStr`: this is similar to `AsRefStr`, but returns a `'static` reference to a string which is helpful +//! in some scenarios. This macro implements `strum::AsStaticRef` which adds a method `.as_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 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.as_static(); +//! 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`. diff --git a/strum_macros/Cargo.toml b/strum_macros/Cargo.toml index ca34e0b..be868d8 100644 --- a/strum_macros/Cargo.toml +++ b/strum_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strum_macros" -version = "0.9.0" +version = "0.10.0" authors = ["Peter Glotfelty "] license = "MIT" diff --git a/strum_macros/src/as_ref_str.rs b/strum_macros/src/as_ref_str.rs index ce38551..09cbc08 100644 --- a/strum_macros/src/as_ref_str.rs +++ b/strum_macros/src/as_ref_str.rs @@ -3,15 +3,14 @@ use syn; use helpers::{unique_attr, extract_attrs, extract_meta, is_disabled}; -pub fn as_ref_str_inner(ast: &syn::DeriveInput) -> TokenStream { +fn get_arms(ast: &syn::DeriveInput) -> Vec { let name = &ast.ident; - let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + let mut arms = Vec::new(); let variants = match ast.data { syn::Data::Enum(ref v) => &v.variants, - _ => panic!("AsRefStr only works on Enums"), + _ => panic!("This macro only works on Enums"), }; - let mut arms = Vec::new(); for variant in variants { use syn::Fields::*; let ident = &variant.ident; @@ -53,14 +52,29 @@ pub fn as_ref_str_inner(ast: &syn::DeriveInput) -> TokenStream { }) } - let arms = &arms; + arms +} + +pub fn as_ref_str_inner(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + let arms = get_arms(ast); quote!{ impl #impl_generics ::std::convert::AsRef for #name #ty_generics #where_clause { fn as_ref(&self) -> &str { - ::strum::AsStaticRef::as_static(self) + match *self { + #(#arms),* + } } } + } +} +pub fn as_static_str_inner(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + let arms = get_arms(ast); + quote!{ impl #impl_generics ::strum::AsStaticRef for #name #ty_generics #where_clause { fn as_static(&self) -> &'static str { match *self { diff --git a/strum_macros/src/lib.rs b/strum_macros/src/lib.rs index d611b89..7bb1b7a 100644 --- a/strum_macros/src/lib.rs +++ b/strum_macros/src/lib.rs @@ -58,6 +58,15 @@ pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { toks.into() } +#[proc_macro_derive(AsStaticStr,attributes(strum))] +pub fn as_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse(input).unwrap(); + + let toks = as_ref_str::as_static_str_inner(&ast); + debug_print_generated(&ast, &toks); + toks.into() +} + #[proc_macro_derive(ToString,attributes(strum))] pub fn to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).unwrap(); diff --git a/strum_tests/Cargo.toml b/strum_tests/Cargo.toml index 874a44c..adddc94 100644 --- a/strum_tests/Cargo.toml +++ b/strum_tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strum_tests" -version = "0.9.0" +version = "0.9.1" authors = ["Peter Glotfelty "] [dependencies] diff --git a/strum_tests/tests/as_ref_no_strum.rs b/strum_tests/tests/as_ref_no_strum.rs new file mode 100644 index 0000000..12d68f6 --- /dev/null +++ b/strum_tests/tests/as_ref_no_strum.rs @@ -0,0 +1,34 @@ +#[macro_use] +extern crate strum_macros; + +#[derive(Debug,Eq,PartialEq,AsRefStr)] +enum Color { + #[strum(to_string="RedRed")] + Red, + #[strum(serialize="b", to_string="blue")] + Blue { hue: usize }, + #[strum(serialize="y", serialize="yellow")] + Yellow, + #[strum(default="true")] + Green(String), +} + +#[test] +fn as_red_str() { + assert_eq!("RedRed", (Color::Red).as_ref()); +} + +#[test] +fn as_blue_str() { + assert_eq!("blue", (Color::Blue { hue: 0 }).as_ref()); +} + +#[test] +fn as_yellow_str() { + assert_eq!("yellow", (Color::Yellow).as_ref()); +} + +#[test] +fn as_green_str() { + assert_eq!("Green", (Color::Green(String::default())).as_ref()); +} diff --git a/strum_tests/tests/as_ref_str.rs b/strum_tests/tests/as_ref_str.rs index 5d6965d..9db2a70 100644 --- a/strum_tests/tests/as_ref_str.rs +++ b/strum_tests/tests/as_ref_str.rs @@ -3,10 +3,9 @@ extern crate strum; extern crate strum_macros; use std::str::FromStr; - use strum::AsStaticRef; -#[derive(Debug,Eq,PartialEq,EnumString,AsRefStr)] +#[derive(Debug,Eq,PartialEq,EnumString,AsRefStr,AsStaticStr)] enum Color { #[strum(to_string="RedRed")] Red, @@ -18,35 +17,26 @@ enum Color { Green(String), } -#[test] -fn color_simple() { - assert_eq!(Color::Red, Color::from_str("RedRed").unwrap()); -} - #[test] fn as_red_str() { - assert_eq!("RedRed", - (Color::Red).as_ref()); - assert_eq!(Color::Red, - Color::from_str((Color::Red).as_ref()).unwrap()); - let _: &'static str = Color::Red.as_static(); + assert_eq!("RedRed", (Color::Red).as_ref()); + assert_eq!(Color::Red, Color::from_str((Color::Red).as_ref()).unwrap()); } #[test] fn as_blue_str() { - assert_eq!("blue", - (Color::Blue { hue: 0 }).as_ref()); + assert_eq!("blue", (Color::Blue { hue: 0 }).as_ref()); let _: &'static str = (Color::Blue { hue: 0 }).as_static(); } #[test] fn as_yellow_str() { assert_eq!("yellow", (Color::Yellow).as_ref()); - let _: &'static str = Color::Yellow.as_static(); + let _: &'static str = (Color::Yellow).as_static(); } #[test] fn as_green_str() { assert_eq!("Green", (Color::Green(String::default())).as_ref()); - let _: &'static str = Color::Green(String::default()).as_static(); + let _: &'static str = (Color::Green(String::default())).as_static(); }