1
0
mirror of https://github.com/danog/strum.git synced 2025-01-22 14:02:27 +01:00

implement From<Enum> for &'static str in case of AsStaticRef derive (#40)

* 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
This commit is contained in:
Evgeniy Dushistov 2018-12-24 19:33:57 +03:00 committed by Peter Glotfelty
parent cb3a611b0e
commit fe6c20a249
4 changed files with 106 additions and 11 deletions

View File

@ -372,7 +372,7 @@
//! assert_eq!(MyVariants::Variant0, MyEnum::Variant0(true).into()); //! assert_eq!(MyVariants::Variant0, MyEnum::Variant0(true).into());
//! } //! }
//! ``` //! ```
//! //!
//! 8. `EnumCount`: for a given enum generates implementation of `strum::EnumCount`, //! 8. `EnumCount`: for a given enum generates implementation of `strum::EnumCount`,
//! which returns number of variants via `strum::EnumCount::count` method, //! which returns number of variants via `strum::EnumCount::count` method,
//! also for given `enum MyEnum` generates `const MYENUM_COUNT: usize` //! 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 /// A cheap reference-to-reference conversion. Used to convert a value to a
/// reference value with `'static` lifetime within generic code. /// reference value with `'static` lifetime within generic code.
/// #[deprecated(since="0.13.0", note="please use `#[derive(IntoStaticStr)]` instead")]
pub trait AsStaticRef<T> pub trait AsStaticRef<T>
where where
T: ?Sized, T: ?Sized,
@ -699,8 +700,8 @@ where
fn as_static(&self) -> &'static T; fn as_static(&self) -> &'static T;
} }
/// A trait for capturing the number of variants in Enum. This trait can be autoderived by /// A trait for capturing the number of variants in Enum. This trait can be autoderived by
/// `strum_macros`. /// `strum_macros`.
pub trait EnumCount { pub trait EnumCount {
fn count() -> usize; fn count() -> usize;
} }

View File

@ -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 name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let arms = get_arms(ast); let arms = get_arms(ast);
quote!{
impl #impl_generics ::strum::AsStaticRef<str> for #name #ty_generics #where_clause { let mut generics = ast.generics.clone();
fn as_static(&self) -> &'static str { generics
match *self { .params
#(#arms),* .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),*
}
}
}
}
}
} }
} }

View File

@ -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 { pub fn as_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse(input).unwrap(); 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); debug_print_generated(&ast, &toks);
toks.into() toks.into()
} }

View File

@ -5,7 +5,7 @@ extern crate strum_macros;
use std::str::FromStr; use std::str::FromStr;
use strum::AsStaticRef; use strum::AsStaticRef;
#[derive(Debug, Eq, PartialEq, EnumString, AsRefStr, AsStaticStr)] #[derive(Debug, Eq, PartialEq, EnumString, AsRefStr, AsStaticStr, IntoStaticStr)]
enum Color { enum Color {
#[strum(to_string = "RedRed")] #[strum(to_string = "RedRed")]
Red, Red,
@ -40,3 +40,48 @@ fn as_green_str() {
assert_eq!("Green", (Color::Green(String::default())).as_ref()); 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();
} }
#[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)));
}