Repository: Peternator7/strum
Pull request #24 (2018-05-23 07:19:14)

Add `AsStaticRef` trait and let `derive(AsRefStr)` implement `AsStaticRef<str>`
This will solve #23.
I'm not sure which name should be used:

* `AsStaticStr::as_static_str()`,
* `AsStaticStr::as_str()` (<-- current choice),
* `AsStr::as_str()`.

Additionaly, documentation should be updated (but I didn't)...

Peternator7: Hey! I appreciate the fix 👍 I think we should keep the symmetry with `AsRef<str>`. 

Either:
- `AsStaticRef::<str>::as_static()` <-- preferred
- `AsStaticRef::<str>::as_static_ref()`

I will happily make the doc changes once we get this merged 😊
lo48576: Rebased (onto current master) and amended.

Patch:
diff --git a/strum/src/lib.rs b/strum/src/lib.rs
index 8aba4a0..15061b3 100644
--- a/strum/src/lib.rs
+++ b/strum/src/lib.rs
@@ -515,3 +515,13 @@ pub trait EnumProperty {
         Option::None
     }
 }
+
+
+/// A cheap reference-to-reference conversion. Used to convert a value to a
+/// reference value with `'static` lifetime within generic code.
+pub trait AsStaticRef<T>
+where
+    T: ?Sized,
+{
+    fn as_static(&self) -> &'static T;
+}
diff --git a/strum_macros/src/as_ref_str.rs b/strum_macros/src/as_ref_str.rs
index f355956..83604ab 100644
--- a/strum_macros/src/as_ref_str.rs
+++ b/strum_macros/src/as_ref_str.rs
@@ -48,12 +48,22 @@ pub fn as_ref_str_inner(ast: &syn::DeriveInput) -> quote::Tokens {
     }
 
     if arms.len() < variants.len() {
-        arms.push(quote!{ _ => panic!("AsRef<str>::as_ref() called on disabled variant.")})
+        arms.push(quote!{
+            _ => panic!("AsRef::<str>::as_ref() or AsStaticRef::<str>::as_static() \
+                         called on disabled variant.")
+        })
     }
 
+    let arms = &arms;
     quote!{
         impl #impl_generics ::std::convert::AsRef<str> for #name #ty_generics #where_clause {
             fn as_ref(&self) -> &str {
+                ::strum::AsStaticRef::as_static(self)
+            }
+        }
+
+        impl #impl_generics ::strum::AsStaticRef<str> for #name #ty_generics #where_clause {
+            fn as_static(&self) -> &'static str {
                 match *self {
                     #(#arms),*
                 }


Test patch:
diff --git a/strum_tests/tests/as_ref_str.rs b/strum_tests/tests/as_ref_str.rs
index a7a54cf..5d6965d 100644
--- a/strum_tests/tests/as_ref_str.rs
+++ b/strum_tests/tests/as_ref_str.rs
@@ -4,6 +4,8 @@ extern crate strum_macros;
 
 use std::str::FromStr;
 
+use strum::AsStaticRef;
+
 #[derive(Debug,Eq,PartialEq,EnumString,AsRefStr)]
 enum Color {
     #[strum(to_string="RedRed")]
@@ -27,20 +29,24 @@ fn as_red_str() {
                (Color::Red).as_ref());
     assert_eq!(Color::Red,
                Color::from_str((Color::Red).as_ref()).unwrap());
+    let _: &'static str = Color::Red.as_static();
 }
 
 #[test]
 fn as_blue_str() {
     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();
 }
 
 #[test]
 fn as_green_str() {
     assert_eq!("Green", (Color::Green(String::default())).as_ref());
+    let _: &'static str = Color::Green(String::default()).as_static();
 }