forked from proxmox-mirrors/proxmox
macro: started basic enum support
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
624afe28a4
commit
7f704d12df
@ -3,11 +3,12 @@ use std::collections::HashMap;
|
|||||||
use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
|
use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
|
||||||
|
|
||||||
use failure::{bail, format_err, Error};
|
use failure::{bail, format_err, Error};
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
use syn::{spanned::Spanned, Expr, Token};
|
use syn::{spanned::Spanned, Expr, Token};
|
||||||
|
|
||||||
use super::api_def::{CommonTypeDefinition, ParameterDefinition};
|
use crate::util;
|
||||||
use super::parsing::*;
|
use crate::api_def::{CommonTypeDefinition, ParameterDefinition};
|
||||||
|
use crate::parsing::*;
|
||||||
|
|
||||||
pub fn api_macro(attr: TokenStream, item: TokenStream) -> Result<TokenStream, Error> {
|
pub fn api_macro(attr: TokenStream, item: TokenStream) -> Result<TokenStream, Error> {
|
||||||
let definition = attr
|
let definition = attr
|
||||||
@ -561,6 +562,12 @@ fn handle_named_struct_fields(
|
|||||||
Ok(verify_entries)
|
Ok(verify_entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enums are string types. Note that we usually use lower case enum values, but rust wants
|
||||||
|
/// CamelCase, so unless otherwise requested by the user (todo!), we convert CamelCase to
|
||||||
|
/// underscore_case automatically.
|
||||||
|
///
|
||||||
|
/// For enums we automatically implement `ToString`, `FromStr`, and derive `Serialize` and
|
||||||
|
/// `Deserialize` via `serde_plain`.
|
||||||
fn handle_enum(
|
fn handle_enum(
|
||||||
_definition: HashMap<String, Expression>,
|
_definition: HashMap<String, Expression>,
|
||||||
item: &syn::ItemEnum,
|
item: &syn::ItemEnum,
|
||||||
@ -569,7 +576,55 @@ fn handle_enum(
|
|||||||
c_bail!(item.generics.span(), "generic types are currently not supported");
|
c_bail!(item.generics.span(), "generic types are currently not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
c_bail!(item.span(), "todo");
|
let enum_ident = &item.ident;
|
||||||
|
let expected = format!("valid {}", enum_ident.to_string());
|
||||||
|
|
||||||
|
let mut display_entries = TokenStream::new();
|
||||||
|
let mut from_str_entries = TokenStream::new();
|
||||||
|
|
||||||
|
for variant in item.variants.iter() {
|
||||||
|
if variant.fields != syn::Fields::Unit {
|
||||||
|
c_bail!(variant.span(), "#[api] enums cannot have fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
let variant_ident = &variant.ident;
|
||||||
|
let span = variant_ident.span();
|
||||||
|
let underscore_name = util::to_underscore_case(&variant_ident.to_string());
|
||||||
|
|
||||||
|
display_entries.extend(quote_spanned! {
|
||||||
|
span => #enum_ident::#variant_ident => write!(f, "{}", #underscore_name),
|
||||||
|
});
|
||||||
|
|
||||||
|
from_str_entries.extend(quote_spanned! {
|
||||||
|
span => #underscore_name => Ok(#enum_ident::#variant_ident),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(quote_spanned! { item.span() =>
|
||||||
|
impl ::std::fmt::Display for #enum_ident {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
#display_entries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::str::FromStr for #enum_ident {
|
||||||
|
type Err = ::failure::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
#from_str_entries
|
||||||
|
_ => ::failure::bail!("expected {}", #expected),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::serde_plain::derive_deserialize_from_str!(#enum_ident, #expected);
|
||||||
|
::serde_plain::derive_serialize_from_display!(#enum_ident);
|
||||||
|
|
||||||
|
::proxmox::api::derive_parse_cli_from_str!(#enum_ident);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//fn parse_api_definition(def: &mut ApiDefinitionBuilder, tokens: TokenStream) -> Result<(), Error> {
|
//fn parse_api_definition(def: &mut ApiDefinitionBuilder, tokens: TokenStream) -> Result<(), Error> {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/// Convert `this_kind_of_text` to `ThisKindOfText`.
|
||||||
pub fn to_camel_case(text: &str) -> String {
|
pub fn to_camel_case(text: &str) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
|
|
||||||
@ -17,3 +18,21 @@ pub fn to_camel_case(text: &str) -> String {
|
|||||||
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert `ThisKindOfText` to `this_kind_of_text`.
|
||||||
|
pub fn to_underscore_case(text: &str) -> String {
|
||||||
|
let mut out = String::new();
|
||||||
|
|
||||||
|
for c in text.chars() {
|
||||||
|
if c.is_uppercase() {
|
||||||
|
if !out.is_empty() {
|
||||||
|
out.push('_');
|
||||||
|
}
|
||||||
|
out.extend(c.to_lowercase());
|
||||||
|
} else {
|
||||||
|
out.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user