mirror of
https://github.com/danog/strum.git
synced 2024-11-26 20:14:40 +01:00
Add derive(AsRefStr)
implementation (#10)
Implements AsRef<str> as a non-allocating alternative to deriving ToString. Docs will come later
This commit is contained in:
parent
c9bba73f9b
commit
af58a6d403
62
strum_macros/src/as_ref_str.rs
Normal file
62
strum_macros/src/as_ref_str.rs
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
use quote;
|
||||
use syn;
|
||||
|
||||
use helpers::{unique_attr, extract_attrs, is_disabled};
|
||||
|
||||
pub fn as_ref_str_inner(ast: &syn::DeriveInput) -> quote::Tokens {
|
||||
let name = &ast.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
|
||||
let variants = match ast.body {
|
||||
syn::Body::Enum(ref v) => v,
|
||||
_ => panic!("AsRefStr only works on Enums"),
|
||||
};
|
||||
|
||||
let mut arms = Vec::new();
|
||||
for variant in variants {
|
||||
use syn::VariantData::*;
|
||||
let ident = &variant.ident;
|
||||
|
||||
if is_disabled(&variant.attrs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look at all the serialize attributes.
|
||||
// Use `to_string` attribute (not `as_ref_str` or something) to keep things consistent
|
||||
// (i.e. always `enum.as_ref().to_string() == enum.to_string()`).
|
||||
let output = if let Some(n) = unique_attr(&variant.attrs, "strum", "to_string") {
|
||||
n
|
||||
} else {
|
||||
let mut attrs = extract_attrs(&variant.attrs, "strum", "serialize");
|
||||
// We always take the longest one. This is arbitary, but is *mostly* deterministic
|
||||
attrs.sort_by_key(|s| -(s.len() as isize));
|
||||
if let Some(n) = attrs.first() {
|
||||
n
|
||||
} else {
|
||||
ident.as_ref()
|
||||
}
|
||||
};
|
||||
|
||||
let params = match variant.data {
|
||||
Unit => quote::Ident::from(""),
|
||||
Tuple(..) => quote::Ident::from("(..)"),
|
||||
Struct(..) => quote::Ident::from("{..}"),
|
||||
};
|
||||
|
||||
arms.push(quote!{ #name::#ident #params => #output });
|
||||
}
|
||||
|
||||
if arms.len() < variants.len() {
|
||||
arms.push(quote!{ _ => panic!("AsRef<str>::as_ref() called on disabled variant.")})
|
||||
}
|
||||
|
||||
quote!{
|
||||
impl #impl_generics ::std::convert::AsRef<str> for #name #ty_generics #where_clause {
|
||||
fn as_ref(&self) -> &str {
|
||||
match *self {
|
||||
#(#arms),*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ extern crate quote;
|
||||
extern crate proc_macro;
|
||||
|
||||
mod helpers;
|
||||
mod as_ref_str;
|
||||
mod to_string;
|
||||
mod from_string;
|
||||
mod enum_iter;
|
||||
@ -46,6 +47,16 @@ pub fn from_string(input: TokenStream) -> TokenStream {
|
||||
toks.parse().unwrap()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(AsRefStr,attributes(strum))]
|
||||
pub fn as_ref_str(input: TokenStream) -> TokenStream {
|
||||
let s = input.to_string();
|
||||
let ast = syn::parse_derive_input(&s).unwrap();
|
||||
|
||||
let toks = as_ref_str::as_ref_str_inner(&ast);
|
||||
debug_print_generated(&ast, &toks);
|
||||
toks.parse().unwrap()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ToString,attributes(strum))]
|
||||
pub fn to_string(input: TokenStream) -> TokenStream {
|
||||
let s = input.to_string();
|
||||
|
@ -57,4 +57,4 @@ pub fn to_string_inner(ast: &syn::DeriveInput) -> quote::Tokens {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
strum_tests/tests/as_ref_str.rs
Normal file
46
strum_tests/tests/as_ref_str.rs
Normal file
@ -0,0 +1,46 @@
|
||||
extern crate strum;
|
||||
#[macro_use]
|
||||
extern crate strum_macros;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug,Eq,PartialEq,EnumString,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 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());
|
||||
}
|
||||
|
||||
#[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());
|
||||
}
|
@ -35,6 +35,7 @@ fn to_yellow_string() {
|
||||
|
||||
#[test]
|
||||
fn to_red_string() {
|
||||
assert_eq!(String::from("RedRed"), (Color::Red).to_string());
|
||||
assert_eq!(Color::Red,
|
||||
Color::from_str((Color::Red).to_string().as_ref()).unwrap());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user