From 857b8ab2b994d3fd65783391da604cc316fef3ae Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 24 Feb 2021 09:21:52 +0100 Subject: [PATCH] Updater: take serde renames into account Signed-off-by: Wolfgang Bumiller --- proxmox-api-macro/src/updater.rs | 35 ++++++++++++++++++++---------- proxmox-api-macro/tests/updater.rs | 15 +++++++------ 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/proxmox-api-macro/src/updater.rs b/proxmox-api-macro/src/updater.rs index 1ef82adc..2d037bd6 100644 --- a/proxmox-api-macro/src/updater.rs +++ b/proxmox-api-macro/src/updater.rs @@ -1,7 +1,10 @@ +use std::convert::TryFrom; + use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, quote_spanned}; use syn::spanned::Spanned; +use crate::serde; use crate::util; pub(crate) fn updatable(item: TokenStream) -> Result { @@ -90,6 +93,7 @@ fn derive_named_struct_updatable( ) -> Result { no_generics(generics); + let serde_container_attrs = serde::ContainerAttrib::try_from(&attrs[..])?; let args = UpdatableArgs::from_attributes(attrs); let updater = match args.updater { Some(updater) => updater, @@ -101,32 +105,41 @@ fn derive_named_struct_updatable( let mut build = TokenStream::new(); for field in fields.named { + let serde_attrs = serde::SerdeAttrib::try_from(&field.attrs[..])?; let attrs = UpdaterFieldArgs::from_attributes(field.attrs); - let field_name = field + let field_ident = field .ident .as_ref() .expect("unnamed field in named struct?"); - let field_name_string = field_name.to_string(); + let field_name_string = if let Some(renamed) = serde_attrs.rename { + renamed.into_str() + } else if let Some(rename_all) = serde_container_attrs.rename_all { + let name = rename_all.apply_to_field(&field_ident.to_string()); + name + } else { + field_ident.to_string() + }; + let build_err = format!( "failed to build value for field '{}': {{}}", field_name_string ); if util::is_option_type(&field.ty).is_some() { delete.extend(quote! { - #field_name_string => { self.#field_name = None; } + #field_name_string => { self.#field_ident = None; } }); build.extend(quote! { - #field_name: ::proxmox::api::schema::Updatable::try_build_from( - from.#field_name + #field_ident: ::proxmox::api::schema::Updatable::try_build_from( + from.#field_ident ) .map_err(|err| ::anyhow::format_err!(#build_err, err))?, }); } else { build.extend(quote! { - #field_name: ::proxmox::api::schema::Updatable::try_build_from( - from.#field_name + #field_ident: ::proxmox::api::schema::Updatable::try_build_from( + from.#field_ident ) .map_err(|err| ::anyhow::format_err!(#build_err, err))?, }); @@ -135,18 +148,18 @@ fn derive_named_struct_updatable( if attrs.fixed { let error = format!( "field '{}' must not be set when updating existing data", - field_name + field_ident ); apply.extend(quote! { - if from.#field_name.is_some() { + if from.#field_ident.is_some() { ::anyhow::bail!(#error); } }); } else { apply.extend(quote! { ::proxmox::api::schema::Updatable::update_from( - &mut self.#field_name, - from.#field_name, + &mut self.#field_ident, + from.#field_ident, delete, )?; }); diff --git a/proxmox-api-macro/tests/updater.rs b/proxmox-api-macro/tests/updater.rs index b52c87a0..4af50dbb 100644 --- a/proxmox-api-macro/tests/updater.rs +++ b/proxmox-api-macro/tests/updater.rs @@ -9,9 +9,10 @@ use proxmox::api::schema::{Updatable, Updater}; /// An example of a simple struct type. #[cfg_attr(not(feature = "noserde"), derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Updater)] +#[serde(rename_all = "kebab-case")] pub struct Simple { /// A test string. - one: String, + one_field: String, /// An optional auto-derived value for testing: #[serde(skip_serializing_if = "Option::is_empty")] @@ -191,7 +192,7 @@ mod test_creatable { "id": "Id1", "name": "The Name", "extra": "Extra Info", - "one": "Part of Simple", + "one-field": "Part of Simple", "info2": "More Info 2", }), &API_METHOD_CREATE_THING, @@ -209,7 +210,7 @@ mod test_creatable { complex: Complex { extra: "Extra Info".to_string(), simple: Simple { - one: "Part of Simple".to_string(), + one_field: "Part of Simple".to_string(), opt: None, }, }, @@ -245,7 +246,7 @@ mod test_creatable { complex: Complex { extra: "Extra Info".to_string(), simple: Simple { - one: "Part of Simple".to_string(), + one_field: "Part of Simple".to_string(), opt: None, }, }, @@ -270,7 +271,7 @@ mod test_creatable { complex: Complex { extra: "Partial flatten update".to_string(), simple: Simple { - one: "Part of Simple".to_string(), + one_field: "Part of Simple".to_string(), opt: None, }, }, @@ -295,7 +296,7 @@ mod test_creatable { complex: Complex { extra: "Partial flatten update".to_string(), simple: Simple { - one: "Part of Simple".to_string(), + one_field: "Part of Simple".to_string(), opt: Some("Deeply nested optional update.".to_string()), }, }, @@ -320,7 +321,7 @@ mod test_creatable { complex: Complex { extra: "Partial flatten update".to_string(), simple: Simple { - one: "Part of Simple".to_string(), + one_field: "Part of Simple".to_string(), opt: None, }, },