Review follow-ups
This commit is contained in:
parent
0d29741b6f
commit
23ac36b559
|
@ -8,6 +8,10 @@ use std::ascii::AsciiExt;
|
||||||
|
|
||||||
use std::fmt::{self, Debug, Display};
|
use std::fmt::{self, Debug, Display};
|
||||||
|
|
||||||
|
use proc_macro2::Ident;
|
||||||
|
#[cfg(test)]
|
||||||
|
use proc_macro2::Span;
|
||||||
|
|
||||||
use self::RenameRule::*;
|
use self::RenameRule::*;
|
||||||
|
|
||||||
/// The different possible ways to change case of fields in a struct, or variants in an enum.
|
/// The different possible ways to change case of fields in a struct, or variants in an enum.
|
||||||
|
@ -42,7 +46,7 @@ impl Default for RenameRule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RENAME_RULES: &[(&str, RenameRule)] = &[
|
const RENAME_RULES: &[(&str, RenameRule)] = &[
|
||||||
("\"lowercase\"", LowerCase),
|
("\"lowercase\"", LowerCase),
|
||||||
("\"UPPERCASE\"", UpperCase),
|
("\"UPPERCASE\"", UpperCase),
|
||||||
("\"PascalCase\"", PascalCase),
|
("\"PascalCase\"", PascalCase),
|
||||||
|
@ -66,9 +70,10 @@ impl RenameRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
|
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
|
||||||
pub fn apply_to_variant(&self, variant: &str) -> String {
|
pub fn apply_to_variant(&self, ident: &Ident) -> String {
|
||||||
|
let variant = ident.to_string();
|
||||||
match *self {
|
match *self {
|
||||||
None | PascalCase => variant.to_owned(),
|
None | PascalCase => variant,
|
||||||
LowerCase => variant.to_ascii_lowercase(),
|
LowerCase => variant.to_ascii_lowercase(),
|
||||||
UpperCase => variant.to_ascii_uppercase(),
|
UpperCase => variant.to_ascii_uppercase(),
|
||||||
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
||||||
|
@ -82,18 +87,17 @@ impl RenameRule {
|
||||||
}
|
}
|
||||||
snake
|
snake
|
||||||
}
|
}
|
||||||
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
ScreamingSnakeCase => SnakeCase.apply_to_variant(ident).to_ascii_uppercase(),
|
||||||
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
KebabCase => SnakeCase.apply_to_variant(ident).replace('_', "-"),
|
||||||
ScreamingKebabCase => ScreamingSnakeCase
|
ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(ident).replace('_', "-"),
|
||||||
.apply_to_variant(variant)
|
|
||||||
.replace('_', "-"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a renaming rule to a struct field, returning the version expected in the source.
|
/// Apply a renaming rule to a struct field, returning the version expected in the source.
|
||||||
pub fn apply_to_field(&self, field: &str) -> String {
|
pub fn apply_to_field(&self, ident: &Ident) -> String {
|
||||||
|
let field = ident.to_string();
|
||||||
match *self {
|
match *self {
|
||||||
None | LowerCase | SnakeCase => field.to_owned(),
|
None | LowerCase | SnakeCase => field,
|
||||||
UpperCase => field.to_ascii_uppercase(),
|
UpperCase => field.to_ascii_uppercase(),
|
||||||
PascalCase => {
|
PascalCase => {
|
||||||
let mut pascal = String::new();
|
let mut pascal = String::new();
|
||||||
|
@ -111,12 +115,12 @@ impl RenameRule {
|
||||||
pascal
|
pascal
|
||||||
}
|
}
|
||||||
CamelCase => {
|
CamelCase => {
|
||||||
let pascal = PascalCase.apply_to_field(field);
|
let pascal = PascalCase.apply_to_field(ident);
|
||||||
pascal[..1].to_ascii_lowercase() + &pascal[1..]
|
pascal[..1].to_ascii_lowercase() + &pascal[1..]
|
||||||
}
|
}
|
||||||
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
||||||
KebabCase => field.replace('_', "-"),
|
KebabCase => field.replace('_', "-"),
|
||||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
|
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(ident).replace('_', "-"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +146,7 @@ impl<'a> Display for ParseError<'a> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rename_variants() {
|
fn rename_variants() {
|
||||||
for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
|
for &(name, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
|
||||||
(
|
(
|
||||||
"Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
"Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
||||||
),
|
),
|
||||||
|
@ -159,10 +163,12 @@ fn rename_variants() {
|
||||||
("A", "a", "A", "a", "a", "A", "a", "A"),
|
("A", "a", "A", "a", "a", "A", "a", "A"),
|
||||||
("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
|
("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||||
] {
|
] {
|
||||||
assert_eq!(None.apply_to_variant(original), original);
|
let original = &Ident::new(name, Span::call_site());
|
||||||
|
|
||||||
|
assert_eq!(None.apply_to_variant(original), name);
|
||||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||||
assert_eq!(UpperCase.apply_to_variant(original), upper);
|
assert_eq!(UpperCase.apply_to_variant(original), upper);
|
||||||
assert_eq!(PascalCase.apply_to_variant(original), original);
|
assert_eq!(PascalCase.apply_to_variant(original), name);
|
||||||
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
||||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||||
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
||||||
|
@ -176,7 +182,7 @@ fn rename_variants() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rename_fields() {
|
fn rename_fields() {
|
||||||
for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
|
for &(name, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
|
||||||
(
|
(
|
||||||
"outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
"outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
||||||
),
|
),
|
||||||
|
@ -192,11 +198,13 @@ fn rename_fields() {
|
||||||
("a", "A", "A", "a", "A", "a", "A"),
|
("a", "A", "A", "a", "A", "a", "A"),
|
||||||
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||||
] {
|
] {
|
||||||
assert_eq!(None.apply_to_field(original), original);
|
let original = &Ident::new(name, Span::call_site());
|
||||||
|
|
||||||
|
assert_eq!(None.apply_to_field(original), name);
|
||||||
assert_eq!(UpperCase.apply_to_field(original), upper);
|
assert_eq!(UpperCase.apply_to_field(original), upper);
|
||||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||||
assert_eq!(CamelCase.apply_to_field(original), camel);
|
assert_eq!(CamelCase.apply_to_field(original), camel);
|
||||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
assert_eq!(SnakeCase.apply_to_field(original), name);
|
||||||
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
||||||
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
||||||
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
|
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
|
||||||
|
|
|
@ -6,7 +6,10 @@ use super::{discard_lifetimes, ContainerMeta, FieldMeta, Namespace, VariantMeta}
|
||||||
|
|
||||||
pub(crate) fn from_xml(input: &syn::DeriveInput) -> TokenStream {
|
pub(crate) fn from_xml(input: &syn::DeriveInput) -> TokenStream {
|
||||||
let ident = &input.ident;
|
let ident = &input.ident;
|
||||||
let meta = ContainerMeta::from_derive(input);
|
let meta = match ContainerMeta::from_derive(input) {
|
||||||
|
Ok(meta) => meta,
|
||||||
|
Err(e) => return e.to_compile_error(),
|
||||||
|
};
|
||||||
|
|
||||||
match &input.data {
|
match &input.data {
|
||||||
syn::Data::Struct(_) if meta.scalar => {
|
syn::Data::Struct(_) if meta.scalar => {
|
||||||
|
@ -224,7 +227,7 @@ fn process_field(
|
||||||
Some(rename) => quote!(#rename),
|
Some(rename) => quote!(#rename),
|
||||||
None => container_meta
|
None => container_meta
|
||||||
.rename_all
|
.rename_all
|
||||||
.apply_to_field(&field_name.to_string())
|
.apply_to_field(field_name)
|
||||||
.into_token_stream(),
|
.into_token_stream(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,23 +37,28 @@ struct ContainerMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContainerMeta {
|
impl ContainerMeta {
|
||||||
fn from_derive(input: &syn::DeriveInput) -> ContainerMeta {
|
fn from_derive(input: &syn::DeriveInput) -> Result<ContainerMeta, syn::Error> {
|
||||||
let mut meta = ContainerMeta::default();
|
let mut meta = ContainerMeta::default();
|
||||||
for item in meta_items(&input.attrs) {
|
for item in meta_items(&input.attrs) {
|
||||||
match item {
|
match item {
|
||||||
MetaItem::Attribute => panic!("attribute key invalid in container xml attribute"),
|
MetaItem::Attribute => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
input.span(),
|
||||||
|
"attribute key invalid in container xml attribute",
|
||||||
|
))
|
||||||
|
}
|
||||||
MetaItem::Ns(ns) => meta.ns = ns,
|
MetaItem::Ns(ns) => meta.ns = ns,
|
||||||
MetaItem::Rename(lit) => meta.rename = Some(lit),
|
MetaItem::Rename(lit) => meta.rename = Some(lit),
|
||||||
MetaItem::RenameAll(lit) => {
|
MetaItem::RenameAll(lit) => {
|
||||||
meta.rename_all = match RenameRule::from_str(&lit.to_string()) {
|
meta.rename_all = match RenameRule::from_str(&lit.to_string()) {
|
||||||
Ok(rule) => rule,
|
Ok(rule) => rule,
|
||||||
Err(err) => panic!("{err}"),
|
Err(err) => return Err(syn::Error::new(input.span(), err)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
MetaItem::Scalar => meta.scalar = true,
|
MetaItem::Scalar => meta.scalar = true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
meta
|
Ok(meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +180,7 @@ impl VariantMeta {
|
||||||
Some(lit) => lit.into_token_stream(),
|
Some(lit) => lit.into_token_stream(),
|
||||||
None => container
|
None => container
|
||||||
.rename_all
|
.rename_all
|
||||||
.apply_to_variant(&input.ident.to_string())
|
.apply_to_variant(&input.ident)
|
||||||
.to_token_stream(),
|
.to_token_stream(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -491,13 +496,13 @@ fn meta_items(attrs: &[syn::Attribute]) -> Vec<MetaItem> {
|
||||||
(MetaState::Rename, TokenTree::Punct(punct)) if punct.as_char() == '=' => {
|
(MetaState::Rename, TokenTree::Punct(punct)) if punct.as_char() == '=' => {
|
||||||
MetaState::RenameValue
|
MetaState::RenameValue
|
||||||
}
|
}
|
||||||
(MetaState::RenameAll, TokenTree::Punct(punct)) if punct.as_char() == '=' => {
|
|
||||||
MetaState::RenameAllValue
|
|
||||||
}
|
|
||||||
(MetaState::RenameValue, TokenTree::Literal(lit)) => {
|
(MetaState::RenameValue, TokenTree::Literal(lit)) => {
|
||||||
items.push(MetaItem::Rename(lit));
|
items.push(MetaItem::Rename(lit));
|
||||||
MetaState::Comma
|
MetaState::Comma
|
||||||
}
|
}
|
||||||
|
(MetaState::RenameAll, TokenTree::Punct(punct)) if punct.as_char() == '=' => {
|
||||||
|
MetaState::RenameAllValue
|
||||||
|
}
|
||||||
(MetaState::RenameAllValue, TokenTree::Literal(lit)) => {
|
(MetaState::RenameAllValue, TokenTree::Literal(lit)) => {
|
||||||
items.push(MetaItem::RenameAll(lit));
|
items.push(MetaItem::RenameAll(lit));
|
||||||
MetaState::Comma
|
MetaState::Comma
|
||||||
|
@ -810,7 +815,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[should_panic(expected = "unknown rename rule `rename_all = \"\\\"forgetaboutit\\\"\"`, expected one of \"\\\"lowercase\\\"\", \"\\\"UPPERCASE\\\"\", \"\\\"PascalCase\\\"\", \"\\\"camelCase\\\"\", \"\\\"snake_case\\\"\", \"\\\"SCREAMING_SNAKE_CASE\\\"\", \"\\\"kebab-case\\\"\", \"\\\"SCREAMING-KEBAB-CASE\\\"\"")]
|
|
||||||
fn bogus_rename_all_not_permitted() {
|
fn bogus_rename_all_not_permitted() {
|
||||||
super::ser::to_xml(&parse_quote! {
|
super::ser::to_xml(&parse_quote! {
|
||||||
#[xml(rename_all = "forgetaboutit")]
|
#[xml(rename_all = "forgetaboutit")]
|
||||||
|
@ -818,6 +822,6 @@ mod tests {
|
||||||
field_1: String,
|
field_1: String,
|
||||||
field_2: u8,
|
field_2: u8,
|
||||||
}
|
}
|
||||||
}).to_string().find("compile_error ! { \"attribute 'rename_all' invalid in field xml attribute\" }").unwrap();
|
}).to_string().find("compile_error ! {").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,11 @@ use crate::Namespace;
|
||||||
use super::{discard_lifetimes, ContainerMeta, FieldMeta, VariantMeta};
|
use super::{discard_lifetimes, ContainerMeta, FieldMeta, VariantMeta};
|
||||||
|
|
||||||
pub fn to_xml(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
pub fn to_xml(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
||||||
let meta = ContainerMeta::from_derive(input);
|
let meta = match ContainerMeta::from_derive(input) {
|
||||||
|
Ok(meta) => meta,
|
||||||
|
Err(e) => return e.to_compile_error(),
|
||||||
|
};
|
||||||
|
|
||||||
match &input.data {
|
match &input.data {
|
||||||
syn::Data::Struct(_) if meta.scalar => {
|
syn::Data::Struct(_) if meta.scalar => {
|
||||||
syn::Error::new(input.span(), "scalar structs are unsupported!").to_compile_error()
|
syn::Error::new(input.span(), "scalar structs are unsupported!").to_compile_error()
|
||||||
|
@ -151,7 +155,7 @@ fn process_named_field(
|
||||||
Some(rename) => quote!(#rename),
|
Some(rename) => quote!(#rename),
|
||||||
None => meta
|
None => meta
|
||||||
.rename_all
|
.rename_all
|
||||||
.apply_to_field(&field_name.to_string())
|
.apply_to_field(field_name)
|
||||||
.into_token_stream(),
|
.into_token_stream(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue