Cleanup
This commit is contained in:
1 parent
fce589369b
commit
ed83ffc5f3
4 files changed
+215
-284
No files matched your search
@@ -116,10 +116,10 @@ pub trait TryScribeCowStr {
|
|||||||
fn try_scribe(&self) -> Option<Cow<'static, str>>;
|
fn try_scribe(&self) -> Option<Cow<'static, str>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Unscribe {
|
pub trait Unscribe: Sized {
|
||||||
fn unscribe(to_unscribe: &str) -> Self;
|
fn unscribe(to_unscribe: &str) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TryUnscribe {
|
pub trait TryUnscribe: Sized {
|
||||||
fn try_unscribe(to_unscribe: &str) -> Option<Self>;
|
fn try_unscribe(to_unscribe: &str) -> Option<Self>;
|
||||||
}
|
}
|
||||||
@@ -42,10 +42,15 @@ pub(crate) enum VariantConstructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Variant<'a> {
|
impl<'a> Variant<'a> {
|
||||||
pub(crate) fn match_variant<F, G>(&self, named_fn: F, other_fn: G) -> MacroResult<Option<(TokenStream, TokenStream)>>
|
pub(crate) fn match_variant<F, G>(
|
||||||
|
&self,
|
||||||
|
enum_ident: &Ident,
|
||||||
|
named_fn: &F,
|
||||||
|
other_fn: &G
|
||||||
|
) -> MacroResult<Option<(TokenStream, TokenStream)>>
|
||||||
where
|
where
|
||||||
F: Fn(&str) -> MacroResult<TokenStream>,
|
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream>,
|
||||||
G: Fn(TokenStream) -> MacroResult<TokenStream>
|
G: Fn(&Variant, &Ident, TokenStream) -> MacroResult<TokenStream>
|
||||||
{
|
{
|
||||||
let variant_ident = &self.data.ident;
|
let variant_ident = &self.data.ident;
|
||||||
|
|
||||||
@@ -54,11 +59,11 @@ impl<'a> Variant<'a> {
|
|||||||
|
|
||||||
VariantType::Named { name, constructor, .. } => {
|
VariantType::Named { name, constructor, .. } => {
|
||||||
let pattern = match constructor {
|
let pattern = match constructor {
|
||||||
VariantConstructor::None => quote! { #variant_ident },
|
VariantConstructor::None => quote! { #enum_ident::#variant_ident },
|
||||||
VariantConstructor::Paren => quote! { #variant_ident () },
|
VariantConstructor::Paren => quote! { #enum_ident::#variant_ident() },
|
||||||
VariantConstructor::Brace => quote! { #variant_ident {} }
|
VariantConstructor::Brace => quote! { #enum_ident::#variant_ident{} }
|
||||||
};
|
};
|
||||||
Ok(Some((pattern, named_fn(name)?)))
|
Ok(Some((pattern, named_fn(self, enum_ident, name)?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantType::Other { field_name } => {
|
VariantType::Other { field_name } => {
|
||||||
@@ -67,10 +72,10 @@ impl<'a> Variant<'a> {
|
|||||||
None => quote! { __enumscribe_other_inner }
|
None => quote! { __enumscribe_other_inner }
|
||||||
};
|
};
|
||||||
let pattern = match field_name {
|
let pattern = match field_name {
|
||||||
Some(_) => quote! { #variant_ident { #field_name_tokens } },
|
Some(_) => quote! { #enum_ident::#variant_ident{#field_name_tokens} },
|
||||||
None => quote! { #variant_ident (#field_name_tokens) }
|
None => quote! { #enum_ident::#variant_ident(#field_name_tokens) }
|
||||||
};
|
};
|
||||||
Ok(Some((pattern, other_fn(field_name_tokens)?)))
|
Ok(Some((pattern, other_fn(self, enum_ident, field_name_tokens)?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+193
-265
@@ -9,6 +9,9 @@ use syn::{Data, DataEnum, DeriveInput};
|
|||||||
|
|
||||||
use error::{MacroError, MacroResult};
|
use error::{MacroError, MacroResult};
|
||||||
|
|
||||||
|
use crate::enums::Variant;
|
||||||
|
use proc_macro2::Ident;
|
||||||
|
|
||||||
mod enums;
|
mod enums;
|
||||||
mod attribute;
|
mod attribute;
|
||||||
mod error;
|
mod error;
|
||||||
@@ -20,6 +23,8 @@ const OTHER: &'static str = "other";
|
|||||||
const IGNORE: &'static str = "ignore";
|
const IGNORE: &'static str = "ignore";
|
||||||
const CASE_INSENSITIVE: &'static str = "case_insensitive";
|
const CASE_INSENSITIVE: &'static str = "case_insensitive";
|
||||||
|
|
||||||
|
type TokenStream2 = proc_macro2::TokenStream;
|
||||||
|
|
||||||
macro_rules! proc_try {
|
macro_rules! proc_try {
|
||||||
($x:expr) => {
|
($x:expr) => {
|
||||||
match $x {
|
match $x {
|
||||||
@@ -29,8 +34,19 @@ macro_rules! proc_try {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(ScribeStaticStr, attributes(enumscribe))]
|
fn derive_scribe<F, G, E>(
|
||||||
pub fn derive_scribe_static_str(input: TokenStream) -> TokenStream {
|
input: TokenStream,
|
||||||
|
trait_ident: TokenStream2,
|
||||||
|
trait_return_type: TokenStream2,
|
||||||
|
named_fn: F,
|
||||||
|
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
|
||||||
|
{
|
||||||
let input: DeriveInput = syn::parse(input)
|
let input: DeriveInput = syn::parse(input)
|
||||||
.expect("failed to parse input");
|
.expect("failed to parse input");
|
||||||
|
|
||||||
@@ -38,328 +54,240 @@ pub fn derive_scribe_static_str(input: TokenStream) -> TokenStream {
|
|||||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
||||||
|
|
||||||
let enum_ident = &input.ident;
|
let enum_ident = &input.ident;
|
||||||
let enum_idents = iter::repeat(enum_ident);
|
|
||||||
|
|
||||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
||||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
||||||
|
|
||||||
for variant in parsed_enum.variants.iter() {
|
for variant in parsed_enum.variants.iter() {
|
||||||
match variant.match_variant(
|
match variant.match_variant(enum_ident, &named_fn, &other_fn) {
|
||||||
|name| Ok(quote! {
|
|
||||||
#name
|
|
||||||
}),
|
|
||||||
|_| 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)),
|
|
||||||
) {
|
|
||||||
Ok(Some((pattern, result))) => {
|
Ok(Some((pattern, result))) => {
|
||||||
match_patterns.push(pattern);
|
match_patterns.push(pattern);
|
||||||
match_results.push(result);
|
match_results.push(result);
|
||||||
},
|
}
|
||||||
|
Ok(None) => return ignore_err_fn(variant, enum_ident).into(),
|
||||||
Ok(None) => return 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).into(),
|
|
||||||
|
|
||||||
Err(err) => return err.into()
|
Err(err) => return err.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(quote! {
|
(quote! {
|
||||||
impl ::enumscribe::ScribeStaticStr for #enum_ident {
|
impl #trait_ident for #enum_ident {
|
||||||
fn scribe(&self) -> &'static str {
|
fn scribe(&self) -> #trait_return_type {
|
||||||
match self {
|
match self {
|
||||||
#(#enum_idents::#match_patterns => #match_results,)*
|
#(#match_patterns => #match_results,)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).into()
|
}).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn derive_try_scribe<F, G>(
|
||||||
|
input: TokenStream,
|
||||||
|
trait_ident: TokenStream2,
|
||||||
|
trait_return_type: TokenStream2,
|
||||||
|
named_fn: F,
|
||||||
|
other_fn: G,
|
||||||
|
ignore_result: TokenStream2
|
||||||
|
) -> TokenStream
|
||||||
|
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 enum_data = proc_try!(get_enum_data(&input));
|
||||||
|
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
||||||
|
|
||||||
|
let enum_ident = &input.ident;
|
||||||
|
|
||||||
|
let mut ignore_variant = false;
|
||||||
|
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
||||||
|
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
||||||
|
|
||||||
|
for variant in parsed_enum.variants.iter() {
|
||||||
|
match variant.match_variant(enum_ident, &named_fn, &other_fn) {
|
||||||
|
Ok(Some((pattern, result))) => {
|
||||||
|
match_patterns.push(pattern);
|
||||||
|
match_results.push(result);
|
||||||
|
}
|
||||||
|
Ok(None) => ignore_variant = true,
|
||||||
|
Err(err) => return err.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ignore_arm = if ignore_variant {
|
||||||
|
quote! { _ => #ignore_result, }
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
(quote! {
|
||||||
|
impl #trait_ident for #enum_ident {
|
||||||
|
fn try_scribe(&self) -> #trait_return_type {
|
||||||
|
match self {
|
||||||
|
#(#match_patterns => #match_results,)*
|
||||||
|
#ignore_arm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).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))]
|
#[proc_macro_derive(TryScribeStaticStr, attributes(enumscribe))]
|
||||||
pub fn derive_try_scribe_static_str(input: TokenStream) -> TokenStream {
|
pub fn derive_try_scribe_static_str(input: TokenStream) -> TokenStream {
|
||||||
let input: DeriveInput = syn::parse(input)
|
derive_try_scribe(
|
||||||
.expect("failed to parse input");
|
input,
|
||||||
|
|
||||||
let enum_data = proc_try!(get_enum_data(&input));
|
quote! { ::enumscribe::TryScribeStaticStr },
|
||||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
quote! { ::std::option::Option<&'static str> },
|
||||||
|
|
||||||
let enum_ident = &input.ident;
|
|_, _, name| Ok(quote! {
|
||||||
let enum_idents = iter::repeat(enum_ident);
|
::std::option::Option::Some(#name)
|
||||||
|
}),
|
||||||
|
|
||||||
let mut ignore_variant = false;
|
|variant, enum_ident, _| Err(MacroError::new(format!(
|
||||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
"cannot derive TryScribeStaticStr for {} because the variant {} is marked as {}, so \
|
||||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
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)),
|
||||||
|
|
||||||
for variant in parsed_enum.variants.iter() {
|
quote! { ::std::option::Option::None }
|
||||||
match variant.match_variant(
|
)
|
||||||
|name| Ok(quote! {
|
|
||||||
::std::option::Option::Some(#name)
|
|
||||||
}),
|
|
||||||
|_| 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 ScribeCowStr instead",
|
|
||||||
enum_ident.to_string(), variant.data.ident.to_string(), OTHER
|
|
||||||
), variant.span)),
|
|
||||||
) {
|
|
||||||
Ok(Some((pattern, result))) => {
|
|
||||||
match_patterns.push(pattern);
|
|
||||||
match_results.push(result);
|
|
||||||
},
|
|
||||||
|
|
||||||
Ok(None) => ignore_variant = true,
|
|
||||||
|
|
||||||
Err(err) => return err.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ignore_arm = if ignore_variant {
|
|
||||||
quote! { _ => ::std::option::Option::None, }
|
|
||||||
} else {
|
|
||||||
quote! {}
|
|
||||||
};
|
|
||||||
|
|
||||||
(quote! {
|
|
||||||
impl ::enumscribe::TryScribeStaticStr for #enum_ident {
|
|
||||||
fn try_scribe(&self) -> ::std::option::Option<&'static str> {
|
|
||||||
match self {
|
|
||||||
#(#enum_idents::#match_patterns => #match_results,)*
|
|
||||||
#ignore_arm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(ScribeString, attributes(enumscribe))]
|
#[proc_macro_derive(ScribeString, attributes(enumscribe))]
|
||||||
pub fn derive_scribe_string(input: TokenStream) -> TokenStream {
|
pub fn derive_scribe_string(input: TokenStream) -> TokenStream {
|
||||||
let input: DeriveInput = syn::parse(input)
|
derive_scribe(
|
||||||
.expect("failed to parse input");
|
input,
|
||||||
|
|
||||||
let enum_data = proc_try!(get_enum_data(&input));
|
quote! { ::enumscribe::ScribeString },
|
||||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
quote! { ::std::string::String },
|
||||||
|
|
||||||
let enum_ident = &input.ident;
|
|_, _, name| Ok(quote! {
|
||||||
let enum_idents = iter::repeat(enum_ident);
|
<_ as ::std::borrow::ToOwned>::to_owned(#name)
|
||||||
|
}),
|
||||||
|
|
||||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
|_, _, field| Ok(quote! {
|
||||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
||||||
|
}),
|
||||||
|
|
||||||
for variant in parsed_enum.variants.iter() {
|
|variant, enum_ident| MacroError::new(format!(
|
||||||
match variant.match_variant(
|
"cannot derive ScribeString for {} because the variant {} is marked as {}\n\
|
||||||
|name| Ok(quote! {
|
explanation: since {} is ignored, it cannot be guaranteed that the enum can \
|
||||||
<_ as ::std::borrow::ToOwned>::to_owned(#name)
|
always be successfully converted to a String\n\
|
||||||
}),
|
hint: try deriving TryScribeString instead",
|
||||||
|field| Ok(quote! {
|
enum_ident.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||||
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
variant.data.ident.to_string(),
|
||||||
}),
|
), variant.span)
|
||||||
) {
|
)
|
||||||
Ok(Some((pattern, result))) => {
|
|
||||||
match_patterns.push(pattern);
|
|
||||||
match_results.push(result);
|
|
||||||
},
|
|
||||||
|
|
||||||
Ok(None) => return 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).into(),
|
|
||||||
|
|
||||||
Err(err) => return err.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(quote! {
|
|
||||||
impl ::enumscribe::ScribeString for #enum_ident {
|
|
||||||
fn scribe(&self) -> ::std::string::String {
|
|
||||||
match self {
|
|
||||||
#(#enum_idents::#match_patterns => #match_results,)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(TryScribeString, attributes(enumscribe))]
|
#[proc_macro_derive(TryScribeString, attributes(enumscribe))]
|
||||||
pub fn derive_try_scribe_string(input: TokenStream) -> TokenStream {
|
pub fn derive_try_scribe_string(input: TokenStream) -> TokenStream {
|
||||||
let input: DeriveInput = syn::parse(input)
|
derive_try_scribe(
|
||||||
.expect("failed to parse input");
|
input,
|
||||||
|
|
||||||
let enum_data = proc_try!(get_enum_data(&input));
|
quote! { ::enumscribe::TryScribeString },
|
||||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
quote! { ::std::option::Option<::std::string::String> },
|
||||||
|
|
||||||
let enum_ident = &input.ident;
|
|_, _, name| Ok(quote! {
|
||||||
let enum_idents = iter::repeat(enum_ident);
|
::std::option::Option::Some(
|
||||||
|
<_ as ::std::borrow::ToOwned>::to_owned(#name)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
let mut ignore_variant = false;
|
|_, _, field| Ok(quote! {
|
||||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
::std::option::Option::Some(
|
||||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
for variant in parsed_enum.variants.iter() {
|
quote! { ::std::option::Option::None }
|
||||||
match variant.match_variant(
|
)
|
||||||
|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)
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
) {
|
|
||||||
Ok(Some((pattern, result))) => {
|
|
||||||
match_patterns.push(pattern);
|
|
||||||
match_results.push(result);
|
|
||||||
},
|
|
||||||
|
|
||||||
Ok(None) => ignore_variant = true,
|
|
||||||
|
|
||||||
Err(err) => return err.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ignore_arm = if ignore_variant {
|
|
||||||
quote! { _ => ::std::option::Option::None, }
|
|
||||||
} else {
|
|
||||||
quote! {}
|
|
||||||
};
|
|
||||||
|
|
||||||
(quote! {
|
|
||||||
impl ::enumscribe::TryScribeString for #enum_ident {
|
|
||||||
fn try_scribe(&self) -> ::std::option::Option<::std::string::String> {
|
|
||||||
match self {
|
|
||||||
#(#enum_idents::#match_patterns => #match_results,)*
|
|
||||||
#ignore_arm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(ScribeCowStr, attributes(enumscribe))]
|
#[proc_macro_derive(ScribeCowStr, attributes(enumscribe))]
|
||||||
pub fn derive_scribe_cow_str(input: TokenStream) -> TokenStream {
|
pub fn derive_scribe_cow_str(input: TokenStream) -> TokenStream {
|
||||||
let input: DeriveInput = syn::parse(input)
|
derive_scribe(
|
||||||
.expect("failed to parse input");
|
input,
|
||||||
|
|
||||||
let enum_data = proc_try!(get_enum_data(&input));
|
quote! { ::enumscribe::ScribeCowStr },
|
||||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
quote! { ::std::borrow::Cow<'static, str> },
|
||||||
|
|
||||||
let enum_ident = &input.ident;
|
|_, _, name| Ok(quote! {
|
||||||
let enum_idents = iter::repeat(enum_ident);
|
::std::borrow::Cow::Borrowed(#name)
|
||||||
|
}),
|
||||||
|
|
||||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
|_, _, field| Ok(quote! {
|
||||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
::std::borrow::Cow::Owned(
|
||||||
|
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
for variant in parsed_enum.variants.iter() {
|
|variant, enum_ident| MacroError::new(format!(
|
||||||
match variant.match_variant(
|
"cannot derive ScribeCowStr for {} because the variant {} is marked as {}\n\
|
||||||
|name| Ok(quote! {
|
explanation: since {} is ignored, it cannot be guaranteed that the enum can \
|
||||||
::std::borrow::Cow::Borrowed(#name)
|
always be successfully converted to a String\n\
|
||||||
}),
|
hint: try deriving TryScribeCowStr instead",
|
||||||
|field| Ok(quote! {
|
enum_ident.to_string(), variant.data.ident.to_string(), IGNORE,
|
||||||
::std::borrow::Cow::Owned(
|
variant.data.ident.to_string(),
|
||||||
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
), variant.span)
|
||||||
)
|
)
|
||||||
}),
|
|
||||||
) {
|
|
||||||
Ok(Some((pattern, result))) => {
|
|
||||||
match_patterns.push(pattern);
|
|
||||||
match_results.push(result);
|
|
||||||
},
|
|
||||||
|
|
||||||
Ok(None) => return 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).into(),
|
|
||||||
|
|
||||||
Err(err) => return err.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(quote! {
|
|
||||||
impl ::enumscribe::ScribeCowStr for #enum_ident {
|
|
||||||
fn scribe(&self) -> ::std::borrow::Cow<'static, str> {
|
|
||||||
match self {
|
|
||||||
#(#enum_idents::#match_patterns => #match_results,)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(TryScribeCowStr, attributes(enumscribe))]
|
#[proc_macro_derive(TryScribeCowStr, attributes(enumscribe))]
|
||||||
pub fn derive_try_scribe_cow_str(input: TokenStream) -> TokenStream {
|
pub fn derive_try_scribe_cow_str(input: TokenStream) -> TokenStream {
|
||||||
let input: DeriveInput = syn::parse(input)
|
derive_try_scribe(
|
||||||
.expect("failed to parse input");
|
input,
|
||||||
|
|
||||||
let enum_data = proc_try!(get_enum_data(&input));
|
quote! { ::enumscribe::TryScribeCowStr },
|
||||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
quote! { ::std::option::Option<::std::borrow::Cow<'static, str>> },
|
||||||
|
|
||||||
let enum_ident = &input.ident;
|
|_, _, name| Ok(quote! {
|
||||||
let enum_idents = iter::repeat(enum_ident);
|
::std::option::Option::Some(
|
||||||
|
::std::borrow::Cow::Borrowed(#name)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
let mut ignore_variant = false;
|
|_, _, field| Ok(quote! {
|
||||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
::std::option::Option::Some(
|
||||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
::std::borrow::Cow::Owned(
|
||||||
|
<_ as ::std::convert::Into<::std::string::String>>::into(#field)
|
||||||
for variant in parsed_enum.variants.iter() {
|
|
||||||
match variant.match_variant(
|
|
||||||
|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)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
) {
|
|
||||||
Ok(Some((pattern, result))) => {
|
|
||||||
match_patterns.push(pattern);
|
|
||||||
match_results.push(result);
|
|
||||||
},
|
|
||||||
|
|
||||||
Ok(None) => ignore_variant = true,
|
quote! { ::std::option::Option::None }
|
||||||
|
)
|
||||||
Err(err) => return err.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ignore_arm = if ignore_variant {
|
|
||||||
quote! { _ => ::std::option::Option::None, }
|
|
||||||
} else {
|
|
||||||
quote! {}
|
|
||||||
};
|
|
||||||
|
|
||||||
(quote! {
|
|
||||||
impl ::enumscribe::TryScribeCowStr for #enum_ident {
|
|
||||||
fn try_scribe(&self) -> ::std::option::Option<::std::borrow::Cow<'static, str>> {
|
|
||||||
match self {
|
|
||||||
#(#enum_idents::#match_patterns => #match_results,)*
|
|
||||||
#ignore_arm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
|
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use enumscribe::*;
|
use enumscribe::*;
|
||||||
|
|
||||||
// #[derive(ScribeString)]
|
#[derive(TryScribeCowStr)]
|
||||||
|
|
||||||
#[derive(TryScribeStaticStr)]
|
|
||||||
enum Airport {
|
enum Airport {
|
||||||
#[enumscribe(str = "LHR", case_insensitive)]
|
#[enumscribe(str = "LHR", case_insensitive)]
|
||||||
Heathrow,
|
Heathrow,
|
||||||
@@ -12,14 +10,14 @@ enum Airport {
|
|||||||
Luton,
|
Luton,
|
||||||
#[enumscribe(str = "BHX", case_insensitive, ignore)]
|
#[enumscribe(str = "BHX", case_insensitive, ignore)]
|
||||||
BirminghamInternational,
|
BirminghamInternational,
|
||||||
// #[enumscribe(other)]
|
#[enumscribe(other)]
|
||||||
// Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let luton = Airport::Luton;
|
let luton = Airport::Luton;
|
||||||
println!("Hello, {:?}!", luton.try_scribe());
|
println!("Hello, {:?}!", luton.try_scribe());
|
||||||
|
|
||||||
// let other = Airport::Other("Dedicated EasyJet-only airport".to_owned());
|
let other = Airport::Other("Dedicated EasyJet-only airport".to_owned());
|
||||||
// println!("Hello, {:?}!", other.try_scribe());
|
println!("Hello, {:?}!", other.try_scribe());
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user