Implement container-level case_insensitive from issue #1

This commit is contained in:
pantonshire committed 2023-02-08 11:10:48 +00:00
1 parent d0da42b9b7
commit 8c078040ac
3 files changed
+106 -24

No files matched your search

+56 -9
View File
@@ -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 })
}
}
+14 -13
View File
@@ -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))
}