Run cargo fmt, minor code cleanup

rename
Pantonshire 5 years ago
parent 4317afa003
commit f9a9db2e9a

@ -2,9 +2,9 @@ use std::collections::HashMap;
use std::fmt; use std::fmt;
use proc_macro2::Span; use proc_macro2::Span;
use syn::{Attribute, Ident, Lit, Token};
use syn::parse::{Parse, ParseBuffer, ParseStream};
use syn::parse::discouraged::Speculative; use syn::parse::discouraged::Speculative;
use syn::parse::{Parse, ParseBuffer, ParseStream};
use syn::{Attribute, Ident, Lit, Token};
use crate::error::{MacroError, MacroResult, ValueTypeError, ValueTypeResult}; use crate::error::{MacroError, MacroResult, ValueTypeError, ValueTypeResult};
@ -40,8 +40,8 @@ impl Value {
Value::None => Ok(true), Value::None => Ok(true),
Value::Lit(Lit::Bool(lit_bool)) => Ok(lit_bool.value), Value::Lit(Lit::Bool(lit_bool)) => Ok(lit_bool.value),
val => Err(ValueTypeError { val => Err(ValueTypeError {
message: format!("expected boolean but found {}", val.type_name()).into() message: format!("expected boolean but found {}", val.type_name()).into(),
}) }),
} }
} }
@ -51,8 +51,8 @@ impl Value {
match self { match self {
Value::Lit(Lit::Str(lit_str)) => Ok(lit_str.value()), Value::Lit(Lit::Str(lit_str)) => Ok(lit_str.value()),
val => Err(ValueTypeError { val => Err(ValueTypeError {
message: format!("expected string but found {}", val.type_name()).into() message: format!("expected string but found {}", val.type_name()).into(),
}) }),
} }
} }
} }
@ -97,13 +97,16 @@ struct KeyValPair {
impl Dict { impl Dict {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Dict { inner: HashMap::new() } Dict {
inner: HashMap::new(),
}
} }
pub(crate) fn from_attrs(name: &str, attrs: &[Attribute]) -> MacroResult<Self> { pub(crate) fn from_attrs(name: &str, attrs: &[Attribute]) -> MacroResult<Self> {
let mut dict = Dict::new(); let mut dict = Dict::new();
let attribute_tags = attrs.iter() let attribute_tags = attrs
.iter()
.filter(|attr| attr.path.is_ident(name)) .filter(|attr| attr.path.is_ident(name))
.map(|attr| attr.parse_args::<AttributeTag>()); .map(|attr| attr.parse_args::<AttributeTag>());
@ -112,9 +115,10 @@ impl Dict {
for (key, val, span) in tag.inner { for (key, val, span) in tag.inner {
if dict.inner.contains_key(&key) { if dict.inner.contains_key(&key) {
return Err(MacroError::new(format!( return Err(MacroError::new(
"key appears more than once: {}", key format!("key appears more than once: {}", key),
), span)); span,
));
} }
dict.inner.insert(key, (val, span)); dict.inner.insert(key, (val, span));
@ -124,9 +128,13 @@ impl Dict {
Ok(dict) Ok(dict)
} }
pub(crate) fn remove_typed<T, F>(&mut self, key: &str, converter: F) -> MacroResult<Option<(T, Span)>> pub(crate) fn remove_typed<T, F>(
where &mut self,
F: Fn(&Value) -> ValueTypeResult<T> key: &str,
converter: F,
) -> MacroResult<Option<(T, Span)>>
where
F: Fn(&Value) -> ValueTypeResult<T>,
{ {
match self.inner.remove(key) { match self.inner.remove(key) {
None => Ok(None), None => Ok(None),
@ -135,14 +143,19 @@ impl Dict {
Err(ValueTypeError { message }) => Err(MacroError::new( Err(ValueTypeError { message }) => Err(MacroError::new(
format!("{} for key: {}", message, key), format!("{} for key: {}", message, key),
span, span,
)) )),
} },
} }
} }
pub(crate) fn remove_typed_or_default<T, F>(&mut self, key: &str, default: (T, Span), converter: F) -> MacroResult<(T, Span)> pub(crate) fn remove_typed_or_default<T, F>(
where &mut self,
F: Fn(&Value) -> ValueTypeResult<T> key: &str,
default: (T, Span),
converter: F,
) -> MacroResult<(T, Span)>
where
F: Fn(&Value) -> ValueTypeResult<T>,
{ {
match self.remove_typed(key, converter) { match self.remove_typed(key, converter) {
Ok(Some(value)) => Ok(value), Ok(Some(value)) => Ok(value),
@ -171,15 +184,14 @@ impl Parse for AttributeTag {
.parse_terminated::<KeyValPair, Token![,]>(KeyValPair::parse)? .parse_terminated::<KeyValPair, Token![,]>(KeyValPair::parse)?
.into_iter() .into_iter()
.map(|pair| (pair.key, pair.val, pair.span)) .map(|pair| (pair.key, pair.val, pair.span))
.collect::<Vec<_>>() .collect::<Vec<_>>(),
}) })
} }
} }
impl Parse for KeyValPair { impl Parse for KeyValPair {
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
let key = input let key = input.parse::<Ident>()?;
.parse::<Ident>()?;
let val = if input.peek(Token![=]) { let val = if input.peek(Token![=]) {
input.parse::<Token![=]>()?; input.parse::<Token![=]>()?;
@ -190,7 +202,8 @@ impl Parse for KeyValPair {
Value::Ident(ident) Value::Ident(ident)
} else { } else {
return Err(input.error(format!( return Err(input.error(format!(
"could not parse value corresponding to key: {}", key "could not parse value corresponding to key: {}",
key
))); )));
} }
} else { } else {
@ -205,17 +218,23 @@ impl Parse for KeyValPair {
} }
} }
fn speculative_parse<T>(input: ParseStream) -> syn::Result<T> where T: Parse { fn speculative_parse<T>(input: ParseStream) -> syn::Result<T>
where
T: Parse,
{
match fork_and_parse(input) { match fork_and_parse(input) {
Ok((fork, parsed)) => { Ok((fork, parsed)) => {
input.advance_to(&fork); input.advance_to(&fork);
Ok(parsed) Ok(parsed)
} }
Err(err) => Err(err) Err(err) => Err(err),
} }
} }
fn fork_and_parse<T>(input: ParseStream) -> syn::Result<(ParseBuffer, T)> where T: Parse { fn fork_and_parse<T>(input: ParseStream) -> syn::Result<(ParseBuffer, T)>
where
T: Parse,
{
let fork = input.fork(); let fork = input.fork();
T::parse(&fork).map(move |parsed| (fork, parsed)) T::parse(&fork).map(move |parsed| (fork, parsed))
} }

@ -2,13 +2,13 @@ use std::collections::HashSet;
use proc_macro2::{Ident, Span}; use proc_macro2::{Ident, Span};
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{DataEnum, Fields};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{DataEnum, Fields};
use crate::{CASE_INSENSITIVE, CRATE_ATTR, IGNORE, NAME, OTHER};
use crate::TokenStream2;
use crate::attribute::{Dict, Value}; use crate::attribute::{Dict, Value};
use crate::error::{MacroError, MacroResult}; use crate::error::{MacroError, MacroResult};
use crate::TokenStream2;
use crate::{CASE_INSENSITIVE, CRATE_ATTR, IGNORE, NAME, OTHER};
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct Enum<'a> { pub(crate) struct Enum<'a> {
@ -31,7 +31,7 @@ pub(crate) enum VariantType<'a> {
case_insensitive: bool, case_insensitive: bool,
}, },
Other { Other {
field_name: Option<&'a Ident> field_name: Option<&'a Ident>,
}, },
} }
@ -47,18 +47,20 @@ impl<'a> Variant<'a> {
&self, &self,
enum_ident: &Ident, enum_ident: &Ident,
named_fn: &F, named_fn: &F,
other_fn: &G other_fn: &G,
) -> MacroResult<Option<(TokenStream2, TokenStream2)>> ) -> MacroResult<Option<(TokenStream2, TokenStream2)>>
where where
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>, F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2> G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>,
{ {
let variant_ident = &self.data.ident; let variant_ident = &self.data.ident;
match &self.v_type { match &self.v_type {
VariantType::Ignore => Ok(None), VariantType::Ignore => Ok(None),
VariantType::Named { name, constructor, .. } => { VariantType::Named {
name, constructor, ..
} => {
let constructor_tokens = constructor.empty(); let constructor_tokens = constructor.empty();
let pattern = quote! { #enum_ident::#variant_ident #constructor_tokens }; let pattern = quote! { #enum_ident::#variant_ident #constructor_tokens };
Ok(Some((pattern, named_fn(self, enum_ident, name)?))) Ok(Some((pattern, named_fn(self, enum_ident, name)?)))
@ -67,13 +69,16 @@ impl<'a> Variant<'a> {
VariantType::Other { field_name } => { VariantType::Other { field_name } => {
let field_name_tokens = match field_name { let field_name_tokens = match field_name {
Some(field_name) => field_name.to_token_stream(), Some(field_name) => field_name.to_token_stream(),
None => quote! { __enumscribe_other_inner } None => quote! { __enumscribe_other_inner },
}; };
let pattern = match field_name { let pattern = match field_name {
Some(_) => quote! { #enum_ident::#variant_ident{#field_name_tokens} }, Some(_) => quote! { #enum_ident::#variant_ident{#field_name_tokens} },
None => quote! { #enum_ident::#variant_ident(#field_name_tokens) } None => quote! { #enum_ident::#variant_ident(#field_name_tokens) },
}; };
Ok(Some((pattern, other_fn(self, enum_ident, field_name_tokens)?))) Ok(Some((
pattern,
other_fn(self, enum_ident, field_name_tokens)?,
)))
} }
} }
} }
@ -84,7 +89,7 @@ impl VariantConstructor {
match self { match self {
VariantConstructor::None => quote! {}, VariantConstructor::None => quote! {},
VariantConstructor::Paren => quote! { () }, VariantConstructor::Paren => quote! { () },
VariantConstructor::Brace => quote! { {} } VariantConstructor::Brace => quote! { {} },
} }
} }
} }
@ -104,9 +109,15 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
// Convert the values in the Dict to the appropriate types // Convert the values in the Dict to the appropriate types
let name_opt = dict.remove_typed(NAME, Value::value_string)?; let name_opt = dict.remove_typed(NAME, Value::value_string)?;
let (other, other_span) = dict.remove_typed_or_default(OTHER, (false, variant_span), Value::value_bool)?; let (other, other_span) =
let (ignore, _) = dict.remove_typed_or_default(IGNORE, (false, variant_span), Value::value_bool)?; dict.remove_typed_or_default(OTHER, (false, variant_span), Value::value_bool)?;
let (case_insensitive, _) = dict.remove_typed_or_default(CASE_INSENSITIVE, (false, variant_span), Value::value_bool)?; let (ignore, _) =
dict.remove_typed_or_default(IGNORE, (false, variant_span), Value::value_bool)?;
let (case_insensitive, _) = dict.remove_typed_or_default(
CASE_INSENSITIVE,
(false, variant_span),
Value::value_bool,
)?;
// Return an error if there are any unrecognised keys in the Dict // Return an error if there are any unrecognised keys in the Dict
dict.assert_empty()?; dict.assert_empty()?;
@ -121,10 +132,7 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
// Return an error if there is already an "other" variant for this enum // Return an error if there is already an "other" variant for this enum
if other_variant { if other_variant {
return Err(MacroError::new( return Err(MacroError::new(
format!( format!("cannot have multiple variants marked as {}", OTHER),
"cannot have multiple variants marked as {}",
OTHER
),
other_span, other_span,
)); ));
} }
@ -136,7 +144,9 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
return Err(MacroError::new( return Err(MacroError::new(
format!( format!(
"cannot use {} for variant {} because it is marked as {}", "cannot use {} for variant {} because it is marked as {}",
NAME, variant.ident.to_string(), OTHER NAME,
variant.ident,
OTHER
), ),
name_span, name_span,
)); ));
@ -147,14 +157,18 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
return Err(MacroError::new( return Err(MacroError::new(
format!( format!(
"the variant {} must have exactly one field because it is marked as {}", "the variant {} must have exactly one field because it is marked as {}",
variant.ident.to_string(), OTHER variant.ident,
OTHER
), ),
variant_span, variant_span,
)); ));
} }
// Get the name of the variant's field (or None if it is unnamed) // Get the name of the variant's field (or None if it is unnamed)
let field_name = variant.fields.iter().next() let field_name = variant
.fields
.iter()
.next()
.and_then(|field| field.ident.as_ref()); .and_then(|field| field.ident.as_ref());
Variant { Variant {
@ -166,7 +180,7 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
// Use the str name if one is provided, otherwise use the variant's name // Use the str name if one is provided, otherwise use the variant's name
let (name, name_span) = match name_opt { let (name, name_span) = match name_opt {
Some((name, name_span)) => (name, name_span), Some((name, name_span)) => (name, name_span),
None => (variant.ident.to_string(), variant.ident.span()) None => (variant.ident.to_string(), variant.ident.span()),
}; };
// Do not allow duplicate names // Do not allow duplicate names
@ -181,7 +195,9 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
// Extra duplicate checking for case-insensitive names // Extra duplicate checking for case-insensitive names
let lowercase_name = name.to_lowercase(); let lowercase_name = name.to_lowercase();
if taken_insensitive_names.contains(&lowercase_name) || (case_insensitive && taken_sensitive_names.contains(&lowercase_name)) { if taken_insensitive_names.contains(&lowercase_name)
|| (case_insensitive && taken_sensitive_names.contains(&lowercase_name))
{
return Err(MacroError::new( return Err(MacroError::new(
format!("duplicate name \"{}\"", name), format!("duplicate name \"{}\"", name),
name_span, name_span,
@ -192,17 +208,17 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
&mut taken_insensitive_names &mut taken_insensitive_names
} else { } else {
&mut taken_sensitive_names &mut taken_sensitive_names
}.insert(lowercase_name); }
.insert(lowercase_name);
// Return an error if the variant has any fields // Return an error if the variant has any fields
if !variant.fields.is_empty() { if !variant.fields.is_empty() {
let variant_ident = variant.ident.to_string();
return Err(MacroError::new( return Err(MacroError::new(
format!( format!(
"the variant {} must not have any fields\n\ "the variant {} must not have any fields\n\
hint: if you do not want to remove {}\'s fields, try using \ hint: if you do not want to remove {}\'s fields, try using \
#[enumscribe(ignore)] for {}", #[enumscribe(ignore)] for {}",
variant_ident, variant_ident, variant_ident variant.ident, variant.ident, variant.ident
), ),
variant_span, variant_span,
)); ));
@ -218,7 +234,11 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
Variant { Variant {
data: variant, data: variant,
v_type: VariantType::Named { name, constructor, case_insensitive }, v_type: VariantType::Named {
name,
constructor,
case_insensitive,
},
span: variant_span, span: variant_span,
} }
}; };

@ -19,7 +19,10 @@ pub(crate) struct MacroError {
pub(crate) type MacroResult<T> = result::Result<T, MacroError>; pub(crate) type MacroResult<T> = result::Result<T, MacroError>;
impl MacroError { impl MacroError {
pub(crate) fn new<T>(message: T, span: Span) -> Self where T: Into<Cow<'static, str>> { pub(crate) fn new<T>(message: T, span: Span) -> Self
where
T: Into<Cow<'static, str>>,
{
MacroError { MacroError {
message: message.into(), message: message.into(),
span, span,

@ -14,10 +14,10 @@ use syn::{Data, DataEnum, DeriveInput};
use error::{MacroError, MacroResult}; use error::{MacroError, MacroResult};
use crate::enums::{Variant, VariantType, Enum}; use crate::enums::{Enum, Variant, VariantType};
mod enums;
mod attribute; mod attribute;
mod enums;
mod error; mod error;
const CRATE_ATTR: &'static str = "enumscribe"; const CRATE_ATTR: &'static str = "enumscribe";
@ -33,7 +33,7 @@ macro_rules! proc_try {
($x:expr) => { ($x:expr) => {
match $x { match $x {
Ok(val) => val, Ok(val) => val,
Err(err) => return err.into() Err(err) => return err.into(),
} }
}; };
} }
@ -46,13 +46,12 @@ fn gen_scribe_impl<F, G, E>(
other_fn: G, other_fn: G,
ignore_err_fn: E, ignore_err_fn: E,
) -> TokenStream ) -> TokenStream
where where
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>, F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>, G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>,
E: Fn(&Variant, &Ident) -> MacroError E: Fn(&Variant, &Ident) -> MacroError,
{ {
let input: DeriveInput = syn::parse(input) let input: DeriveInput = syn::parse(input).expect("failed to parse input");
.expect("failed to parse input");
let enum_data = proc_try!(get_enum_data(&input)); let enum_data = proc_try!(get_enum_data(&input));
let parsed_enum = proc_try!(enums::parse_enum(enum_data)); let parsed_enum = proc_try!(enums::parse_enum(enum_data));
@ -65,7 +64,7 @@ fn gen_scribe_impl<F, G, E>(
match variant.match_variant(enum_ident, &named_fn, &other_fn) { match variant.match_variant(enum_ident, &named_fn, &other_fn) {
Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }), Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }),
Ok(None) => return ignore_err_fn(variant, enum_ident).into(), Ok(None) => return ignore_err_fn(variant, enum_ident).into(),
Err(err) => return err.into() Err(err) => return err.into(),
} }
} }
@ -77,7 +76,8 @@ fn gen_scribe_impl<F, G, E>(
} }
} }
} }
}).into() })
.into()
} }
fn gen_try_scribe_impl<F, G>( fn gen_try_scribe_impl<F, G>(
@ -88,12 +88,11 @@ fn gen_try_scribe_impl<F, G>(
other_fn: G, other_fn: G,
ignore_result: TokenStream2, ignore_result: TokenStream2,
) -> TokenStream ) -> TokenStream
where where
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>, F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2> G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>,
{ {
let input: DeriveInput = syn::parse(input) let input: DeriveInput = syn::parse(input).expect("failed to parse input");
.expect("failed to parse input");
let enum_data = proc_try!(get_enum_data(&input)); let enum_data = proc_try!(get_enum_data(&input));
let parsed_enum = proc_try!(enums::parse_enum(enum_data)); let parsed_enum = proc_try!(enums::parse_enum(enum_data));
@ -107,7 +106,7 @@ fn gen_try_scribe_impl<F, G>(
match variant.match_variant(enum_ident, &named_fn, &other_fn) { match variant.match_variant(enum_ident, &named_fn, &other_fn) {
Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }), Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }),
Ok(None) => ignore_variant = true, Ok(None) => ignore_variant = true,
Err(err) => return err.into() Err(err) => return err.into(),
} }
} }
@ -126,7 +125,8 @@ fn gen_try_scribe_impl<F, G>(
} }
} }
} }
}).into() })
.into()
} }
fn gen_unscribe_impl<F, G, E>( fn gen_unscribe_impl<F, G, E>(
@ -138,13 +138,12 @@ fn gen_unscribe_impl<F, G, E>(
other_fn: G, other_fn: G,
other_missing_fn: E, other_missing_fn: E,
) -> TokenStream ) -> TokenStream
where where
F: Fn(TokenStream2) -> TokenStream2, F: Fn(TokenStream2) -> TokenStream2,
G: Fn(TokenStream2) -> TokenStream2, G: Fn(TokenStream2) -> TokenStream2,
E: Fn(&Ident) -> MacroResult<TokenStream2> E: Fn(&Ident) -> MacroResult<TokenStream2>,
{ {
let input: DeriveInput = syn::parse(input) let input: DeriveInput = syn::parse(input).expect("failed to parse input");
.expect("failed to parse input");
let enum_data = proc_try!(get_enum_data(&input)); let enum_data = proc_try!(get_enum_data(&input));
let parsed_enum = proc_try!(enums::parse_enum(enum_data)); let parsed_enum = proc_try!(enums::parse_enum(enum_data));
@ -154,7 +153,12 @@ fn gen_unscribe_impl<F, G, E>(
let to_unscribe_ident = quote! { __enumscribe_to_unscribe }; let to_unscribe_ident = quote! { __enumscribe_to_unscribe };
let main_match = proc_try!(gen_unscribe_match( let main_match = proc_try!(gen_unscribe_match(
enum_ident, &parsed_enum, &to_unscribe_ident, named_fn, other_fn, other_missing_fn enum_ident,
&parsed_enum,
&to_unscribe_ident,
named_fn,
other_fn,
other_missing_fn
)); ));
(quote! { (quote! {
@ -163,7 +167,8 @@ fn gen_unscribe_impl<F, G, E>(
#main_match #main_match
} }
} }
}).into() })
.into()
} }
fn gen_unscribe_match<F, G, E>( fn gen_unscribe_match<F, G, E>(
@ -174,10 +179,10 @@ fn gen_unscribe_match<F, G, E>(
other_fn: G, other_fn: G,
other_missing_fn: E, other_missing_fn: E,
) -> MacroResult<TokenStream2> ) -> MacroResult<TokenStream2>
where where
F: Fn(TokenStream2) -> TokenStream2, F: Fn(TokenStream2) -> TokenStream2,
G: Fn(TokenStream2) -> TokenStream2, G: Fn(TokenStream2) -> TokenStream2,
E: Fn(&Ident) -> MacroResult<TokenStream2> E: Fn(&Ident) -> MacroResult<TokenStream2>,
{ {
let mut other_arm = None; let mut other_arm = None;
let mut case_sensitive_arms = Vec::new(); let mut case_sensitive_arms = Vec::new();
@ -189,7 +194,11 @@ fn gen_unscribe_match<F, G, E>(
match &variant.v_type { match &variant.v_type {
VariantType::Ignore => (), VariantType::Ignore => (),
VariantType::Named { name, constructor, case_insensitive } => { VariantType::Named {
name,
constructor,
case_insensitive,
} => {
let match_pattern = if *case_insensitive { let match_pattern = if *case_insensitive {
let lowercase_name = name.to_lowercase(); let lowercase_name = name.to_lowercase();
quote! { #lowercase_name } quote! { #lowercase_name }
@ -198,18 +207,21 @@ fn gen_unscribe_match<F, G, E>(
}; };
let constructor_tokens = constructor.empty(); let constructor_tokens = constructor.empty();
let constructed_variant = quote! { #enum_ident::#variant_ident #constructor_tokens }; let constructed_variant =
quote! { #enum_ident::#variant_ident #constructor_tokens };
let match_result = named_fn(constructed_variant); let match_result = named_fn(constructed_variant);
if *case_insensitive { if *case_insensitive {
&mut case_insensitive_arms &mut case_insensitive_arms
} else { } else {
&mut case_sensitive_arms &mut case_sensitive_arms
}.push(quote! { #match_pattern => #match_result }); }
.push(quote! { #match_pattern => #match_result });
} }
VariantType::Other { field_name } => { VariantType::Other { field_name } => {
let unscribe_value = quote! { <_ as ::std::convert::Into<_>>::into(#match_against) }; let unscribe_value =
quote! { <_ as ::std::convert::Into<_>>::into(#match_against) };
let constructed_variant = match field_name { let constructed_variant = match field_name {
None => quote! { None => quote! {
@ -217,7 +229,7 @@ fn gen_unscribe_match<F, G, E>(
}, },
Some(field_name) => quote! { Some(field_name) => quote! {
#enum_ident::#variant_ident { #field_name: #unscribe_value } #enum_ident::#variant_ident { #field_name: #unscribe_value }
} },
}; };
let match_result = other_fn(constructed_variant); let match_result = other_fn(constructed_variant);
@ -229,7 +241,7 @@ fn gen_unscribe_match<F, G, E>(
let other_arm = match other_arm { let other_arm = match other_arm {
Some(other_arm) => other_arm, Some(other_arm) => other_arm,
None => other_missing_fn(enum_ident)? None => other_missing_fn(enum_ident)?,
}; };
let case_insensitive_match = if case_insensitive_arms.is_empty() { let case_insensitive_match = if case_insensitive_arms.is_empty() {
@ -258,16 +270,14 @@ fn gen_unscribe_match<F, G, E>(
} }
}, },
(true, Some(case_insensitive_match)) => { (true, Some(case_insensitive_match)) => case_insensitive_match,
case_insensitive_match
}
(false, Some(case_insensitive_match)) => quote! { (false, Some(case_insensitive_match)) => quote! {
match #match_against { match #match_against {
#(#case_sensitive_arms,)* #(#case_sensitive_arms,)*
_ => { #case_insensitive_match }, _ => { #case_insensitive_match },
} }
} },
}; };
Ok(main_match) Ok(main_match)
@ -301,26 +311,32 @@ fn gen_unscribe_match<F, G, E>(
pub fn derive_scribe_static_str(input: TokenStream) -> TokenStream { pub fn derive_scribe_static_str(input: TokenStream) -> TokenStream {
gen_scribe_impl( gen_scribe_impl(
input, input,
quote! { ::enumscribe::ScribeStaticStr }, quote! { ::enumscribe::ScribeStaticStr },
quote! { &'static str }, quote! { &'static str },
|_, _, name| Ok(quote! { #name }), |_, _, name| Ok(quote! { #name }),
|variant, enum_ident, _| {
|variant, enum_ident, _| Err(MacroError::new(format!( Err(MacroError::new(
"cannot derive ScribeStaticStr for {} because the variant {} is marked as {}, so \ format!(
there is no &'static str associated with it\n\ "cannot derive ScribeStaticStr for {} because the variant {} is marked as {}, so \
hint: try deriving ScribeCowStr instead", there is no &'static str associated with it\n\
enum_ident, variant.data.ident, OTHER hint: try deriving ScribeCowStr instead",
), variant.span)), enum_ident, variant.data.ident, OTHER
),
|variant, enum_ident| MacroError::new(format!( variant.span,
"cannot derive ScribeStaticStr for {} because the variant {} is marked as {}\n\ ))
explanation: since {} is ignored, it cannot be guaranteed that the enum can \ },
always be successfully converted to a String\n\ |variant, enum_ident| {
hint: try deriving TryScribeStaticStr instead", MacroError::new(
enum_ident, variant.data.ident, IGNORE, variant.data.ident format!(
), variant.span), "cannot derive ScribeStaticStr for {} because the variant {} is marked as {}\n\
explanation: since {} is ignored, it cannot be guaranteed that the enum can \
always be successfully converted to a String\n\
hint: try deriving TryScribeStaticStr instead",
enum_ident, variant.data.ident, IGNORE, variant.data.ident
),
variant.span,
)
},
) )
} }
@ -343,21 +359,24 @@ pub fn derive_scribe_static_str(input: TokenStream) -> TokenStream {
pub fn derive_try_scribe_static_str(input: TokenStream) -> TokenStream { pub fn derive_try_scribe_static_str(input: TokenStream) -> TokenStream {
gen_try_scribe_impl( gen_try_scribe_impl(
input, input,
quote! { ::enumscribe::TryScribeStaticStr }, quote! { ::enumscribe::TryScribeStaticStr },
quote! { ::std::option::Option<&'static str> }, quote! { ::std::option::Option<&'static str> },
|_, _, name| {
|_, _, name| Ok(quote! { Ok(quote! {
::std::option::Option::Some(#name) ::std::option::Option::Some(#name)
}), })
},
|variant, enum_ident, _| Err(MacroError::new(format!( |variant, enum_ident, _| {
"cannot derive TryScribeStaticStr for {} because the variant {} is marked as {}, so \ Err(MacroError::new(
there is no &'static str associated with it\n\ format!(
hint: try deriving TryScribeCowStr instead", "cannot derive TryScribeStaticStr for {} because the variant {} is marked as {}, so \
enum_ident, variant.data.ident, OTHER there is no &'static str associated with it\n\
), variant.span)), hint: try deriving TryScribeCowStr instead",
enum_ident, variant.data.ident, OTHER
),
variant.span,
))
},
quote! { ::std::option::Option::None }, quote! { ::std::option::Option::None },
) )
} }
@ -375,25 +394,30 @@ pub fn derive_try_scribe_static_str(input: TokenStream) -> TokenStream {
pub fn derive_scribe_string(input: TokenStream) -> TokenStream { pub fn derive_scribe_string(input: TokenStream) -> TokenStream {
gen_scribe_impl( gen_scribe_impl(
input, input,
quote! { ::enumscribe::ScribeString }, quote! { ::enumscribe::ScribeString },
quote! { ::std::string::String }, quote! { ::std::string::String },
|_, _, name| {
|_, _, name| Ok(quote! { Ok(quote! {
<_ as ::std::borrow::ToOwned>::to_owned(#name) <_ as ::std::borrow::ToOwned>::to_owned(#name)
}), })
},
|_, _, field| Ok(quote! { |_, _, field| {
<_ as ::std::convert::Into<::std::string::String>>::into(#field) Ok(quote! {
}), <_ as ::std::convert::Into<::std::string::String>>::into(#field)
})
|variant, enum_ident| MacroError::new(format!( },
"cannot derive ScribeString for {} because the variant {} is marked as {}\n\ |variant, enum_ident| {
explanation: since {} is ignored, it cannot be guaranteed that the enum can \ MacroError::new(
always be successfully converted to a String\n\ format!(
hint: try deriving TryScribeString instead", "cannot derive ScribeString for {} because the variant {} is marked as {}\n\
enum_ident, variant.data.ident, IGNORE, variant.data.ident explanation: since {} is ignored, it cannot be guaranteed that the enum can \
), variant.span), always be successfully converted to a String\n\
hint: try deriving TryScribeString instead",
enum_ident, variant.data.ident, IGNORE, variant.data.ident
),
variant.span,
)
},
) )
} }
@ -410,22 +434,22 @@ pub fn derive_scribe_string(input: TokenStream) -> TokenStream {
pub fn derive_try_scribe_string(input: TokenStream) -> TokenStream { pub fn derive_try_scribe_string(input: TokenStream) -> TokenStream {
gen_try_scribe_impl( gen_try_scribe_impl(
input, input,
quote! { ::enumscribe::TryScribeString }, quote! { ::enumscribe::TryScribeString },
quote! { ::std::option::Option<::std::string::String> }, quote! { ::std::option::Option<::std::string::String> },
|_, _, name| {
|_, _, name| Ok(quote! { Ok(quote! {
::std::option::Option::Some( ::std::option::Option::Some(
<_ as ::std::borrow::ToOwned>::to_owned(#name) <_ as ::std::borrow::ToOwned>::to_owned(#name)
) )
}), })
},
|_, _, field| Ok(quote! { |_, _, field| {
::std::option::Option::Some( Ok(quote! {
<_ as ::std::convert::Into<::std::string::String>>::into(#field) ::std::option::Option::Some(
) <_ as ::std::convert::Into<::std::string::String>>::into(#field)
}), )
})
},
quote! { ::std::option::Option::None }, quote! { ::std::option::Option::None },
) )
} }
@ -453,27 +477,32 @@ pub fn derive_try_scribe_string(input: TokenStream) -> TokenStream {
pub fn derive_scribe_cow_str(input: TokenStream) -> TokenStream { pub fn derive_scribe_cow_str(input: TokenStream) -> TokenStream {
gen_scribe_impl( gen_scribe_impl(
input, input,
quote! { ::enumscribe::ScribeCowStr }, quote! { ::enumscribe::ScribeCowStr },
quote! { ::std::borrow::Cow<'static, str> }, quote! { ::std::borrow::Cow<'static, str> },
|_, _, name| {
|_, _, name| Ok(quote! { Ok(quote! {
::std::borrow::Cow::Borrowed(#name) ::std::borrow::Cow::Borrowed(#name)
}), })
},
|_, _, field| Ok(quote! { |_, _, field| {
::std::borrow::Cow::Owned( Ok(quote! {
<_ as ::std::convert::Into<::std::string::String>>::into(#field) ::std::borrow::Cow::Owned(
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
)
})
},
|variant, enum_ident| {
MacroError::new(
format!(
"cannot derive ScribeCowStr for {} because the variant {} is marked as {}\n\
explanation: since {} is ignored, it cannot be guaranteed that the enum can \
always be successfully converted to a String\n\
hint: try deriving TryScribeCowStr instead",
enum_ident, variant.data.ident, IGNORE, variant.data.ident
),
variant.span,
) )
}), },
|variant, enum_ident| MacroError::new(format!(
"cannot derive ScribeCowStr for {} because the variant {} is marked as {}\n\
explanation: since {} is ignored, it cannot be guaranteed that the enum can \
always be successfully converted to a String\n\
hint: try deriving TryScribeCowStr instead",
enum_ident, variant.data.ident, IGNORE, variant.data.ident
), variant.span),
) )
} }
@ -501,24 +530,24 @@ pub fn derive_scribe_cow_str(input: TokenStream) -> TokenStream {
pub fn derive_try_scribe_cow_str(input: TokenStream) -> TokenStream { pub fn derive_try_scribe_cow_str(input: TokenStream) -> TokenStream {
gen_try_scribe_impl( gen_try_scribe_impl(
input, input,
quote! { ::enumscribe::TryScribeCowStr }, quote! { ::enumscribe::TryScribeCowStr },
quote! { ::std::option::Option<::std::borrow::Cow<'static, str>> }, quote! { ::std::option::Option<::std::borrow::Cow<'static, str>> },
|_, _, name| {
|_, _, name| Ok(quote! { Ok(quote! {
::std::option::Option::Some( ::std::option::Option::Some(
::std::borrow::Cow::Borrowed(#name) ::std::borrow::Cow::Borrowed(#name)
)
}),
|_, _, field| Ok(quote! {
::std::option::Option::Some(
::std::borrow::Cow::Owned(
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
) )
) })
}), },
|_, _, field| {
Ok(quote! {
::std::option::Option::Some(
::std::borrow::Cow::Owned(
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
)
)
})
},
quote! { ::std::option::Option::None }, quote! { ::std::option::Option::None },
) )
} }
@ -548,22 +577,23 @@ pub fn derive_try_scribe_cow_str(input: TokenStream) -> TokenStream {
pub fn derive_unscribe(input: TokenStream) -> TokenStream { pub fn derive_unscribe(input: TokenStream) -> TokenStream {
gen_unscribe_impl( gen_unscribe_impl(
input, input,
quote! { ::enumscribe::Unscribe }, quote! { ::enumscribe::Unscribe },
quote! { unscribe }, quote! { unscribe },
quote! { Self }, quote! { Self },
|constructed_named_variant| constructed_named_variant, |constructed_named_variant| constructed_named_variant,
|constructed_other_variant| constructed_other_variant, |constructed_other_variant| constructed_other_variant,
|enum_ident| {
|enum_ident| Err(MacroError::new(format!( Err(MacroError::new(
"cannot derive Unscribe for {} because no variant is marked as {}\n\ format!(
explanation: since there is no {} variant, it cannot be guaranteed that every string \ "cannot derive Unscribe for {} because no variant is marked as {}\n\
can be successfully converted to a variant of {}\n\ explanation: since there is no {} variant, it cannot be guaranteed that every string \
hint: either introduce an {} variant, or try deriving TryUnscribe instead", can be successfully converted to a variant of {}\n\
enum_ident, OTHER, OTHER, enum_ident, OTHER hint: either introduce an {} variant, or try deriving TryUnscribe instead",
), enum_ident.span())), enum_ident, OTHER, OTHER, enum_ident, OTHER
),
enum_ident.span(),
))
},
) )
} }
@ -589,15 +619,11 @@ pub fn derive_unscribe(input: TokenStream) -> TokenStream {
pub fn derive_try_unscribe(input: TokenStream) -> TokenStream { pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
gen_unscribe_impl( gen_unscribe_impl(
input, input,
quote! { ::enumscribe::TryUnscribe }, quote! { ::enumscribe::TryUnscribe },
quote! { try_unscribe }, quote! { try_unscribe },
quote! { ::std::option::Option<Self> }, quote! { ::std::option::Option<Self> },
|constructed_named_variant| quote! { ::std::option::Option::Some(#constructed_named_variant) }, |constructed_named_variant| quote! { ::std::option::Option::Some(#constructed_named_variant) },
|constructed_other_variant| quote! { ::std::option::Option::Some(#constructed_other_variant) }, |constructed_other_variant| quote! { ::std::option::Option::Some(#constructed_other_variant) },
|_| Ok(quote! { _ => ::std::option::Option::None }), |_| Ok(quote! { _ => ::std::option::Option::None }),
) )
} }
@ -614,8 +640,7 @@ pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[proc_macro_derive(EnumSerialize, attributes(enumscribe))] #[proc_macro_derive(EnumSerialize, attributes(enumscribe))]
pub fn derive_enum_serialize(input: TokenStream) -> TokenStream { pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
let input: DeriveInput = syn::parse(input) let input: DeriveInput = syn::parse(input).expect("failed to parse input");
.expect("failed to parse input");
let enum_data = proc_try!(get_enum_data(&input)); let enum_data = proc_try!(get_enum_data(&input));
let parsed_enum = proc_try!(enums::parse_enum(enum_data)); let parsed_enum = proc_try!(enums::parse_enum(enum_data));
@ -632,7 +657,9 @@ pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
match &variant.v_type { match &variant.v_type {
VariantType::Ignore => ignore_variant = true, VariantType::Ignore => ignore_variant = true,
VariantType::Named { name, constructor, .. } => { VariantType::Named {
name, constructor, ..
} => {
let constructor_tokens = constructor.empty(); let constructor_tokens = constructor.empty();
match_arms.push(quote! { match_arms.push(quote! {
#enum_ident::#variant_ident #constructor_tokens => #enum_ident::#variant_ident #constructor_tokens =>
@ -640,23 +667,19 @@ pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
}) })
} }
VariantType::Other { field_name } => { VariantType::Other { field_name } => match field_name {
match field_name { Some(field_name) => match_arms.push(quote! {
Some(field_name) => { #enum_ident::#variant_ident { #field_name } =>
match_arms.push(quote! { #serializer_ident.serialize_str(&#field_name)
#enum_ident::#variant_ident { #field_name } => }),
#serializer_ident.serialize_str(&#field_name) None => {
}) let field_name = quote! { __enumscribe_other_inner };
} match_arms.push(quote! {
None => { #enum_ident::#variant_ident(#field_name) =>
let field_name = quote! { __enumscribe_other_inner }; #serializer_ident.serialize_str(&#field_name)
match_arms.push(quote! { })
#enum_ident::#variant_ident(#field_name) =>
#serializer_ident.serialize_str(&#field_name)
})
}
} }
} },
} }
} }
@ -685,7 +708,8 @@ pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
} }
} }
} }
}).into() })
.into()
} }
/// Derives `serde::Deserialize` for an enum. /// Derives `serde::Deserialize` for an enum.
@ -707,8 +731,7 @@ pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[proc_macro_derive(EnumDeserialize, attributes(enumscribe))] #[proc_macro_derive(EnumDeserialize, attributes(enumscribe))]
pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream { pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
let input: DeriveInput = syn::parse(input) let input: DeriveInput = syn::parse(input).expect("failed to parse input");
.expect("failed to parse input");
let enum_data = proc_try!(get_enum_data(&input)); let enum_data = proc_try!(get_enum_data(&input));
let parsed_enum = proc_try!(enums::parse_enum(enum_data)); let parsed_enum = proc_try!(enums::parse_enum(enum_data));
@ -719,10 +742,12 @@ pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
let deserialized_string_ident = quote! { __enumscribe_deserialized_string }; let deserialized_string_ident = quote! { __enumscribe_deserialized_string };
let deserialized_str_ident = quote! { __enumscribe_deserialized_str }; let deserialized_str_ident = quote! { __enumscribe_deserialized_str };
let variant_strings = parsed_enum.variants.iter() let variant_strings = parsed_enum
.variants
.iter()
.map(|variant| match &variant.v_type { .map(|variant| match &variant.v_type {
VariantType::Named { name, .. } => Some(name.as_str()), VariantType::Named { name, .. } => Some(name.as_str()),
_ => None _ => None,
}) })
.filter(|name| name.is_some()) .filter(|name| name.is_some())
.map(|name| name.unwrap()) .map(|name| name.unwrap())
@ -759,18 +784,32 @@ pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
#main_match #main_match
} }
} }
}).into() })
.into()
} }
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> { fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
let enum_data = match &input.data { let enum_data = match &input.data {
Data::Enum(enum_data) => enum_data, Data::Enum(enum_data) => enum_data,
Data::Struct(_) => return Err(MacroError::new("enumscribe cannot be used for structs", input.ident.span())), Data::Struct(_) => {
Data::Union(_) => return Err(MacroError::new("enumscribe cannot be used for unions", input.ident.span())) return Err(MacroError::new(
"enumscribe cannot be used for structs",
input.ident.span(),
))
}
Data::Union(_) => {
return Err(MacroError::new(
"enumscribe cannot be used for unions",
input.ident.span(),
))
}
}; };
if enum_data.variants.is_empty() { if enum_data.variants.is_empty() {
return Err(MacroError::new("enumscribe cannot be used for empty enums", input.ident.span())); return Err(MacroError::new(
"enumscribe cannot be used for empty enums",
input.ident.span(),
));
} }
Ok(enum_data) Ok(enum_data)

@ -39,12 +39,16 @@ fn main() {
let info = AirportInfo { let info = AirportInfo {
airport: Airport::Gatwick(), airport: Airport::Gatwick(),
info: "It's somewhere in London, innit".to_owned() info: "It's somewhere in London, innit".to_owned(),
}; };
println!("{}", serde_json::to_string(&info).unwrap()); println!("{}", serde_json::to_string(&info).unwrap());
println!(); println!();
let info_str = r#"{ "airport": "lgw", "info": "Fun Gatwick fact: I'm fresh out of Gatwick facts" }"#; let info_str =
println!("{:?}", serde_json::from_str::<AirportInfo>(info_str).unwrap()); r#"{ "airport": "lgw", "info": "Fun Gatwick fact: I'm fresh out of Gatwick facts" }"#;
println!(
"{:?}",
serde_json::from_str::<AirportInfo>(info_str).unwrap()
);
} }

@ -45,7 +45,7 @@ fn case_insensitivity_example() {
fn other_example() { fn other_example() {
use std::borrow::Cow; use std::borrow::Cow;
use enumscribe::{Unscribe, ScribeCowStr}; use enumscribe::{ScribeCowStr, Unscribe};
#[derive(ScribeCowStr, Unscribe, PartialEq, Eq, Debug)] #[derive(ScribeCowStr, Unscribe, PartialEq, Eq, Debug)]
enum Website { enum Website {
@ -61,12 +61,21 @@ fn other_example() {
assert_eq!(Website::unscribe("github.com"), Website::Github); assert_eq!(Website::unscribe("github.com"), Website::Github);
// Unbelievably, there exist websites other than github and crates.io // Unbelievably, there exist websites other than github and crates.io
assert_eq!(Website::unscribe("stackoverflow.com"), Website::Other("stackoverflow.com".to_owned())); assert_eq!(
Website::unscribe("stackoverflow.com"),
Website::Other("stackoverflow.com".to_owned())
);
// We can't scribe to a &'static str anymore, so we use a Cow<'static, str> instead // We can't scribe to a &'static str anymore, so we use a Cow<'static, str> instead
assert_eq!(Website::Github.scribe(), Cow::Borrowed::<'static, str>("github.com")); assert_eq!(
Website::Github.scribe(),
assert_eq!(Website::Other("owasp.org".to_owned()).scribe(), Cow::Owned::<'static, str>("owasp.org".to_owned())); Cow::Borrowed::<'static, str>("github.com")
);
assert_eq!(
Website::Other("owasp.org".to_owned()).scribe(),
Cow::Owned::<'static, str>("owasp.org".to_owned())
);
} }
fn ignore_example() { fn ignore_example() {
@ -90,9 +99,9 @@ fn ignore_example() {
} }
fn serde_example() { fn serde_example() {
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use enumscribe::{EnumSerialize, EnumDeserialize}; use enumscribe::{EnumDeserialize, EnumSerialize};
#[derive(EnumSerialize, EnumDeserialize, PartialEq, Eq, Clone, Copy, Debug)] #[derive(EnumSerialize, EnumDeserialize, PartialEq, Eq, Clone, Copy, Debug)]
enum Airport { enum Airport {
@ -118,7 +127,10 @@ fn serde_example() {
let flight_json = r#"{"takeoff":"LHR","landing":"LGW"}"#; let flight_json = r#"{"takeoff":"LHR","landing":"LGW"}"#;
assert_eq!(serde_json::to_string(&flight).unwrap(), flight_json.to_owned()); assert_eq!(
serde_json::to_string(&flight).unwrap(),
flight_json.to_owned()
);
assert_eq!(serde_json::from_str::<Flight>(flight_json).unwrap(), flight); assert_eq!(serde_json::from_str::<Flight>(flight_json).unwrap(), flight);
} }

@ -1,17 +1,12 @@
use std::borrow::Cow; use std::borrow::Cow;
use enumscribe::{ use enumscribe::{
ScribeCowStr, ScribeCowStr, ScribeStaticStr, ScribeString, TryScribeCowStr, TryScribeStaticStr,
ScribeStaticStr,
ScribeString,
TryScribeCowStr,
TryScribeStaticStr,
TryScribeString, TryScribeString,
}; };
const TEST_STRINGS: [&'static str; 6] = [ const TEST_STRINGS: [&'static str; 6] =
"", "\0", "foo", "baa", "Hello, world!", "こんにちは、世界" ["", "\0", "foo", "baa", "Hello, world!", "こんにちは、世界"];
];
#[test] #[test]
fn test_scribe_static_str() { fn test_scribe_static_str() {
@ -54,7 +49,10 @@ fn test_try_scribe_static_str() {
#[enumscribe(ignore)] #[enumscribe(ignore)]
V7(i32, i32), V7(i32, i32),
#[enumscribe(ignore)] #[enumscribe(ignore)]
V8 { s: &'static str, x: i32 }, V8 {
s: &'static str,
x: i32,
},
} }
assert_eq!(E0::V0.try_scribe(), Some("V0")); assert_eq!(E0::V0.try_scribe(), Some("V0"));
@ -65,7 +63,14 @@ fn test_try_scribe_static_str() {
assert_eq!(E0::V5 {}.try_scribe(), Some("baz")); assert_eq!(E0::V5 {}.try_scribe(), Some("baz"));
assert_eq!(E0::V6.try_scribe(), None); assert_eq!(E0::V6.try_scribe(), None);
assert_eq!(E0::V7(123, 456).try_scribe(), None); assert_eq!(E0::V7(123, 456).try_scribe(), None);
assert_eq!(E0::V8 { s: "lorem ipsum", x: 246 }.try_scribe(), None); assert_eq!(
E0::V8 {
s: "lorem ipsum",
x: 246
}
.try_scribe(),
None
);
} }
#[test] #[test]
@ -135,7 +140,10 @@ fn test_try_scribe_string() {
#[enumscribe(ignore)] #[enumscribe(ignore)]
V7(i32, i32), V7(i32, i32),
#[enumscribe(ignore)] #[enumscribe(ignore)]
V8 { s: &'static str, x: i32 }, V8 {
s: &'static str,
x: i32,
},
} }
assert_eq!(E0::V0.try_scribe(), Some("V0".to_owned())); assert_eq!(E0::V0.try_scribe(), Some("V0".to_owned()));
@ -146,7 +154,14 @@ fn test_try_scribe_string() {
assert_eq!(E0::V5 {}.try_scribe(), Some("baz".to_owned())); assert_eq!(E0::V5 {}.try_scribe(), Some("baz".to_owned()));
assert_eq!(E0::V6.try_scribe(), None); assert_eq!(E0::V6.try_scribe(), None);
assert_eq!(E0::V7(123, 456).try_scribe(), None); assert_eq!(E0::V7(123, 456).try_scribe(), None);
assert_eq!(E0::V8 { s: "lorem ipsum", x: 246 }.try_scribe(), None); assert_eq!(
E0::V8 {
s: "lorem ipsum",
x: 246
}
.try_scribe(),
None
);
#[derive(TryScribeString, Eq, PartialEq, Debug)] #[derive(TryScribeString, Eq, PartialEq, Debug)]
enum E1 { enum E1 {
@ -213,7 +228,10 @@ fn test_scribe_cow_str() {
assert_eq!(E1::V0.scribe(), Cow::Borrowed("foo")); assert_eq!(E1::V0.scribe(), Cow::Borrowed("foo"));
for &x in &TEST_STRINGS { for &x in &TEST_STRINGS {
assert_eq!(E1::V1(x.to_owned()).scribe(), Cow::Owned::<'static, str>(x.to_owned())); assert_eq!(
E1::V1(x.to_owned()).scribe(),
Cow::Owned::<'static, str>(x.to_owned())
);
} }
#[derive(ScribeCowStr, Eq, PartialEq, Debug)] #[derive(ScribeCowStr, Eq, PartialEq, Debug)]
@ -226,7 +244,10 @@ fn test_scribe_cow_str() {
assert_eq!(E2::V0.scribe(), "foo".to_owned()); assert_eq!(E2::V0.scribe(), "foo".to_owned());
for &x in &TEST_STRINGS { for &x in &TEST_STRINGS {
assert_eq!(E2::V1 { s: x.to_owned() }.scribe(), Cow::Owned::<'static, str>(x.to_owned())); assert_eq!(
E2::V1 { s: x.to_owned() }.scribe(),
Cow::Owned::<'static, str>(x.to_owned())
);
} }
} }
@ -248,7 +269,10 @@ fn test_try_scribe_cow_str() {
#[enumscribe(ignore)] #[enumscribe(ignore)]
V7(i32, i32), V7(i32, i32),
#[enumscribe(ignore)] #[enumscribe(ignore)]
V8 { s: &'static str, x: i32 }, V8 {
s: &'static str,
x: i32,
},
} }
assert_eq!(E0::V0.try_scribe(), Some(Cow::Borrowed("V0"))); assert_eq!(E0::V0.try_scribe(), Some(Cow::Borrowed("V0")));
@ -259,7 +283,14 @@ fn test_try_scribe_cow_str() {
assert_eq!(E0::V5 {}.try_scribe(), Some(Cow::Borrowed("baz"))); assert_eq!(E0::V5 {}.try_scribe(), Some(Cow::Borrowed("baz")));
assert_eq!(E0::V6.try_scribe(), None); assert_eq!(E0::V6.try_scribe(), None);
assert_eq!(E0::V7(123, 456).try_scribe(), None); assert_eq!(E0::V7(123, 456).try_scribe(), None);
assert_eq!(E0::V8 { s: "lorem ipsum", x: 246 }.try_scribe(), None); assert_eq!(
E0::V8 {
s: "lorem ipsum",
x: 246
}
.try_scribe(),
None
);
#[derive(TryScribeCowStr, Eq, PartialEq, Debug)] #[derive(TryScribeCowStr, Eq, PartialEq, Debug)]
enum E1 { enum E1 {
@ -273,7 +304,10 @@ fn test_try_scribe_cow_str() {
assert_eq!(E1::V0.try_scribe(), Some(Cow::Borrowed("foo"))); assert_eq!(E1::V0.try_scribe(), Some(Cow::Borrowed("foo")));
for &x in &TEST_STRINGS { for &x in &TEST_STRINGS {
assert_eq!(E1::V1(x.to_owned()).try_scribe(), Some(Cow::Owned::<'static, str>(x.to_owned()))); assert_eq!(
E1::V1(x.to_owned()).try_scribe(),
Some(Cow::Owned::<'static, str>(x.to_owned()))
);
} }
assert_eq!(E1::V2.try_scribe(), None); assert_eq!(E1::V2.try_scribe(), None);
@ -289,7 +323,10 @@ fn test_try_scribe_cow_str() {
assert_eq!(E2::V0.try_scribe(), Some(Cow::Borrowed("foo"))); assert_eq!(E2::V0.try_scribe(), Some(Cow::Borrowed("foo")));
for &x in &TEST_STRINGS { for &x in &TEST_STRINGS {
assert_eq!(E2::V1 { s: x.to_owned() }.try_scribe(), Some(Cow::Owned::<'static, str>(x.to_owned()))); assert_eq!(
E2::V1 { s: x.to_owned() }.try_scribe(),
Some(Cow::Owned::<'static, str>(x.to_owned()))
);
} }
assert_eq!(E2::V2.try_scribe(), None); assert_eq!(E2::V2.try_scribe(), None);
} }

@ -279,24 +279,42 @@ fn test_try_unscribe() {
assert_eq!(E1::try_unscribe("loREM"), Some(E1::V7)); assert_eq!(E1::try_unscribe("loREM"), Some(E1::V7));
assert_eq!(E1::try_unscribe("larem"), Some(E1::V12("larem".to_owned()))); assert_eq!(E1::try_unscribe("larem"), Some(E1::V12("larem".to_owned())));
assert_eq!(E1::try_unscribe("lore"), Some(E1::V12("lore".to_owned()))); assert_eq!(E1::try_unscribe("lore"), Some(E1::V12("lore".to_owned())));
assert_eq!(E1::try_unscribe("llorem"), Some(E1::V12("llorem".to_owned()))); assert_eq!(
assert_eq!(E1::try_unscribe("loremm"), Some(E1::V12("loremm".to_owned()))); E1::try_unscribe("llorem"),
Some(E1::V12("llorem".to_owned()))
);
assert_eq!(
E1::try_unscribe("loremm"),
Some(E1::V12("loremm".to_owned()))
);
assert_eq!(E1::try_unscribe("ipsum"), Some(E1::V9())); assert_eq!(E1::try_unscribe("ipsum"), Some(E1::V9()));
assert_eq!(E1::try_unscribe("IPSUM"), Some(E1::V9())); assert_eq!(E1::try_unscribe("IPSUM"), Some(E1::V9()));
assert_eq!(E1::try_unscribe("IpSuM"), Some(E1::V9())); assert_eq!(E1::try_unscribe("IpSuM"), Some(E1::V9()));
assert_eq!(E1::try_unscribe("ipSUM"), Some(E1::V9())); assert_eq!(E1::try_unscribe("ipSUM"), Some(E1::V9()));
assert_eq!(E1::try_unscribe("ipdum"), Some(E1::V12("ipdum".to_owned()))); assert_eq!(E1::try_unscribe("ipdum"), Some(E1::V12("ipdum".to_owned())));
assert_eq!(E1::try_unscribe("ipsu"), Some(E1::V12("ipsu".to_owned()))); assert_eq!(E1::try_unscribe("ipsu"), Some(E1::V12("ipsu".to_owned())));
assert_eq!(E1::try_unscribe("iipsum"), Some(E1::V12("iipsum".to_owned()))); assert_eq!(
assert_eq!(E1::try_unscribe("ipsumm"), Some(E1::V12("ipsumm".to_owned()))); E1::try_unscribe("iipsum"),
Some(E1::V12("iipsum".to_owned()))
);
assert_eq!(
E1::try_unscribe("ipsumm"),
Some(E1::V12("ipsumm".to_owned()))
);
assert_eq!(E1::try_unscribe("dolor"), Some(E1::V11 {})); assert_eq!(E1::try_unscribe("dolor"), Some(E1::V11 {}));
assert_eq!(E1::try_unscribe("DOLOR"), Some(E1::V11 {})); assert_eq!(E1::try_unscribe("DOLOR"), Some(E1::V11 {}));
assert_eq!(E1::try_unscribe("DoLoR"), Some(E1::V11 {})); assert_eq!(E1::try_unscribe("DoLoR"), Some(E1::V11 {}));
assert_eq!(E1::try_unscribe("doLOR"), Some(E1::V11 {})); assert_eq!(E1::try_unscribe("doLOR"), Some(E1::V11 {}));
assert_eq!(E1::try_unscribe("doler"), Some(E1::V12("doler".to_owned()))); assert_eq!(E1::try_unscribe("doler"), Some(E1::V12("doler".to_owned())));
assert_eq!(E1::try_unscribe("dolo"), Some(E1::V12("dolo".to_owned()))); assert_eq!(E1::try_unscribe("dolo"), Some(E1::V12("dolo".to_owned())));
assert_eq!(E1::try_unscribe("ddolor"), Some(E1::V12("ddolor".to_owned()))); assert_eq!(
assert_eq!(E1::try_unscribe("dolorr"), Some(E1::V12("dolorr".to_owned()))); E1::try_unscribe("ddolor"),
Some(E1::V12("ddolor".to_owned()))
);
assert_eq!(
E1::try_unscribe("dolorr"),
Some(E1::V12("dolorr".to_owned()))
);
assert_eq!(E1::try_unscribe(""), Some(E1::V12("".to_owned()))); assert_eq!(E1::try_unscribe(""), Some(E1::V12("".to_owned())));
assert_eq!(E1::try_unscribe("\0"), Some(E1::V12("\0".to_owned()))); assert_eq!(E1::try_unscribe("\0"), Some(E1::V12("\0".to_owned())));
} }

Loading…
Cancel
Save