Skip to content

Commit

Permalink
implement From<Enum> for &'static str in case of AsStaticRef derive (#40
Browse files Browse the repository at this point in the history
)

* implement From<Enum> for &'static str in case of AsStaticRef derive

* make possible to use <&'static str>::from(Enum) without strum crate

* mark AsStaticRef trait as deprecated
  • Loading branch information
Dushistov authored and Peternator7 committed Dec 24, 2018
1 parent cb3a611 commit fe6c20a
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 11 deletions.
7 changes: 4 additions & 3 deletions strum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -692,15 +692,16 @@ 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,
{
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;
}
52 changes: 46 additions & 6 deletions strum_macros/src/as_ref_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),*
}
}
}
}
}
}
}
11 changes: 10 additions & 1 deletion strum_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
47 changes: 46 additions & 1 deletion strum_tests/tests/as_ref_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)));
}

0 comments on commit fe6c20a

Please sign in to comment.