Repository: Peternator7/strum
Pull request #28 (2018-06-23 23:13:27)

Did a little bit of refactoring and added some docs around AsStaticStr


Patch:
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<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 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 <peglotfe@microsoft.com>"]
 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<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.
+//!     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<str>` 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 <peglotfe@microsoft.com>"]
 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<TokenStream> {
     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<str> 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<str> 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();


Test patch:
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 <peglotfe@microsoft.com>"]
 
 [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();
 }