Implement container-level case_insensitive from issue #1
This commit is contained in:
1 parent
d0da42b9b7
commit
8c078040ac
3 files changed
+106
-24
No files matched your search
@@ -3,11 +3,11 @@ use std::collections::HashSet;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{DataEnum, Fields};
|
||||
use syn::{DataEnum, Fields, Attribute};
|
||||
|
||||
use crate::attribute::{Dict, Value};
|
||||
use crate::error::{MacroError, MacroResult};
|
||||
use crate::TokenStream2;
|
||||
use crate::{TokenStream2, CASE_SENSITIVE};
|
||||
use crate::{CASE_INSENSITIVE, CRATE_ATTR, IGNORE, NAME, OTHER};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -94,13 +94,27 @@ impl VariantConstructor {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
|
||||
pub(crate) fn parse_enum<'a>(data: &'a DataEnum, attrs: &'a [Attribute]) -> MacroResult<Enum<'a>> {
|
||||
let mut variants = Vec::with_capacity(data.variants.len());
|
||||
let mut taken_names = HashSet::new();
|
||||
let mut taken_insensitive_names = HashSet::new();
|
||||
let mut taken_sensitive_names = HashSet::new();
|
||||
let mut other_variant = false;
|
||||
|
||||
let global_case_insensitive = {
|
||||
let mut dict = Dict::from_attrs(CRATE_ATTR, attrs)?;
|
||||
|
||||
let (global_case_insensitive, _) = dict.remove_typed_or_default(
|
||||
CASE_INSENSITIVE,
|
||||
(false, data.enum_token.span()),
|
||||
Value::value_bool,
|
||||
)?;
|
||||
|
||||
dict.assert_empty()?;
|
||||
|
||||
global_case_insensitive
|
||||
};
|
||||
|
||||
for variant in data.variants.iter() {
|
||||
let variant_span = variant.span();
|
||||
|
||||
@@ -108,17 +122,50 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
|
||||
let mut dict = Dict::from_attrs(CRATE_ATTR, &variant.attrs)?;
|
||||
|
||||
// Convert the values in the Dict to the appropriate types
|
||||
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 (ignore, _) =
|
||||
dict.remove_typed_or_default(IGNORE, (false, variant_span), Value::value_bool)?;
|
||||
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 (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,
|
||||
)?;
|
||||
|
||||
let (case_sensitive, case_sensitive_span) = dict.remove_typed_or_default(
|
||||
CASE_SENSITIVE,
|
||||
(false, variant_span),
|
||||
Value::value_bool
|
||||
)?;
|
||||
|
||||
let case_insensitive = match (case_insensitive, case_sensitive) {
|
||||
(false, false) => global_case_insensitive,
|
||||
(false, true) => false,
|
||||
(true, false) => true,
|
||||
(true, true) => {
|
||||
return Err(MacroError::new(
|
||||
format!(
|
||||
"variant {} cannot be both case_insensitive and case_sensitive",
|
||||
variant.ident,
|
||||
),
|
||||
case_sensitive_span,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
// Return an error if there are any unrecognised keys in the Dict
|
||||
dict.assert_empty()?;
|
||||
|
||||
@@ -247,4 +294,4 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
|
||||
}
|
||||
|
||||
Ok(Enum { variants })
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ use proc_macro::TokenStream;
|
||||
|
||||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use syn::{Data, DataEnum, DeriveInput};
|
||||
use syn::{Data, DataEnum, DeriveInput, Attribute};
|
||||
|
||||
use error::{MacroError, MacroResult};
|
||||
|
||||
@@ -26,6 +26,7 @@ const NAME: &'static str = "str";
|
||||
const OTHER: &'static str = "other";
|
||||
const IGNORE: &'static str = "ignore";
|
||||
const CASE_INSENSITIVE: &'static str = "case_insensitive";
|
||||
const CASE_SENSITIVE: &'static str = "case_sensitive";
|
||||
|
||||
type TokenStream2 = proc_macro2::TokenStream;
|
||||
|
||||
@@ -53,8 +54,8 @@ where
|
||||
{
|
||||
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_data, enum_attrs) = proc_try!(get_enum_data(&input));
|
||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data, enum_attrs));
|
||||
|
||||
let enum_ident = &input.ident;
|
||||
|
||||
@@ -95,8 +96,8 @@ where
|
||||
{
|
||||
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_data, enum_attrs) = proc_try!(get_enum_data(&input));
|
||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data, enum_attrs));
|
||||
|
||||
let enum_ident = &input.ident;
|
||||
|
||||
@@ -147,8 +148,8 @@ where
|
||||
{
|
||||
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_data, enum_attrs) = proc_try!(get_enum_data(&input));
|
||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data, enum_attrs));
|
||||
|
||||
let enum_ident = &input.ident;
|
||||
|
||||
@@ -645,8 +646,8 @@ pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
|
||||
pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
|
||||
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_data, enum_attrs) = proc_try!(get_enum_data(&input));
|
||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data, enum_attrs));
|
||||
|
||||
let enum_ident = &input.ident;
|
||||
let serializer_ident = quote! { __enumscribe_serializer };
|
||||
@@ -737,8 +738,8 @@ pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
|
||||
pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
|
||||
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_data, enum_attrs) = proc_try!(get_enum_data(&input));
|
||||
let parsed_enum = proc_try!(enums::parse_enum(enum_data, enum_attrs));
|
||||
|
||||
let enum_ident = &input.ident;
|
||||
|
||||
@@ -792,7 +793,7 @@ pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
|
||||
.into()
|
||||
}
|
||||
|
||||
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
|
||||
fn get_enum_data(input: &DeriveInput) -> MacroResult<(&DataEnum, &[Attribute])> {
|
||||
let enum_data = match &input.data {
|
||||
Data::Enum(enum_data) => enum_data,
|
||||
Data::Struct(_) => {
|
||||
@@ -816,5 +817,5 @@ fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
|
||||
));
|
||||
}
|
||||
|
||||
Ok(enum_data)
|
||||
Ok((enum_data, &input.attrs))
|
||||
}
|
||||
Reference in new issue
Block a user