]> git.proxmox.com Git - proxmox.git/commitdiff
api-macro: make skip_serializing_if without default an error
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 6 Dec 2023 13:38:04 +0000 (14:38 +0100)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 6 Dec 2023 13:39:47 +0000 (14:39 +0100)
except for Option types, since this causes deserialization issues

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
proxmox-api-macro/src/api/structs.rs
proxmox-api-macro/src/serde.rs

index edd1bc1162fc7b7c4ca7567e5339395b197e70ea..f9d35be861f93acf5f23f8b68818e2407932d788 100644 (file)
@@ -168,7 +168,7 @@ fn handle_regular_struct(
                     .as_ref()
                     .ok_or_else(|| format_err!(field => "field without name?"))?;
 
-                if let Some(renamed) = attrs.rename {
+                if let Some(renamed) = 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());
@@ -201,7 +201,7 @@ fn handle_regular_struct(
                         }
                     }
 
-                    handle_regular_field(field_def, field, false)?;
+                    handle_regular_field(field_def, field, false, &attrs)?;
 
                     if attrs.flatten {
                         all_of_schemas.extend(quote::quote! {&});
@@ -215,7 +215,7 @@ fn handle_regular_struct(
                         false,
                         Schema::blank(span),
                     );
-                    handle_regular_field(&mut field_def, field, true)?;
+                    handle_regular_field(&mut field_def, field, true, &attrs)?;
 
                     if attrs.flatten {
                         all_of_schemas.extend(quote::quote! {&});
@@ -373,6 +373,7 @@ fn handle_regular_field(
     field_def: &mut ObjectEntry,
     field: &syn::Field,
     derived: bool, // whether this field was missing in the schema
+    attrs: &serde::FieldAttrib,
 ) -> Result<(), Error> {
     let schema: &mut Schema = &mut field_def.schema;
 
@@ -389,6 +390,8 @@ fn handle_regular_field(
         } else if !field_def.optional.expect_bool() {
             error!(&field.ty => "non-optional Option type?");
         }
+    } else {
+        attrs.check_non_option_type();
     }
 
     Ok(())
index d378405be589cd1a71a0d01ecf2246d4ecc42ee3..2821f8d578b348cbee8901799733acffe360933e 100644 (file)
@@ -5,7 +5,9 @@
 
 use std::convert::TryFrom;
 
+use proc_macro2::Span;
 use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
 use syn::Token;
 
 /// Serde name types.
@@ -171,6 +173,8 @@ impl TryFrom<&[syn::Attribute]> for ContainerAttrib {
 pub struct FieldAttrib {
     pub rename: Option<syn::LitStr>,
     pub flatten: bool,
+    has_skip_serializing_if: Option<Span>,
+    has_default: bool,
 }
 
 impl FieldAttrib {
@@ -200,11 +204,26 @@ impl FieldAttrib {
             } else if path.is_ident("flatten") {
                 arg.require_path_only()?;
                 self.flatten = true;
+            } else if path.is_ident("skip_serializing_if") {
+                self.has_skip_serializing_if = Some(match arg.require_name_value() {
+                    Ok(nv) => nv.span(),
+                    Err(_) => arg.span(),
+                });
+            } else if path.is_ident("default") {
+                self.has_default = true;
             }
         }
 
         Ok(())
     }
+
+    pub fn check_non_option_type(&self) {
+        if let Some(span) = self.has_skip_serializing_if {
+            if !self.has_default {
+                error!(span, "`skip_serializing_if` without `default`");
+            }
+        }
+    }
 }
 
 impl TryFrom<&[syn::Attribute]> for FieldAttrib {