From 50eadf23fbbbb3bc21e005ca4c3e6208f3430342 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Fri, 19 Jul 2019 14:50:23 +0200 Subject: [PATCH] macro: support Option in deserialization When deserializing we currently expect all fields to be available, but we actually want Option types to be truly optional... Signed-off-by: Wolfgang Bumiller --- proxmox-api-macro/src/api_macro.rs | 7 ++++--- proxmox-api/src/api_type.rs | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/proxmox-api-macro/src/api_macro.rs b/proxmox-api-macro/src/api_macro.rs index 0ddeff72..27720f3e 100644 --- a/proxmox-api-macro/src/api_macro.rs +++ b/proxmox-api-macro/src/api_macro.rs @@ -539,9 +539,10 @@ fn handle_struct_named( }); field_option_check_or_default_list.extend(quote_spanned! { field_span => - let #field_ident = #field_ident.ok_or_else(|| { - ::serde::de::Error::missing_field(#field_str) - })?; + let #field_ident = ::proxmox::api::ApiType::deserialization_check( + #field_ident, + || ::serde::de::Error::missing_field(#field_str), + )?; }); field_name_matches.extend(quote_spanned! { field_span => diff --git a/proxmox-api/src/api_type.rs b/proxmox-api/src/api_type.rs index 17676549..6ab62055 100644 --- a/proxmox-api/src/api_type.rs +++ b/proxmox-api/src/api_type.rs @@ -164,7 +164,7 @@ impl dyn ApiMethodInfo + Send + Sync { /// While this is very useful for structural types, we sometimes to want to be able to pass a /// simple unconstrainted type like a `String` with no restrictions, so most basic types implement /// `ApiType` as well. -pub trait ApiType { +pub trait ApiType: Sized { /// API types need to provide a `TypeInfo`, providing details about the underlying type. fn type_info() -> &'static TypeInfo; @@ -190,6 +190,14 @@ pub trait ApiType { fn should_skip_serialization(&self) -> bool { false } + + #[inline] + fn deserialization_check(this: Option, missing_error: F) -> Result + where + F: FnOnce() -> E, + { + this.ok_or_else(missing_error) + } } /// Option types are supposed to wrap their underlying types with an `optional:` text in their @@ -244,6 +252,14 @@ impl ApiType for Option { fn should_skip_serialization(&self) -> bool { self.is_none() } + + #[inline] + fn deserialization_check(this: Option, _missing_error: F) -> Result + where + F: FnOnce() -> E, + { + Ok(this.unwrap_or(None)) + } } /// Any `Result` of course gets the same info as `T`, since this only means that it can