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::convert::TryInto;
use std::mem;
use failure::Error; use failure::Error;
use proc_macro2::{Ident, Span, TokenStream}; 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::punctuated::Punctuated;
use syn::Token; use syn::Token;
use super::Schema; use super::Schema;
use crate::util::{JSONObject, JSONValue, SimpleIdent}; 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. /// Enums, provided they're simple enums, simply get an enum string schema attached to them.
pub fn handle_enum( pub fn handle_enum(
mut attribs: JSONObject, mut attribs: JSONObject,
@ -45,30 +61,24 @@ pub fn handle_enum(
let mut renamed = false; let mut renamed = false;
for attrib in &mut variant.attrs { for attrib in &mut variant.attrs {
if !attrib.path.is_ident("api") { if !attrib.path.is_ident("serde") {
continue; continue;
} }
attrib.path = syn::parse2(quote! { serde })?; let args: AttrArgs = syn::parse2(attrib.tokens.clone())?;
for arg in args.args {
let mut obj: JSONObject = match arg {
syn::parse2(mem::replace(&mut attrib.tokens, TokenStream::new()))?; syn::NestedMeta::Meta(syn::Meta::NameValue(var)) => {
match obj.remove("rename") { if var.path.is_ident("rename") {
Some(JSONValue::Expr(syn::Expr::Lit(lit))) => { match var.lit {
if let syn::Lit::Str(lit) = lit.lit { syn::Lit::Str(lit) => variants.push(lit),
attrib.tokens.extend(quote! { rename = #lit }); _ => bail!(var.lit => "'rename' value must be a string literal"),
variants.push(lit); }
renamed = true; renamed = true;
} else { }
bail!(attrib => "'rename' must be a literal string");
} }
_ => (), // 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 proxmox_api_macro::api;
use failure::Error; use failure::Error;
//use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
#[api( #[api(
@ -24,7 +24,9 @@ impl OkString {
} }
#[api(description: "A selection of either A, B or C")] #[api(description: "A selection of either A, B or C")]
#[derive(Deserialize)]
pub enum Selection { pub enum Selection {
#[serde(rename = "a")]
A, A,
B, B,
C, C,