forked from Proxmox/proxmox
macro: derive ser/de for newtypes just like structs
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
a53e8c5e82
commit
bb3e2859e4
@ -8,6 +8,7 @@ use proxmox::api::api;
|
||||
// representations. Numeric always being bytes, string having suffixes.
|
||||
#[api({
|
||||
description: "Represents an amount of memory and can be expressed with suffixes such as MiB.",
|
||||
serialize_as_string: true,
|
||||
})]
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
|
||||
#[repr(transparent)]
|
||||
@ -40,7 +41,6 @@ impl std::str::FromStr for Memory {
|
||||
}
|
||||
}
|
||||
}
|
||||
serde_plain::derive_deserialize_from_str!(Memory, "valid memory amount description");
|
||||
proxmox::api::derive_parse_cli_from_str!(Memory);
|
||||
|
||||
impl std::fmt::Display for Memory {
|
||||
@ -55,7 +55,6 @@ impl std::fmt::Display for Memory {
|
||||
write!(f, "{}{}", n, SUFFIXES[i])
|
||||
}
|
||||
}
|
||||
serde_plain::derive_serialize_from_display!(Memory);
|
||||
|
||||
impl Memory {
|
||||
pub const fn from_bytes(v: u64) -> Self {
|
||||
|
@ -449,14 +449,25 @@ struct StructField<'i, 't> {
|
||||
|
||||
fn handle_newtype(
|
||||
mut definition: Object,
|
||||
name: &Ident,
|
||||
type_ident: &Ident,
|
||||
item: &syn::FieldsUnnamed,
|
||||
) -> Result<TokenStream, Error> {
|
||||
let type_s = type_ident.to_string();
|
||||
let type_span = type_ident.span();
|
||||
let type_str = syn::LitStr::new(&type_s, type_span);
|
||||
|
||||
let fields = &item.unnamed;
|
||||
let field_punct = fields.first().unwrap();
|
||||
let field = field_punct.value();
|
||||
|
||||
let common = CommonTypeDefinition::from_object(&mut definition)?;
|
||||
|
||||
let serialize_as_string = definition
|
||||
.remove("serialize_as_string")
|
||||
.map(|e| e.expect_lit_bool_direct())
|
||||
.transpose()?
|
||||
.unwrap_or(false);
|
||||
|
||||
let apidef = ParameterDefinition::from_object(definition)?;
|
||||
|
||||
let impl_verify = struct_fields_impl_verify(item.span(), &[StructField {
|
||||
@ -464,23 +475,44 @@ fn handle_newtype(
|
||||
ident: None,
|
||||
access: syn::Member::Unnamed(syn::Index {
|
||||
index: 0,
|
||||
span: name.span(),
|
||||
span: type_ident.span(),
|
||||
}),
|
||||
mem_id: 0,
|
||||
string: "0".to_string(),
|
||||
strlit: syn::LitStr::new("0", name.span()),
|
||||
strlit: syn::LitStr::new("0", type_ident.span()),
|
||||
ty: &field.ty,
|
||||
}])?;
|
||||
|
||||
let (impl_serialize, impl_deserialize) = if serialize_as_string {
|
||||
let expected = format!("valid {}", type_ident);
|
||||
(
|
||||
quote_spanned! { item.span() =>
|
||||
::serde_plain::derive_serialize_from_display!(#type_ident);
|
||||
},
|
||||
quote_spanned! { item.span() =>
|
||||
::serde_plain::derive_deserialize_from_str!(#type_ident, #expected);
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(
|
||||
newtype_derive_serialize(item.span(), type_ident),
|
||||
newtype_derive_deserialize(item.span(), type_ident),
|
||||
)
|
||||
};
|
||||
|
||||
let description = common.description;
|
||||
let parse_cli = common.cli.quote(&name);
|
||||
let parse_cli = common.cli.quote(&type_ident);
|
||||
Ok(quote! {
|
||||
impl ::proxmox::api::ApiType for #name {
|
||||
#impl_serialize
|
||||
|
||||
#impl_deserialize
|
||||
|
||||
impl ::proxmox::api::ApiType for #type_ident {
|
||||
fn type_info() -> &'static ::proxmox::api::TypeInfo {
|
||||
use ::proxmox::api::cli::ParseCli;
|
||||
use ::proxmox::api::cli::ParseCliFromStr;
|
||||
const INFO: ::proxmox::api::TypeInfo = ::proxmox::api::TypeInfo {
|
||||
name: stringify!(#name),
|
||||
name: #type_str,
|
||||
description: #description,
|
||||
complete_fn: None, // FIXME!
|
||||
parse_cli: #parse_cli,
|
||||
@ -493,6 +525,38 @@ fn handle_newtype(
|
||||
})
|
||||
}
|
||||
|
||||
fn newtype_derive_serialize(
|
||||
span: Span,
|
||||
type_ident: &Ident,
|
||||
) -> TokenStream {
|
||||
quote_spanned! { span =>
|
||||
impl ::serde::ser::Serialize for #type_ident {
|
||||
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ::serde::ser::Serializer,
|
||||
{
|
||||
::serde::ser::Serialize::serialize::<S>(&self.0, serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn newtype_derive_deserialize(
|
||||
span: Span,
|
||||
type_ident: &Ident,
|
||||
) -> TokenStream {
|
||||
quote_spanned! { span =>
|
||||
impl<'de> ::serde::de::Deserialize<'de> for #type_ident {
|
||||
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
|
||||
where
|
||||
D: ::serde::de::Deserializer<'de>,
|
||||
{
|
||||
Ok(Self(::serde::de::Deserialize::<'de>::deserialize::<D>(deserializer)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_struct_unnamed(
|
||||
mut definition: Object,
|
||||
name: &Ident,
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use failure::{bail, Error};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use proxmox::api::{api, Router};
|
||||
@ -11,7 +10,6 @@ use proxmox::api::{api, Router};
|
||||
description: "A hostname or IP address",
|
||||
validate: validate_hostname,
|
||||
})]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[repr(transparent)]
|
||||
pub struct HostOrIp(String);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user