Repository: Peternator7/strum (rust)

Issue:
RFC: Use instead (in addition) to strum::AsStaticStr  core::convert::Into trait ?
What about generates something like:

```Rust
        impl Into<&'static str> for $Name {
            fn into(self) -> &'static str {
                match self {
                    $($Name::$Variant => $StrVar),*
                }
            }
        }
```

instead of `strum::AsStaticStr` or in additional to `strum::AsStaticStr`?

Pull request description:
implement From<Enum> for &'static str in case of AsStaticRef derive
fix #38

Patch:
diff --git a/strum/src/lib.rs b/strum/src/lib.rs
index 0ff91f1..5e596e8 100644
--- a/strum/src/lib.rs
+++ b/strum/src/lib.rs
@@ -372,7 +372,7 @@
 //!         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`
@@ -692,6 +692,7 @@ pub trait EnumProperty {
 
 /// A cheap reference-to-reference conversion. Used to convert a value to a
 /// reference value with `'static` lifetime within generic code.
+/// #[deprecated(since="0.13.0", note="please use `#[derive(IntoStaticStr)]` instead")]
 pub trait AsStaticRef<T>
 where
     T: ?Sized,
@@ -699,8 +700,8 @@ where
     fn as_static(&self) -> &'static T;
 }
 
-/// A trait for capturing the number of variants in Enum. This trait can be autoderived by 
-/// `strum_macros`. 
+/// A trait for capturing the number of variants in Enum. This trait can be autoderived by
+/// `strum_macros`.
 pub trait EnumCount {
     fn count() -> usize;
 }
diff --git a/strum_macros/src/as_ref_str.rs b/strum_macros/src/as_ref_str.rs
index e89ece5..e824980 100644
--- a/strum_macros/src/as_ref_str.rs
+++ b/strum_macros/src/as_ref_str.rs
@@ -70,17 +70,57 @@ pub fn as_ref_str_inner(ast: &syn::DeriveInput) -> TokenStream {
     }
 }
 
-pub fn as_static_str_inner(ast: &syn::DeriveInput) -> TokenStream {
+pub enum GenerateTraitVariant {
+    AsStaticStr,
+    From,
+}
+
+pub fn as_static_str_inner(
+    ast: &syn::DeriveInput,
+    trait_variant: GenerateTraitVariant,
+) -> 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 {
-                    #(#arms),*
+
+    let mut generics = ast.generics.clone();
+    generics
+        .params
+        .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(
+            parse_quote!('_derivative_strum),
+        )));
+    let (impl_generics2, _, _) = generics.split_for_impl();
+    let arms2 = arms.clone();
+    let arms3 = arms.clone();
+    match trait_variant {
+        GenerateTraitVariant::AsStaticStr => {
+            quote!{
+                impl #impl_generics ::strum::AsStaticRef<str> for #name #ty_generics #where_clause {
+                    fn as_static(&self) -> &'static str {
+                        match *self {
+                            #(#arms),*
+                        }
+                    }
                 }
             }
         }
+        GenerateTraitVariant::From => {
+            quote! {
+            impl #impl_generics ::std::convert::From<#name #ty_generics> for &'static str #where_clause {
+                fn from(x: #name #ty_generics) -> &'static str {
+                    match x {
+                        #(#arms2),*
+                    }
+                }
+            }
+            impl #impl_generics2 ::std::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause {
+                fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
+                    match *x {
+                        #(#arms3),*
+                    }
+                }
+            }
+            }
+        }
     }
 }
diff --git a/strum_macros/src/lib.rs b/strum_macros/src/lib.rs
index 30d4f5b..b428212 100644
--- a/strum_macros/src/lib.rs
+++ b/strum_macros/src/lib.rs
@@ -67,7 +67,16 @@ pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
 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);
+    let toks = as_ref_str::as_static_str_inner(&ast, as_ref_str::GenerateTraitVariant::AsStaticStr);
+    debug_print_generated(&ast, &toks);
+    toks.into()
+}
+
+#[proc_macro_derive(IntoStaticStr, attributes(strum))]
+pub fn into_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, as_ref_str::GenerateTraitVariant::From);
     debug_print_generated(&ast, &toks);
     toks.into()
 }


Test patch:
diff --git a/strum_tests/tests/as_ref_str.rs b/strum_tests/tests/as_ref_str.rs
index c2b1e20..0262f3a 100644
--- a/strum_tests/tests/as_ref_str.rs
+++ b/strum_tests/tests/as_ref_str.rs
@@ -5,7 +5,7 @@ extern crate strum_macros;
 use std::str::FromStr;
 use strum::AsStaticRef;
 
-#[derive(Debug, Eq, PartialEq, EnumString, AsRefStr, AsStaticStr)]
+#[derive(Debug, Eq, PartialEq, EnumString, AsRefStr, AsStaticStr, IntoStaticStr)]
 enum Color {
     #[strum(to_string = "RedRed")]
     Red,
@@ -40,3 +40,48 @@ fn as_green_str() {
     assert_eq!("Green", (Color::Green(String::default())).as_ref());
     let _: &'static str = (Color::Green(String::default())).as_static();
 }
+
+#[derive(IntoStaticStr)]
+enum Foo<'a> {
+    A,
+    C(&'a i32),
+}
+
+#[derive(IntoStaticStr)]
+enum Boo<'a, T> {
+    A(T),
+    B,
+    C(&'a i32),
+}
+
+#[derive(IntoStaticStr)]
+enum Moo<'a, T>
+where
+    T: AsRef<str>,
+{
+    A(T),
+    B,
+    C(&'a i32),
+}
+
+#[test]
+fn test_into_static_str() {
+    assert_eq!("RedRed", <&'static str>::from(Color::Red));
+    assert_eq!("blue", <&'static str>::from(Color::Blue { hue: 0 }));
+    assert_eq!("yellow", <&'static str>::from(Color::Yellow));
+
+    assert_eq!("RedRed", <&'static str>::from(&Color::Red));
+    assert_eq!("blue", <&'static str>::from(&Color::Blue { hue: 0 }));
+    assert_eq!("yellow", <&'static str>::from(&Color::Yellow));
+
+    assert_eq!("A", <&'static str>::from(Foo::A));
+    assert_eq!("C", <&'static str>::from(Foo::C(&17)));
+
+    assert_eq!("A", <&'static str>::from(Boo::A(17)));
+    assert_eq!("B", <&'static str>::from(Boo::B::<i32>));
+    assert_eq!("C", <&'static str>::from(Boo::C::<i32>(&17)));
+
+    assert_eq!("A", <&'static str>::from(Moo::A::<String>("aaa".into())));
+    assert_eq!("B", <&'static str>::from(Moo::B::<String>));
+    assert_eq!("C", <&'static str>::from(Moo::C::<String>(&17)));
+}