|
|
|
|
@ -14,10 +14,10 @@ use syn::{Data, DataEnum, DeriveInput};
|
|
|
|
|
|
|
|
|
|
use error::{MacroError, MacroResult};
|
|
|
|
|
|
|
|
|
|
use crate::enums::{Variant, VariantType, Enum};
|
|
|
|
|
use crate::enums::{Enum, Variant, VariantType};
|
|
|
|
|
|
|
|
|
|
mod enums;
|
|
|
|
|
mod attribute;
|
|
|
|
|
mod enums;
|
|
|
|
|
mod error;
|
|
|
|
|
|
|
|
|
|
const CRATE_ATTR: &'static str = "enumscribe";
|
|
|
|
|
@ -33,7 +33,7 @@ macro_rules! proc_try {
|
|
|
|
|
($x:expr) => {
|
|
|
|
|
match $x {
|
|
|
|
|
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,
|
|
|
|
|
ignore_err_fn: E,
|
|
|
|
|
) -> TokenStream
|
|
|
|
|
where
|
|
|
|
|
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
|
|
|
|
|
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>,
|
|
|
|
|
E: Fn(&Variant, &Ident) -> MacroError
|
|
|
|
|
where
|
|
|
|
|
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
|
|
|
|
|
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>,
|
|
|
|
|
E: Fn(&Variant, &Ident) -> MacroError,
|
|
|
|
|
{
|
|
|
|
|
let input: DeriveInput = syn::parse(input)
|
|
|
|
|
.expect("failed to parse input");
|
|
|
|
|
let input: DeriveInput = syn::parse(input).expect("failed to parse input");
|
|
|
|
|
|
|
|
|
|
let enum_data = proc_try!(get_enum_data(&input));
|
|
|
|
|
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) {
|
|
|
|
|
Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }),
|
|
|
|
|
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>(
|
|
|
|
|
@ -88,12 +88,11 @@ fn gen_try_scribe_impl<F, G>(
|
|
|
|
|
other_fn: G,
|
|
|
|
|
ignore_result: TokenStream2,
|
|
|
|
|
) -> TokenStream
|
|
|
|
|
where
|
|
|
|
|
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
|
|
|
|
|
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>
|
|
|
|
|
where
|
|
|
|
|
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
|
|
|
|
|
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>,
|
|
|
|
|
{
|
|
|
|
|
let input: DeriveInput = syn::parse(input)
|
|
|
|
|
.expect("failed to parse input");
|
|
|
|
|
let input: DeriveInput = syn::parse(input).expect("failed to parse input");
|
|
|
|
|
|
|
|
|
|
let enum_data = proc_try!(get_enum_data(&input));
|
|
|
|
|
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) {
|
|
|
|
|
Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }),
|
|
|
|
|
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>(
|
|
|
|
|
@ -138,13 +138,12 @@ fn gen_unscribe_impl<F, G, E>(
|
|
|
|
|
other_fn: G,
|
|
|
|
|
other_missing_fn: E,
|
|
|
|
|
) -> TokenStream
|
|
|
|
|
where
|
|
|
|
|
F: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
G: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
E: Fn(&Ident) -> MacroResult<TokenStream2>
|
|
|
|
|
where
|
|
|
|
|
F: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
G: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
E: Fn(&Ident) -> MacroResult<TokenStream2>,
|
|
|
|
|
{
|
|
|
|
|
let input: DeriveInput = syn::parse(input)
|
|
|
|
|
.expect("failed to parse input");
|
|
|
|
|
let input: DeriveInput = syn::parse(input).expect("failed to parse input");
|
|
|
|
|
|
|
|
|
|
let enum_data = proc_try!(get_enum_data(&input));
|
|
|
|
|
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 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! {
|
|
|
|
|
@ -163,7 +167,8 @@ fn gen_unscribe_impl<F, G, E>(
|
|
|
|
|
#main_match
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}).into()
|
|
|
|
|
})
|
|
|
|
|
.into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
@ -174,10 +179,10 @@ fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
other_fn: G,
|
|
|
|
|
other_missing_fn: E,
|
|
|
|
|
) -> MacroResult<TokenStream2>
|
|
|
|
|
where
|
|
|
|
|
F: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
G: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
E: Fn(&Ident) -> MacroResult<TokenStream2>
|
|
|
|
|
where
|
|
|
|
|
F: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
G: Fn(TokenStream2) -> TokenStream2,
|
|
|
|
|
E: Fn(&Ident) -> MacroResult<TokenStream2>,
|
|
|
|
|
{
|
|
|
|
|
let mut other_arm = None;
|
|
|
|
|
let mut case_sensitive_arms = Vec::new();
|
|
|
|
|
@ -189,7 +194,11 @@ fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
match &variant.v_type {
|
|
|
|
|
VariantType::Ignore => (),
|
|
|
|
|
|
|
|
|
|
VariantType::Named { name, constructor, case_insensitive } => {
|
|
|
|
|
VariantType::Named {
|
|
|
|
|
name,
|
|
|
|
|
constructor,
|
|
|
|
|
case_insensitive,
|
|
|
|
|
} => {
|
|
|
|
|
let match_pattern = if *case_insensitive {
|
|
|
|
|
let lowercase_name = name.to_lowercase();
|
|
|
|
|
quote! { #lowercase_name }
|
|
|
|
|
@ -198,18 +207,21 @@ fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if *case_insensitive {
|
|
|
|
|
&mut case_insensitive_arms
|
|
|
|
|
} else {
|
|
|
|
|
&mut case_sensitive_arms
|
|
|
|
|
}.push(quote! { #match_pattern => #match_result });
|
|
|
|
|
}
|
|
|
|
|
.push(quote! { #match_pattern => #match_result });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
None => quote! {
|
|
|
|
|
@ -217,7 +229,7 @@ fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
},
|
|
|
|
|
Some(field_name) => quote! {
|
|
|
|
|
#enum_ident::#variant_ident { #field_name: #unscribe_value }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let match_result = other_fn(constructed_variant);
|
|
|
|
|
@ -229,7 +241,7 @@ fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
|
|
|
|
|
let other_arm = match 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() {
|
|
|
|
|
@ -258,16 +270,14 @@ fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
(true, Some(case_insensitive_match)) => {
|
|
|
|
|
case_insensitive_match
|
|
|
|
|
}
|
|
|
|
|
(true, Some(case_insensitive_match)) => case_insensitive_match,
|
|
|
|
|
|
|
|
|
|
(false, Some(case_insensitive_match)) => quote! {
|
|
|
|
|
match #match_against {
|
|
|
|
|
#(#case_sensitive_arms,)*
|
|
|
|
|
_ => { #case_insensitive_match },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(main_match)
|
|
|
|
|
@ -301,26 +311,32 @@ fn gen_unscribe_match<F, G, E>(
|
|
|
|
|
pub fn derive_scribe_static_str(input: TokenStream) -> TokenStream {
|
|
|
|
|
gen_scribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::ScribeStaticStr },
|
|
|
|
|
quote! { &'static str },
|
|
|
|
|
|
|
|
|
|
|_, _, name| Ok(quote! { #name }),
|
|
|
|
|
|
|
|
|
|
|variant, enum_ident, _| Err(MacroError::new(format!(
|
|
|
|
|
"cannot derive ScribeStaticStr for {} because the variant {} is marked as {}, so \
|
|
|
|
|
there is no &'static str associated with it\n\
|
|
|
|
|
hint: try deriving ScribeCowStr instead",
|
|
|
|
|
enum_ident, variant.data.ident, OTHER
|
|
|
|
|
), variant.span)),
|
|
|
|
|
|
|
|
|
|
|variant, enum_ident| MacroError::new(format!(
|
|
|
|
|
"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),
|
|
|
|
|
|variant, enum_ident, _| {
|
|
|
|
|
Err(MacroError::new(
|
|
|
|
|
format!(
|
|
|
|
|
"cannot derive ScribeStaticStr for {} because the variant {} is marked as {}, so \
|
|
|
|
|
there is no &'static str associated with it\n\
|
|
|
|
|
hint: try deriving ScribeCowStr instead",
|
|
|
|
|
enum_ident, variant.data.ident, OTHER
|
|
|
|
|
),
|
|
|
|
|
variant.span,
|
|
|
|
|
))
|
|
|
|
|
},
|
|
|
|
|
|variant, enum_ident| {
|
|
|
|
|
MacroError::new(
|
|
|
|
|
format!(
|
|
|
|
|
"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 {
|
|
|
|
|
gen_try_scribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::TryScribeStaticStr },
|
|
|
|
|
quote! { ::std::option::Option<&'static str> },
|
|
|
|
|
|
|
|
|
|
|_, _, name| Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(#name)
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|variant, enum_ident, _| Err(MacroError::new(format!(
|
|
|
|
|
"cannot derive TryScribeStaticStr for {} because the variant {} is marked as {}, so \
|
|
|
|
|
there is no &'static str associated with it\n\
|
|
|
|
|
hint: try deriving TryScribeCowStr instead",
|
|
|
|
|
enum_ident, variant.data.ident, OTHER
|
|
|
|
|
), variant.span)),
|
|
|
|
|
|
|
|
|
|
|_, _, name| {
|
|
|
|
|
Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(#name)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|variant, enum_ident, _| {
|
|
|
|
|
Err(MacroError::new(
|
|
|
|
|
format!(
|
|
|
|
|
"cannot derive TryScribeStaticStr for {} because the variant {} is marked as {}, so \
|
|
|
|
|
there is no &'static str associated with it\n\
|
|
|
|
|
hint: try deriving TryScribeCowStr instead",
|
|
|
|
|
enum_ident, variant.data.ident, OTHER
|
|
|
|
|
),
|
|
|
|
|
variant.span,
|
|
|
|
|
))
|
|
|
|
|
},
|
|
|
|
|
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 {
|
|
|
|
|
gen_scribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::ScribeString },
|
|
|
|
|
quote! { ::std::string::String },
|
|
|
|
|
|
|
|
|
|
|_, _, name| Ok(quote! {
|
|
|
|
|
<_ as ::std::borrow::ToOwned>::to_owned(#name)
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|_, _, 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\
|
|
|
|
|
explanation: since {} is ignored, it cannot be guaranteed that the enum can \
|
|
|
|
|
always be successfully converted to a String\n\
|
|
|
|
|
hint: try deriving TryScribeString instead",
|
|
|
|
|
enum_ident, variant.data.ident, IGNORE, variant.data.ident
|
|
|
|
|
), variant.span),
|
|
|
|
|
|_, _, name| {
|
|
|
|
|
Ok(quote! {
|
|
|
|
|
<_ as ::std::borrow::ToOwned>::to_owned(#name)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|_, _, 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\
|
|
|
|
|
explanation: since {} is ignored, it cannot be guaranteed that the enum can \
|
|
|
|
|
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 {
|
|
|
|
|
gen_try_scribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::TryScribeString },
|
|
|
|
|
quote! { ::std::option::Option<::std::string::String> },
|
|
|
|
|
|
|
|
|
|
|_, _, name| Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(
|
|
|
|
|
<_ as ::std::borrow::ToOwned>::to_owned(#name)
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|_, _, field| Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(
|
|
|
|
|
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|_, _, name| {
|
|
|
|
|
Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(
|
|
|
|
|
<_ as ::std::borrow::ToOwned>::to_owned(#name)
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|_, _, field| {
|
|
|
|
|
Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(
|
|
|
|
|
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
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 {
|
|
|
|
|
gen_scribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::ScribeCowStr },
|
|
|
|
|
quote! { ::std::borrow::Cow<'static, str> },
|
|
|
|
|
|
|
|
|
|
|_, _, name| Ok(quote! {
|
|
|
|
|
::std::borrow::Cow::Borrowed(#name)
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|_, _, field| Ok(quote! {
|
|
|
|
|
::std::borrow::Cow::Owned(
|
|
|
|
|
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
|
|
|
|
|_, _, name| {
|
|
|
|
|
Ok(quote! {
|
|
|
|
|
::std::borrow::Cow::Borrowed(#name)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|_, _, field| {
|
|
|
|
|
Ok(quote! {
|
|
|
|
|
::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 {
|
|
|
|
|
gen_try_scribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::TryScribeCowStr },
|
|
|
|
|
quote! { ::std::option::Option<::std::borrow::Cow<'static, str>> },
|
|
|
|
|
|
|
|
|
|
|_, _, name| Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(
|
|
|
|
|
::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)
|
|
|
|
|
|_, _, name| {
|
|
|
|
|
Ok(quote! {
|
|
|
|
|
::std::option::Option::Some(
|
|
|
|
|
::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)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
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 {
|
|
|
|
|
gen_unscribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::Unscribe },
|
|
|
|
|
quote! { unscribe },
|
|
|
|
|
quote! { Self },
|
|
|
|
|
|
|
|
|
|
|constructed_named_variant| constructed_named_variant,
|
|
|
|
|
|
|
|
|
|
|constructed_other_variant| constructed_other_variant,
|
|
|
|
|
|
|
|
|
|
|enum_ident| Err(MacroError::new(format!(
|
|
|
|
|
"cannot derive Unscribe for {} because no variant is marked as {}\n\
|
|
|
|
|
explanation: since there is no {} variant, it cannot be guaranteed that every string \
|
|
|
|
|
can be successfully converted to a variant of {}\n\
|
|
|
|
|
hint: either introduce an {} variant, or try deriving TryUnscribe instead",
|
|
|
|
|
enum_ident, OTHER, OTHER, enum_ident, OTHER
|
|
|
|
|
), enum_ident.span())),
|
|
|
|
|
|enum_ident| {
|
|
|
|
|
Err(MacroError::new(
|
|
|
|
|
format!(
|
|
|
|
|
"cannot derive Unscribe for {} because no variant is marked as {}\n\
|
|
|
|
|
explanation: since there is no {} variant, it cannot be guaranteed that every string \
|
|
|
|
|
can be successfully converted to a variant of {}\n\
|
|
|
|
|
hint: either introduce an {} variant, or try deriving TryUnscribe instead",
|
|
|
|
|
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 {
|
|
|
|
|
gen_unscribe_impl(
|
|
|
|
|
input,
|
|
|
|
|
|
|
|
|
|
quote! { ::enumscribe::TryUnscribe },
|
|
|
|
|
quote! { try_unscribe },
|
|
|
|
|
quote! { ::std::option::Option<Self> },
|
|
|
|
|
|
|
|
|
|
|constructed_named_variant| quote! { ::std::option::Option::Some(#constructed_named_variant) },
|
|
|
|
|
|
|
|
|
|
|constructed_other_variant| quote! { ::std::option::Option::Some(#constructed_other_variant) },
|
|
|
|
|
|
|
|
|
|
|_| Ok(quote! { _ => ::std::option::Option::None }),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
@ -614,8 +640,7 @@ pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
|
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
|
#[proc_macro_derive(EnumSerialize, attributes(enumscribe))]
|
|
|
|
|
pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
|
|
|
|
|
let input: DeriveInput = syn::parse(input)
|
|
|
|
|
.expect("failed to parse input");
|
|
|
|
|
let input: DeriveInput = syn::parse(input).expect("failed to parse input");
|
|
|
|
|
|
|
|
|
|
let enum_data = proc_try!(get_enum_data(&input));
|
|
|
|
|
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 {
|
|
|
|
|
VariantType::Ignore => ignore_variant = true,
|
|
|
|
|
|
|
|
|
|
VariantType::Named { name, constructor, .. } => {
|
|
|
|
|
VariantType::Named {
|
|
|
|
|
name, constructor, ..
|
|
|
|
|
} => {
|
|
|
|
|
let constructor_tokens = constructor.empty();
|
|
|
|
|
match_arms.push(quote! {
|
|
|
|
|
#enum_ident::#variant_ident #constructor_tokens =>
|
|
|
|
|
@ -640,23 +667,19 @@ pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VariantType::Other { field_name } => {
|
|
|
|
|
match field_name {
|
|
|
|
|
Some(field_name) => {
|
|
|
|
|
match_arms.push(quote! {
|
|
|
|
|
#enum_ident::#variant_ident { #field_name } =>
|
|
|
|
|
#serializer_ident.serialize_str(&#field_name)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
let field_name = quote! { __enumscribe_other_inner };
|
|
|
|
|
match_arms.push(quote! {
|
|
|
|
|
#enum_ident::#variant_ident(#field_name) =>
|
|
|
|
|
#serializer_ident.serialize_str(&#field_name)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
VariantType::Other { field_name } => match field_name {
|
|
|
|
|
Some(field_name) => match_arms.push(quote! {
|
|
|
|
|
#enum_ident::#variant_ident { #field_name } =>
|
|
|
|
|
#serializer_ident.serialize_str(&#field_name)
|
|
|
|
|
}),
|
|
|
|
|
None => {
|
|
|
|
|
let field_name = quote! { __enumscribe_other_inner };
|
|
|
|
|
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.
|
|
|
|
|
@ -707,8 +731,7 @@ pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
|
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
|
#[proc_macro_derive(EnumDeserialize, attributes(enumscribe))]
|
|
|
|
|
pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
|
|
|
|
|
let input: DeriveInput = syn::parse(input)
|
|
|
|
|
.expect("failed to parse input");
|
|
|
|
|
let input: DeriveInput = syn::parse(input).expect("failed to parse input");
|
|
|
|
|
|
|
|
|
|
let enum_data = proc_try!(get_enum_data(&input));
|
|
|
|
|
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_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 {
|
|
|
|
|
VariantType::Named { name, .. } => Some(name.as_str()),
|
|
|
|
|
_ => None
|
|
|
|
|
_ => None,
|
|
|
|
|
})
|
|
|
|
|
.filter(|name| name.is_some())
|
|
|
|
|
.map(|name| name.unwrap())
|
|
|
|
|
@ -759,18 +784,32 @@ pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
|
|
|
|
|
#main_match
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}).into()
|
|
|
|
|
})
|
|
|
|
|
.into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
|
|
|
|
|
let enum_data = match &input.data {
|
|
|
|
|
Data::Enum(enum_data) => enum_data,
|
|
|
|
|
Data::Struct(_) => 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()))
|
|
|
|
|
Data::Struct(_) => {
|
|
|
|
|
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() {
|
|
|
|
|
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)
|
|
|
|
|
|