api-macro: handle renames in updater derive

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2024-08-01 14:19:10 +02:00
parent 4c37db22d2
commit 51d78fdd2b
2 changed files with 53 additions and 15 deletions

View File

@ -271,7 +271,8 @@ fn handle_regular_struct(
} }
}); });
if derive { if derive {
let updater = derive_updater(stru.clone(), schema.clone(), &mut stru)?; let updater =
derive_updater(stru.clone(), schema.clone(), &mut stru, &container_attrs)?;
// make sure we don't leave #[updater] attributes on the original struct: // make sure we don't leave #[updater] attributes on the original struct:
if let syn::Fields::Named(fields) = &mut stru.fields { if let syn::Fields::Named(fields) = &mut stru.fields {
@ -403,6 +404,7 @@ fn derive_updater(
mut stru: syn::ItemStruct, mut stru: syn::ItemStruct,
mut schema: Schema, mut schema: Schema,
original_struct: &mut syn::ItemStruct, original_struct: &mut syn::ItemStruct,
container_attrs: &serde::ContainerAttrib,
) -> Result<TokenStream, Error> { ) -> Result<TokenStream, Error> {
let original_name = &original_struct.ident; let original_name = &original_struct.ident;
stru.ident = Ident::new(&format!("{}Updater", stru.ident), stru.ident.span()); stru.ident = Ident::new(&format!("{}Updater", stru.ident), stru.ident.span());
@ -425,6 +427,7 @@ fn derive_updater(
&mut schema, &mut schema,
&mut all_of_schemas, &mut all_of_schemas,
&mut is_empty_impl, &mut is_empty_impl,
container_attrs,
) { ) {
Ok(FieldAction::Keep) => fields.named.push(field), Ok(FieldAction::Keep) => fields.named.push(field),
Ok(FieldAction::Skip) => (), Ok(FieldAction::Skip) => (),
@ -471,32 +474,51 @@ fn handle_updater_field(
schema: &mut Schema, schema: &mut Schema,
all_of_schemas: &mut TokenStream, all_of_schemas: &mut TokenStream,
is_empty_impl: &mut TokenStream, is_empty_impl: &mut TokenStream,
container_attrs: &serde::ContainerAttrib,
) -> Result<FieldAction, syn::Error> { ) -> Result<FieldAction, syn::Error> {
let updater_attrs = UpdaterFieldAttributes::from_attributes(&mut field.attrs); let updater_attrs = UpdaterFieldAttributes::from_attributes(&mut field.attrs);
let serde_attrs = serde::FieldAttrib::try_from(&field.attrs[..])?;
let field_name = field.ident.as_ref().expect("unnamed field in FieldsNamed"); let field_name = field.ident.as_ref().expect("unnamed field in FieldsNamed");
let field_name_string = field_name.to_string(); let field_name_string = field_name.to_string();
let (name, name_span) = {
let ident: &Ident = field
.ident
.as_ref()
.ok_or_else(|| format_err!(&field => "field without name?"))?;
if let Some(renamed) = serde_attrs.rename.clone() {
(renamed.value(), ident.span())
} else if let Some(rename_all) = container_attrs.rename_all {
let name = rename_all.apply_to_field(&ident.to_string());
(name, ident.span())
} else {
(ident.to_string(), ident.span())
}
};
if updater_attrs.skip() { if updater_attrs.skip() {
if !schema.remove_obj_property_by_ident(&field_name_string) { if !schema.remove_obj_property_by_ident(&name)
bail!( && !schema.remove_obj_property_by_ident(&field_name_string)
field_name.span(), {
"failed to find schema entry for {:?}", bail!(name_span, "failed to find schema entry for {:?}", name);
field_name_string,
);
} }
return Ok(FieldAction::Skip); return Ok(FieldAction::Skip);
} }
let field_schema = match schema.find_obj_property_by_ident_mut(&field_name_string) { let field_schema = match schema.find_obj_property_by_ident_mut(&name) {
Some(obj) => obj, Some(obj) => obj,
None => { None => match schema.find_obj_property_by_ident_mut(&field_name_string) {
bail!( Some(obj) => obj,
field_name.span(), None => {
"failed to find schema entry for {:?}", bail!(
field_name_string, field_name.span(),
); "failed to find schema entry for {:?}",
} field_name_string,
);
}
},
}; };
let span = Span::call_site(); let span = Span::call_site();

View File

@ -155,3 +155,19 @@ pub struct WithSerde {
#[updater(serde(skip_serializing_if = "Option::is_none"))] #[updater(serde(skip_serializing_if = "Option::is_none"))]
more: MyType, more: MyType,
} }
#[api(
properties: {
another: { type: MyType },
},
)]
/// A struct where we replace serde attributes.
#[derive(Deserialize, Serialize, Updater)]
pub struct RenamedStuff {
/// Simple string.
data: String,
#[serde(rename = "another")]
#[updater(skip)]
more: MyType,
}