Derive for TryUnscribe
This commit is contained in:
1 parent
8f7f76d8ba
commit
867b09a1fe
2 files changed
+200
-171
No files matched your search
+192
-163
@@ -34,7 +34,7 @@ macro_rules! proc_try {
|
||||
};
|
||||
}
|
||||
|
||||
fn derive_scribe<F, G, E>(
|
||||
fn gen_scribe_impl<F, G, E>(
|
||||
input: TokenStream,
|
||||
trait_ident: TokenStream2,
|
||||
trait_return_type: TokenStream2,
|
||||
@@ -76,7 +76,7 @@ fn derive_scribe<F, G, E>(
|
||||
}).into()
|
||||
}
|
||||
|
||||
fn derive_try_scribe<F, G>(
|
||||
fn gen_try_scribe_impl<F, G>(
|
||||
input: TokenStream,
|
||||
trait_ident: TokenStream2,
|
||||
trait_return_type: TokenStream2,
|
||||
@@ -125,141 +125,20 @@ fn derive_try_scribe<F, G>(
|
||||
}).into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ScribeStaticStr, attributes(enumscribe))]
|
||||
pub fn derive_scribe_static_str(input: TokenStream) -> TokenStream {
|
||||
derive_scribe(
|
||||
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.to_string(), variant.data.ident.to_string(), 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.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||
variant.data.ident.to_string(),
|
||||
), variant.span),
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryScribeStaticStr, attributes(enumscribe))]
|
||||
pub fn derive_try_scribe_static_str(input: TokenStream) -> TokenStream {
|
||||
derive_try_scribe(
|
||||
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.to_string(), variant.data.ident.to_string(), OTHER
|
||||
), variant.span)),
|
||||
quote! { ::std::option::Option::None },
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ScribeString, attributes(enumscribe))]
|
||||
pub fn derive_scribe_string(input: TokenStream) -> TokenStream {
|
||||
derive_scribe(
|
||||
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.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||
variant.data.ident.to_string(),
|
||||
), variant.span),
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryScribeString, attributes(enumscribe))]
|
||||
pub fn derive_try_scribe_string(input: TokenStream) -> TokenStream {
|
||||
derive_try_scribe(
|
||||
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)
|
||||
)
|
||||
}),
|
||||
quote! { ::std::option::Option::None },
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ScribeCowStr, attributes(enumscribe))]
|
||||
pub fn derive_scribe_cow_str(input: TokenStream) -> TokenStream {
|
||||
derive_scribe(
|
||||
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)
|
||||
)
|
||||
}),
|
||||
|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.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||
variant.data.ident.to_string(),
|
||||
), variant.span),
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryScribeCowStr, attributes(enumscribe))]
|
||||
pub fn derive_try_scribe_cow_str(input: TokenStream) -> TokenStream {
|
||||
derive_try_scribe(
|
||||
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)
|
||||
)
|
||||
)
|
||||
}),
|
||||
quote! { ::std::option::Option::None },
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Unscribe, attributes(enumscribe))]
|
||||
pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
fn gen_unscribe_impl<F, G, E>(
|
||||
input: TokenStream,
|
||||
trait_ident: TokenStream2,
|
||||
trait_fn_name: TokenStream2,
|
||||
trait_return_type: TokenStream2,
|
||||
named_fn: F,
|
||||
other_fn: G,
|
||||
other_missing_fn: E
|
||||
) -> TokenStream
|
||||
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");
|
||||
|
||||
@@ -268,7 +147,6 @@ pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
|
||||
let enum_ident = &input.ident;
|
||||
|
||||
let mut all_ignored = true;
|
||||
let mut other_arm = None;
|
||||
let mut case_sensitive_arms = Vec::new();
|
||||
let mut case_insensitive_arms = Vec::new();
|
||||
@@ -282,8 +160,6 @@ pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
VariantType::Ignore => (),
|
||||
|
||||
VariantType::Named { name, constructor, case_insensitive } => {
|
||||
all_ignored = false;
|
||||
|
||||
let match_pattern = if *case_insensitive {
|
||||
let lowercase_name = name.to_lowercase();
|
||||
quote! { #lowercase_name }
|
||||
@@ -292,7 +168,8 @@ pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
};
|
||||
|
||||
let constructor_tokens = constructor.empty();
|
||||
let match_result = 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
|
||||
@@ -302,11 +179,9 @@ pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
VariantType::Other { field_name } => {
|
||||
all_ignored = false;
|
||||
|
||||
let unscribe_value = quote! { <_ as ::std::convert::Into<_>>::into(#to_unscribe_ident) };
|
||||
|
||||
let match_result = match field_name {
|
||||
let constructed_variant = match field_name {
|
||||
None => quote! {
|
||||
#enum_ident::#variant_ident(#unscribe_value)
|
||||
},
|
||||
@@ -315,28 +190,16 @@ pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
};
|
||||
|
||||
let match_result = other_fn(constructed_variant);
|
||||
|
||||
other_arm = Some(quote! { _ => #match_result })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if all_ignored {
|
||||
return MacroError::new(format!(
|
||||
"cannot derive Unscribe for {} because all variants are marked as {}\n\
|
||||
hint: introduce at least one variant that is not marked as {}",
|
||||
enum_ident.to_string(), IGNORE, IGNORE
|
||||
), enum_ident.span()).into()
|
||||
}
|
||||
|
||||
let other_arm = match other_arm {
|
||||
Some(other_arm) => other_arm,
|
||||
None => return 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.to_string(), OTHER, OTHER, enum_ident.to_string(), OTHER
|
||||
), enum_ident.span()).into()
|
||||
None => proc_try!(other_missing_fn(enum_ident))
|
||||
};
|
||||
|
||||
let case_insensitive_match = if case_insensitive_arms.is_empty() {
|
||||
@@ -378,19 +241,185 @@ pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
};
|
||||
|
||||
(quote! {
|
||||
impl ::enumscribe::Unscribe for #enum_ident {
|
||||
fn unscribe(#to_unscribe_ident: &str) -> Self {
|
||||
impl #trait_ident for #enum_ident {
|
||||
fn #trait_fn_name(#to_unscribe_ident: &str) -> #trait_return_type {
|
||||
#main_match
|
||||
}
|
||||
}
|
||||
}).into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ScribeStaticStr, attributes(enumscribe))]
|
||||
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.to_string(), variant.data.ident.to_string(), 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.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||
variant.data.ident.to_string(),
|
||||
), variant.span),
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryScribeStaticStr, attributes(enumscribe))]
|
||||
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.to_string(), variant.data.ident.to_string(), OTHER
|
||||
), variant.span)),
|
||||
quote! { ::std::option::Option::None },
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ScribeString, attributes(enumscribe))]
|
||||
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.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||
variant.data.ident.to_string(),
|
||||
), variant.span),
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryScribeString, attributes(enumscribe))]
|
||||
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)
|
||||
)
|
||||
}),
|
||||
quote! { ::std::option::Option::None },
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ScribeCowStr, attributes(enumscribe))]
|
||||
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)
|
||||
)
|
||||
}),
|
||||
|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.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||
variant.data.ident.to_string(),
|
||||
), variant.span),
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryScribeCowStr, attributes(enumscribe))]
|
||||
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)
|
||||
)
|
||||
)
|
||||
}),
|
||||
quote! { ::std::option::Option::None },
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Unscribe, attributes(enumscribe))]
|
||||
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.to_string(), OTHER, OTHER, enum_ident.to_string(), OTHER
|
||||
), enum_ident.span()))
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryUnscribe, attributes(enumscribe))]
|
||||
pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
|
||||
//TODO: make sure at least one variant is non-ignore
|
||||
gen_unscribe_impl(
|
||||
input,
|
||||
|
||||
todo!()
|
||||
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 })
|
||||
)
|
||||
}
|
||||
|
||||
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
|
||||
|
||||
Reference in new issue
Block a user