]> git.proxmox.com Git - proxmox.git/commitdiff
macro: split enum handler into separate module
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 9 Aug 2019 10:40:43 +0000 (12:40 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 9 Aug 2019 10:42:06 +0000 (12:42 +0200)
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
proxmox-api-macro/src/api_macro.rs
proxmox-api-macro/src/api_macro/enum_types.rs [new file with mode: 0644]
proxmox-api-macro/src/api_macro/struct_types.rs

index 1710b5fb33d928067c1333620de82bf87d0ce517..5e3f71ad0a286fbfb5eeaa4e7a64074bd7d2f64d 100644 (file)
@@ -1,15 +1,12 @@
-use std::mem;
-
-use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
+use proc_macro2::{Delimiter, TokenStream, TokenTree};
 
 use failure::Error;
-use quote::{quote_spanned, ToTokens};
+use quote::ToTokens;
 use syn::spanned::Spanned;
 
-use crate::api_def::{CommonTypeDefinition, ParameterDefinition};
-use crate::parsing::*;
-use crate::util;
+use crate::parsing::parse_object;
 
+mod enum_types;
 mod function;
 mod struct_types;
 
@@ -40,7 +37,7 @@ pub fn api_macro(attr: TokenStream, item: TokenStream) -> Result<TokenStream, Er
         }
         syn::Item::Fn(func) => function::handle_function(def_span, definition, func),
         syn::Item::Enum(ref mut itemenum) => {
-            let extra = handle_enum(definition, itemenum)?;
+            let extra = enum_types::handle_enum(definition, itemenum)?;
             let mut output = item.into_token_stream();
             output.extend(extra);
             Ok(output)
@@ -48,112 +45,3 @@ pub fn api_macro(attr: TokenStream, item: TokenStream) -> Result<TokenStream, Er
         _ => c_bail!(item => "api macro currently only applies to structs and functions"),
     }
 }
-
-/// 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(mut definition: Object, item: &mut syn::ItemEnum) -> Result<TokenStream, Error> {
-    if item.generics.lt_token.is_some() {
-        c_bail!(
-            item.generics.span(),
-            "generic types are currently not supported"
-        );
-    }
-
-    let enum_ident = &item.ident;
-    let enum_name = enum_ident.to_string();
-    let expected = format!("valid {}", enum_ident);
-
-    let mut display_entries = TokenStream::new();
-    let mut from_str_entries = TokenStream::new();
-
-    for variant in item.variants.iter_mut() {
-        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());
-        let mut underscore_name = syn::LitStr::new(&underscore_name, variant_ident.span());
-
-        let cap = variant.attrs.len();
-        for attr in mem::replace(&mut variant.attrs, Vec::with_capacity(cap)) {
-            if attr.path.is_ident(Ident::new("api", Span::call_site())) {
-                use util::ApiItem;
-
-                let attrs: util::ApiAttr = syn::parse2(attr.tts)?;
-
-                for attr in attrs.items {
-                    match attr {
-                        ApiItem::Rename(to) => underscore_name = to,
-                        //other => c_bail!(other.span(), "unsupported attribute on enum variant"),
-                    }
-                }
-            } else {
-                variant.attrs.push(attr);
-            }
-        }
-
-        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),
-        });
-    }
-
-    let common = CommonTypeDefinition::from_object(&mut definition)?;
-    let apidef = ParameterDefinition::from_object(definition)?;
-
-    if let Some(validate) = apidef.validate {
-        c_bail!(validate => "validators are not allowed on enum types");
-    }
-
-    let description = common.description;
-    let parse_cli = common.cli.quote(&enum_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);
-
-        impl ::proxmox::api::ApiType for #enum_ident {
-            fn type_info() -> &'static ::proxmox::api::TypeInfo {
-                const INFO: ::proxmox::api::TypeInfo = ::proxmox::api::TypeInfo {
-                    name: #enum_name,
-                    description: #description,
-                    complete_fn: None, // FIXME!
-                    parse_cli: #parse_cli,
-                };
-                &INFO
-            }
-
-            fn verify(&self) -> ::std::result::Result<(), ::failure::Error> {
-                Ok(())
-            }
-        }
-    })
-}
diff --git a/proxmox-api-macro/src/api_macro/enum_types.rs b/proxmox-api-macro/src/api_macro/enum_types.rs
new file mode 100644 (file)
index 0000000..946632c
--- /dev/null
@@ -0,0 +1,124 @@
+//! `#[api]` handler for enums.
+//!
+//! Simple enums without data are string types. Note that we usually use lower case enum values,
+//! but rust wants CamelCase, so unless otherwise requested by the user, we convert `CamelCase` to
+//! `underscore_case` automatically.
+//!
+//! For "string" enums we automatically implement `ToString`, `FromStr`, and derive `Serialize` and
+//! `Deserialize` via `serde_plain`.
+
+use std::mem;
+
+use proc_macro2::{Ident, Span, TokenStream};
+
+use failure::Error;
+use quote::quote_spanned;
+use syn::spanned::Spanned;
+
+use crate::api_def::{CommonTypeDefinition, ParameterDefinition};
+use crate::parsing::Object;
+
+use crate::util;
+
+pub fn handle_enum(mut definition: Object, item: &mut syn::ItemEnum) -> Result<TokenStream, Error> {
+    if item.generics.lt_token.is_some() {
+        c_bail!(
+            item.generics.span(),
+            "generic types are currently not supported"
+        );
+    }
+
+    let enum_ident = &item.ident;
+    let enum_name = enum_ident.to_string();
+    let expected = format!("valid {}", enum_ident);
+
+    let mut display_entries = TokenStream::new();
+    let mut from_str_entries = TokenStream::new();
+
+    for variant in item.variants.iter_mut() {
+        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());
+        let mut underscore_name = syn::LitStr::new(&underscore_name, variant_ident.span());
+
+        let cap = variant.attrs.len();
+        for attr in mem::replace(&mut variant.attrs, Vec::with_capacity(cap)) {
+            if attr.path.is_ident(Ident::new("api", Span::call_site())) {
+                use util::ApiItem;
+
+                let attrs: util::ApiAttr = syn::parse2(attr.tts)?;
+
+                for attr in attrs.items {
+                    match attr {
+                        ApiItem::Rename(to) => underscore_name = to,
+                        //other => c_bail!(other.span(), "unsupported attribute on enum variant"),
+                    }
+                }
+            } else {
+                variant.attrs.push(attr);
+            }
+        }
+
+        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),
+        });
+    }
+
+    let common = CommonTypeDefinition::from_object(&mut definition)?;
+    let apidef = ParameterDefinition::from_object(definition)?;
+
+    if let Some(validate) = apidef.validate {
+        c_bail!(validate => "validators are not allowed on enum types");
+    }
+
+    let description = common.description;
+    let parse_cli = common.cli.quote(&enum_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);
+
+        impl ::proxmox::api::ApiType for #enum_ident {
+            fn type_info() -> &'static ::proxmox::api::TypeInfo {
+                const INFO: ::proxmox::api::TypeInfo = ::proxmox::api::TypeInfo {
+                    name: #enum_name,
+                    description: #description,
+                    complete_fn: None, // FIXME!
+                    parse_cli: #parse_cli,
+                };
+                &INFO
+            }
+
+            fn verify(&self) -> ::std::result::Result<(), ::failure::Error> {
+                Ok(())
+            }
+        }
+    })
+}
index 06418885be23af9e03be92e5a3c6190d07e85296..b56a0cec25d464de934bc60c0f1d8688697844d6 100644 (file)
@@ -16,7 +16,7 @@ mod newtype;
 mod unnamed;
 
 /// Commonly used items of a struct field.
-struct StructField<'i, 't> {
+pub struct StructField<'i, 't> {
     def: ParameterDefinition,
     ident: Option<&'i Ident>,
     access: syn::Member,