diff --git a/example/src/main.rs b/example/src/main.rs index 631368e..3faee12 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -26,8 +26,17 @@ rest_resource!{Users, route => { }} #[derive(Deserialize, OpenapiType, Serialize)] -struct User { - username : String +enum TestEnum +{ + Foo, + Bar +} + +#[derive(Deserialize, OpenapiType, Serialize)] +struct User +{ + username : String, + test : Option } impl ResourceReadAll>>> for Users @@ -36,7 +45,7 @@ impl ResourceReadAll>>> for Users { vec![Username().fake(), Username().fake()] .into_iter() - .map(|username| Some(User { username })) + .map(|username| Some(User { username, test: None })) .collect::>>() .into() } @@ -47,7 +56,7 @@ impl ResourceRead> for Users fn read(_state : &mut State, id : u64) -> Success { let username : String = Username().fake(); - User { username: format!("{}{}", username, id) }.into() + User { username: format!("{}{}", username, id), test: None }.into() } } diff --git a/gotham_restful/src/helper.rs b/gotham_restful/src/helper.rs index d4c7fcc..7efb776 100644 --- a/gotham_restful/src/helper.rs +++ b/gotham_restful/src/helper.rs @@ -2,7 +2,7 @@ pub mod openapi { pub use indexmap::IndexMap; - pub use openapiv3::{ObjectType, ReferenceOr, Schema, SchemaData, SchemaKind, Type}; + pub use openapiv3::{ObjectType, ReferenceOr, Schema, SchemaData, SchemaKind, StringType, Type, VariantOrUnknownOrEmpty}; } #[cfg(not(feature = "openapi"))] diff --git a/gotham_restful_derive/src/openapi_type.rs b/gotham_restful_derive/src/openapi_type.rs index 7ab40f7..d4df178 100644 --- a/gotham_restful_derive/src/openapi_type.rs +++ b/gotham_restful_derive/src/openapi_type.rs @@ -4,10 +4,66 @@ use quote::quote; use syn::{ Field, Fields, + Item, + ItemEnum, ItemStruct, + Variant, parse_macro_input }; +pub fn expand(tokens : TokenStream) -> TokenStream +{ + let input = parse_macro_input!(tokens as Item); + + match input { + Item::Enum(item) => expand_enum(item), + Item::Struct(item) => expand_struct(item), + _ => panic!("derive(OpenapiType) not supported for this context") + }.into() +} + +fn expand_variant(variant : &Variant) -> TokenStream2 +{ + if variant.fields != Fields::Unit + { + panic!("Enum Variants with Fields not supported"); + } + + let ident = &variant.ident; + + quote! { + enumeration.push(stringify!(#ident).to_string()); + } +} + +fn expand_enum(input : ItemEnum) -> TokenStream2 +{ + let ident = input.ident; + let generics = input.generics; + + let variants : Vec = input.variants.iter().map(expand_variant).collect(); + + quote! { + impl #generics ::gotham_restful::OpenapiType for #ident #generics + { + fn to_schema() -> ::gotham_restful::OpenapiSchema + { + use ::gotham_restful::{helper::openapi::*, OpenapiSchema}; + + let mut enumeration : Vec = Vec::new(); + + #(#variants)* + + OpenapiSchema::new(SchemaKind::Type(Type::String(StringType { + format: VariantOrUnknownOrEmpty::Empty, + pattern: None, + enumeration + }))) + } + } + } +} + fn expand_field(field : &Field) -> TokenStream2 { let ident = match &field.ident { @@ -48,10 +104,8 @@ fn expand_field(field : &Field) -> TokenStream2 }} } -pub fn expand(tokens : TokenStream) -> TokenStream +pub fn expand_struct(input : ItemStruct) -> TokenStream2 { - let input = parse_macro_input!(tokens as ItemStruct); - let ident = input.ident; let generics = input.generics; @@ -63,7 +117,7 @@ pub fn expand(tokens : TokenStream) -> TokenStream Fields::Unit => Vec::new() }; - let output = quote!{ + quote!{ impl #generics ::gotham_restful::OpenapiType for #ident #generics { fn to_schema() -> ::gotham_restful::OpenapiSchema @@ -92,7 +146,5 @@ pub fn expand(tokens : TokenStream) -> TokenStream } } } - }; - - output.into() + } }