api-macro: parse serde(rename) on enums

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-11-28 13:42:46 +01:00
parent 30a1c0b9ae
commit 7d6fac0fa5
2 changed files with 34 additions and 22 deletions

View File

@ -1,16 +1,32 @@
use std::convert::TryInto;
use std::mem;
use failure::Error;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, quote_spanned};
use quote::quote_spanned;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::Token;
use super::Schema;
use crate::util::{JSONObject, JSONValue, SimpleIdent};
/// `parse_macro_input!` expects a TokenStream_1
struct AttrArgs {
paren_token: syn::token::Paren,
args: Punctuated<syn::NestedMeta, Token![,]>,
}
impl Parse for AttrArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let content;
Ok(Self {
paren_token: syn::parenthesized!(content in input),
args: Punctuated::parse_terminated(&content)?,
})
}
}
/// Enums, provided they're simple enums, simply get an enum string schema attached to them.
pub fn handle_enum(
mut attribs: JSONObject,
@ -45,30 +61,24 @@ pub fn handle_enum(
let mut renamed = false;
for attrib in &mut variant.attrs {
if !attrib.path.is_ident("api") {
if !attrib.path.is_ident("serde") {
continue;
}
attrib.path = syn::parse2(quote! { serde })?;
let mut obj: JSONObject =
syn::parse2(mem::replace(&mut attrib.tokens, TokenStream::new()))?;
match obj.remove("rename") {
Some(JSONValue::Expr(syn::Expr::Lit(lit))) => {
if let syn::Lit::Str(lit) = lit.lit {
attrib.tokens.extend(quote! { rename = #lit });
variants.push(lit);
renamed = true;
} else {
bail!(attrib => "'rename' must be a literal string");
let args: AttrArgs = syn::parse2(attrib.tokens.clone())?;
for arg in args.args {
match arg {
syn::NestedMeta::Meta(syn::Meta::NameValue(var)) => {
if var.path.is_ident("rename") {
match var.lit {
syn::Lit::Str(lit) => variants.push(lit),
_ => bail!(var.lit => "'rename' value must be a string literal"),
}
renamed = true;
}
}
_ => (), // ignore
}
Some(_) => bail!(attrib => "'rename' must be a literal string"),
None => (),
}
if !obj.is_empty() {
bail!(attrib => "unknown fields in attribute");
}
}

View File

@ -5,7 +5,7 @@ use proxmox::api::schema;
use proxmox_api_macro::api;
use failure::Error;
//use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[api(
@ -24,7 +24,9 @@ impl OkString {
}
#[api(description: "A selection of either A, B or C")]
#[derive(Deserialize)]
pub enum Selection {
#[serde(rename = "a")]
A,
B,
C,