From a3137d86c2c3af2af584228b036a6c1f6782c77f Mon Sep 17 00:00:00 2001 From: pantonshire Date: Sat, 18 Nov 2023 16:08:37 +0000 Subject: [PATCH] rename and rename_all attributes --- enumscribe_derive/src/enums.rs | 45 ++++++++++++++-------- enumscribe_derive/src/lib.rs | 2 + enumscribe_derive/src/rename.rs | 2 +- enumscribe_examples/examples/rename_all.rs | 21 ++++++++++ 4 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 enumscribe_examples/examples/rename_all.rs diff --git a/enumscribe_derive/src/enums.rs b/enumscribe_derive/src/enums.rs index 7e9da6e..f095d14 100644 --- a/enumscribe_derive/src/enums.rs +++ b/enumscribe_derive/src/enums.rs @@ -7,8 +7,9 @@ use syn::{DataEnum, Fields, Attribute}; use crate::attribute::{Dict, Value}; use crate::error::{MacroError, MacroResult}; +use crate::rename::RenameVariant; use crate::{TokenStream2, CASE_SENSITIVE}; -use crate::{CASE_INSENSITIVE, CRATE_ATTR, IGNORE, NAME, OTHER}; +use crate::{CASE_INSENSITIVE, RENAME, RENAME_ALL, CRATE_ATTR, IGNORE, NAME, OTHER}; #[derive(Clone)] pub(crate) struct Enum<'a> { @@ -192,19 +193,20 @@ pub(crate) fn parse_enum<'a>(data: &'a DataEnum, attrs: &'a [Attribute]) -> Macr 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, - )?; + let mut global_dict = Dict::from_attrs(CRATE_ATTR, attrs)?; + + let (global_case_insensitive, _) = global_dict.remove_typed_or_default( + CASE_INSENSITIVE, + (false, data.enum_token.span()), + Value::value_bool, + )?; - dict.assert_empty()?; + let global_rename = global_dict.remove_typed(RENAME_ALL, Value::value_string)? + .map(|(global_rename, span)| RenameVariant::from_str(&global_rename, span)) + .transpose()?; - global_case_insensitive - }; + global_dict.assert_empty()?; + drop(global_dict); for variant in data.variants.iter() { let variant_span = variant.span(); @@ -213,10 +215,7 @@ pub(crate) fn parse_enum<'a>(data: &'a DataEnum, attrs: &'a [Attribute]) -> Macr 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 name_opt = dict.remove_typed(NAME, Value::value_string)?; let (other, other_span) = dict.remove_typed_or_default( OTHER, @@ -257,6 +256,11 @@ pub(crate) fn parse_enum<'a>(data: &'a DataEnum, attrs: &'a [Attribute]) -> Macr } }; + let rename = dict.remove_typed(RENAME, Value::value_string)? + .map(|(rename, span)| RenameVariant::from_str(&rename, span)) + .transpose()? + .or(global_rename); + // Return an error if there are any unrecognised keys in the Dict dict.assert_empty()?; @@ -318,7 +322,14 @@ pub(crate) fn parse_enum<'a>(data: &'a DataEnum, attrs: &'a [Attribute]) -> Macr // Use the str name if one is provided, otherwise use the variant's name let (name, name_span) = match name_opt { Some((name, name_span)) => (name, name_span), - None => (variant.ident.to_string(), variant.ident.span()), + None => { + let name_span = variant.ident.span(); + let mut name = variant.ident.to_string(); + if let Some(rename) = rename { + name = rename.apply(&name); + } + (name, name_span) + }, }; // Do not allow duplicate names diff --git a/enumscribe_derive/src/lib.rs b/enumscribe_derive/src/lib.rs index efc3d39..7f5a595 100644 --- a/enumscribe_derive/src/lib.rs +++ b/enumscribe_derive/src/lib.rs @@ -28,6 +28,8 @@ const OTHER: &'static str = "other"; const IGNORE: &'static str = "ignore"; const CASE_INSENSITIVE: &'static str = "case_insensitive"; const CASE_SENSITIVE: &'static str = "case_sensitive"; +const RENAME: &'static str = "rename"; +const RENAME_ALL: &'static str = "rename_all"; type TokenStream2 = proc_macro2::TokenStream; diff --git a/enumscribe_derive/src/rename.rs b/enumscribe_derive/src/rename.rs index 546dfe5..911d434 100644 --- a/enumscribe_derive/src/rename.rs +++ b/enumscribe_derive/src/rename.rs @@ -20,7 +20,7 @@ impl RenameVariant { match s { "lowercase" => Ok(Self::Lower), "UPPERCASE" => Ok(Self::Upper), - "PascalCase" => Ok(Self::Upper), + "PascalCase" => Ok(Self::Pascal), "camelCase" => Ok(Self::Camel), "snake_case" => Ok(Self::Snake), "SCREAMING_SNAKE_CASE" => Ok(Self::ScreamingSnake), diff --git a/enumscribe_examples/examples/rename_all.rs b/enumscribe_examples/examples/rename_all.rs new file mode 100644 index 0000000..7749cdb --- /dev/null +++ b/enumscribe_examples/examples/rename_all.rs @@ -0,0 +1,21 @@ +use enumscribe::*; + +#[derive(ScribeStaticStr, TryUnscribe, PartialEq, Eq, Debug)] +#[enumscribe(rename_all = "snake_case")] +enum Bird { + BlackRedstart, + #[enumscribe(case_insensitive)] + GardenWarbler, + #[enumscribe(rename = "SCREAMING-KEBAB-CASE")] + BarnacleGoose, +} + +fn main() { + assert_eq!(Bird::BlackRedstart.scribe(), "black_redstart"); + assert_eq!(Bird::GardenWarbler.scribe(), "garden_warbler"); + assert_eq!(Bird::BarnacleGoose.scribe(), "BARNACLE-GOOSE"); + + assert_eq!(Bird::try_unscribe("black_redstart").unwrap(), Bird::BlackRedstart); + assert_eq!(Bird::try_unscribe("gArDeN_wArBlEr").unwrap(), Bird::GardenWarbler); + assert_eq!(Bird::try_unscribe("BARNACLE-GOOSE").unwrap(), Bird::BarnacleGoose); +}