mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-23 04:52:28 +00:00
Merge branch 'allow-openapi-customizations' into 'master'
Allow OpenAPI customizations See merge request msrd0/gotham-restful!7
This commit is contained in:
commit
d8c2ffaa9d
6 changed files with 198 additions and 34 deletions
|
@ -299,6 +299,7 @@ impl<'a> OperationParams<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_operation(
|
fn new_operation(
|
||||||
|
operation_id : Option<String>,
|
||||||
default_status : hyper::StatusCode,
|
default_status : hyper::StatusCode,
|
||||||
accepted_types : Option<Vec<Mime>>,
|
accepted_types : Option<Vec<Mime>>,
|
||||||
schema : ReferenceOr<Schema>,
|
schema : ReferenceOr<Schema>,
|
||||||
|
@ -334,7 +335,7 @@ fn new_operation(
|
||||||
|
|
||||||
Operation {
|
Operation {
|
||||||
tags: Vec::new(),
|
tags: Vec::new(),
|
||||||
operation_id: None, // TODO
|
operation_id,
|
||||||
parameters: params.into_params(),
|
parameters: params.into_params(),
|
||||||
request_body,
|
request_body,
|
||||||
responses: Responses {
|
responses: Responses {
|
||||||
|
@ -383,7 +384,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}", &self.1);
|
let path = format!("/{}", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&path);
|
let mut item = (self.0).1.remove_path(&path);
|
||||||
item.get = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), None, None, Handler::Res::requires_auth()));
|
item.get = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), None, None, Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).read_all::<Handler>()
|
(&mut *(self.0).0, self.1).read_all::<Handler>()
|
||||||
|
@ -395,7 +396,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}/{{id}}", &self.1);
|
let path = format!("/{}/{{id}}", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&path);
|
let mut item = (self.0).1.remove_path(&path);
|
||||||
item.get = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_path_params(vec!["id"]), None, None, Handler::Res::requires_auth()));
|
item.get = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_path_params(vec!["id"]), None, None, Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).read::<Handler>()
|
(&mut *(self.0).0, self.1).read::<Handler>()
|
||||||
|
@ -407,7 +408,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}/search", &self.1);
|
let path = format!("/{}/search", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&self.1);
|
let mut item = (self.0).1.remove_path(&self.1);
|
||||||
item.get = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_query_params(Handler::Query::schema()), None, None, Handler::Res::requires_auth()));
|
item.get = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_query_params(Handler::Query::schema()), None, None, Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).search::<Handler>()
|
(&mut *(self.0).0, self.1).search::<Handler>()
|
||||||
|
@ -420,7 +421,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}", &self.1);
|
let path = format!("/{}", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&path);
|
let mut item = (self.0).1.remove_path(&path);
|
||||||
item.post = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), Some(body_schema), Handler::Body::supported_types(), Handler::Res::requires_auth()));
|
item.post = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), Some(body_schema), Handler::Body::supported_types(), Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).create::<Handler>()
|
(&mut *(self.0).0, self.1).create::<Handler>()
|
||||||
|
@ -433,7 +434,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}", &self.1);
|
let path = format!("/{}", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&path);
|
let mut item = (self.0).1.remove_path(&path);
|
||||||
item.put = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), Some(body_schema), Handler::Body::supported_types(), Handler::Res::requires_auth()));
|
item.put = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), Some(body_schema), Handler::Body::supported_types(), Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).update_all::<Handler>()
|
(&mut *(self.0).0, self.1).update_all::<Handler>()
|
||||||
|
@ -446,7 +447,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}/{{id}}", &self.1);
|
let path = format!("/{}/{{id}}", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&path);
|
let mut item = (self.0).1.remove_path(&path);
|
||||||
item.put = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_path_params(vec!["id"]), Some(body_schema), Handler::Body::supported_types(), Handler::Res::requires_auth()));
|
item.put = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_path_params(vec!["id"]), Some(body_schema), Handler::Body::supported_types(), Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).update::<Handler>()
|
(&mut *(self.0).0, self.1).update::<Handler>()
|
||||||
|
@ -458,7 +459,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}", &self.1);
|
let path = format!("/{}", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&path);
|
let mut item = (self.0).1.remove_path(&path);
|
||||||
item.delete = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), None, None, Handler::Res::requires_auth()));
|
item.delete = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::default(), None, None, Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).delete_all::<Handler>()
|
(&mut *(self.0).0, self.1).delete_all::<Handler>()
|
||||||
|
@ -470,7 +471,7 @@ macro_rules! implOpenapiRouter {
|
||||||
|
|
||||||
let path = format!("/{}/{{id}}", &self.1);
|
let path = format!("/{}/{{id}}", &self.1);
|
||||||
let mut item = (self.0).1.remove_path(&path);
|
let mut item = (self.0).1.remove_path(&path);
|
||||||
item.delete = Some(new_operation(Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_path_params(vec!["id"]), None, None, Handler::Res::requires_auth()));
|
item.delete = Some(new_operation(Handler::operation_id(), Handler::Res::default_status(), Handler::Res::accepted_types(), schema, OperationParams::from_path_params(vec!["id"]), None, None, Handler::Res::requires_auth()));
|
||||||
(self.0).1.add_path(path, item);
|
(self.0).1.add_path(path, item);
|
||||||
|
|
||||||
(&mut *(self.0).0, self.1).delete::<Handler>()
|
(&mut *(self.0).0, self.1).delete::<Handler>()
|
||||||
|
|
|
@ -22,6 +22,12 @@ pub trait Resource
|
||||||
pub trait ResourceMethod
|
pub trait ResourceMethod
|
||||||
{
|
{
|
||||||
type Res : ResourceResult;
|
type Res : ResourceResult;
|
||||||
|
|
||||||
|
#[cfg(feature = "openapi")]
|
||||||
|
fn operation_id() -> Option<String>
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a GET request on the Resource root.
|
/// Handle a GET request on the Resource root.
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub fn derive_from_body(tokens : TokenStream) -> TokenStream
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "openapi")]
|
#[cfg(feature = "openapi")]
|
||||||
#[proc_macro_derive(OpenapiType)]
|
#[proc_macro_derive(OpenapiType, attributes(openapi))]
|
||||||
pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream
|
pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream
|
||||||
{
|
{
|
||||||
openapi_type::expand(tokens)
|
openapi_type::expand(tokens)
|
||||||
|
|
|
@ -4,8 +4,12 @@ use proc_macro2::{Ident, TokenStream as TokenStream2};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{
|
use syn::{
|
||||||
Attribute,
|
Attribute,
|
||||||
|
AttributeArgs,
|
||||||
FnArg,
|
FnArg,
|
||||||
ItemFn,
|
ItemFn,
|
||||||
|
Lit,
|
||||||
|
Meta,
|
||||||
|
NestedMeta,
|
||||||
PatType,
|
PatType,
|
||||||
ReturnType,
|
ReturnType,
|
||||||
Type,
|
Type,
|
||||||
|
@ -96,17 +100,17 @@ impl Method
|
||||||
format_ident!("{}", name)
|
format_ident!("{}", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mod_ident(&self, resource : String) -> Ident
|
pub fn mod_ident(&self, resource : &str) -> Ident
|
||||||
{
|
{
|
||||||
format_ident!("_gotham_restful_resource_{}_method_{}", resource.to_snake_case(), self.fn_ident())
|
format_ident!("_gotham_restful_resource_{}_method_{}", resource.to_snake_case(), self.fn_ident())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handler_struct_ident(&self, resource : String) -> Ident
|
pub fn handler_struct_ident(&self, resource : &str) -> Ident
|
||||||
{
|
{
|
||||||
format_ident!("{}{}Handler", resource.to_camel_case(), self.trait_ident())
|
format_ident!("{}{}Handler", resource.to_camel_case(), self.trait_ident())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_ident(&self, resource : String) -> Ident
|
pub fn setup_ident(&self, resource : &str) -> Ident
|
||||||
{
|
{
|
||||||
format_ident!("{}_{}_setup_impl", resource.to_snake_case(), self.fn_ident())
|
format_ident!("{}_{}_setup_impl", resource.to_snake_case(), self.fn_ident())
|
||||||
}
|
}
|
||||||
|
@ -210,19 +214,61 @@ fn interpret_arg(index : usize, arg : &PatType) -> MethodArgument
|
||||||
MethodArgument { ident, ty }
|
MethodArgument { ident, ty }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "openapi")]
|
||||||
|
fn expand_operation_id(attrs : &AttributeArgs) -> TokenStream2
|
||||||
|
{
|
||||||
|
let mut operation_id : Option<&Lit> = None;
|
||||||
|
for meta in attrs
|
||||||
|
{
|
||||||
|
match meta {
|
||||||
|
NestedMeta::Meta(Meta::NameValue(kv)) => {
|
||||||
|
if kv.path.segments.last().map(|p| p.ident.to_string()) == Some("operation_id".to_owned())
|
||||||
|
{
|
||||||
|
operation_id = Some(&kv.lit)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match operation_id {
|
||||||
|
Some(operation_id) => quote! {
|
||||||
|
fn operation_id() -> Option<String>
|
||||||
|
{
|
||||||
|
Some(#operation_id.to_string())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => quote!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "openapi"))]
|
||||||
|
fn expand_operation_id(_ : &AttributeArgs) -> TokenStream2
|
||||||
|
{
|
||||||
|
quote!()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
|
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
|
||||||
{
|
{
|
||||||
let krate = super::krate();
|
let krate = super::krate();
|
||||||
let resource_ident = parse_macro_input!(attrs as Ident);
|
|
||||||
|
// parse attributes
|
||||||
|
let mut method_attrs = parse_macro_input!(attrs as AttributeArgs);
|
||||||
|
let resource_path = match method_attrs.remove(0) {
|
||||||
|
NestedMeta::Meta(Meta::Path(path)) => path,
|
||||||
|
_ => panic!("Expected resource name for rest macro")
|
||||||
|
};
|
||||||
|
let resource_name = resource_path.segments.last().expect("Resource name must not be empty").ident.to_string();
|
||||||
|
|
||||||
let fun = parse_macro_input!(item as ItemFn);
|
let fun = parse_macro_input!(item as ItemFn);
|
||||||
let fun_ident = &fun.sig.ident;
|
let fun_ident = &fun.sig.ident;
|
||||||
let fun_vis = &fun.vis;
|
let fun_vis = &fun.vis;
|
||||||
|
|
||||||
let trait_ident = method.trait_ident();
|
let trait_ident = method.trait_ident();
|
||||||
let method_ident = method.fn_ident();
|
let method_ident = method.fn_ident();
|
||||||
let mod_ident = method.mod_ident(resource_ident.to_string());
|
let mod_ident = method.mod_ident(&resource_name);
|
||||||
let handler_ident = method.handler_struct_ident(resource_ident.to_string());
|
let handler_ident = method.handler_struct_ident(&resource_name);
|
||||||
let setup_ident = method.setup_ident(resource_ident.to_string());
|
let setup_ident = method.setup_ident(&resource_name);
|
||||||
|
|
||||||
let (ret, is_no_content) = match &fun.sig.output {
|
let (ret, is_no_content) = match &fun.sig.output {
|
||||||
ReturnType::Default => (quote!(#krate::NoContent), true),
|
ReturnType::Default => (quote!(#krate::NoContent), true),
|
||||||
|
@ -298,13 +344,16 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare the where clause
|
// prepare the where clause
|
||||||
let mut where_clause = quote!(#resource_ident : #krate::Resource,);
|
let mut where_clause = quote!(#resource_path : #krate::Resource,);
|
||||||
for arg in args.iter().filter(|arg| (*arg).ty.is_auth_status())
|
for arg in args.iter().filter(|arg| (*arg).ty.is_auth_status())
|
||||||
{
|
{
|
||||||
let auth_ty = arg.ty.quote_ty();
|
let auth_ty = arg.ty.quote_ty();
|
||||||
where_clause = quote!(#where_clause #auth_ty : Clone,);
|
where_clause = quote!(#where_clause #auth_ty : Clone,);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// operation id code
|
||||||
|
let operation_id = expand_operation_id(&method_attrs);
|
||||||
|
|
||||||
// put everything together
|
// put everything together
|
||||||
let output = quote! {
|
let output = quote! {
|
||||||
#fun
|
#fun
|
||||||
|
@ -318,6 +367,8 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
|
||||||
impl #krate::ResourceMethod for #handler_ident
|
impl #krate::ResourceMethod for #handler_ident
|
||||||
{
|
{
|
||||||
type Res = #ret;
|
type Res = #ret;
|
||||||
|
|
||||||
|
#operation_id
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #krate::#trait_ident for #handler_ident
|
impl #krate::#trait_ident for #handler_ident
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::{
|
||||||
|
Delimiter,
|
||||||
|
TokenStream as TokenStream2,
|
||||||
|
TokenTree
|
||||||
|
};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use std::{iter, iter::FromIterator};
|
||||||
use syn::{
|
use syn::{
|
||||||
|
Attribute,
|
||||||
|
AttributeArgs,
|
||||||
Field,
|
Field,
|
||||||
Fields,
|
Fields,
|
||||||
Generics,
|
Generics,
|
||||||
|
@ -9,6 +16,9 @@ use syn::{
|
||||||
Item,
|
Item,
|
||||||
ItemEnum,
|
ItemEnum,
|
||||||
ItemStruct,
|
ItemStruct,
|
||||||
|
Lit,
|
||||||
|
Meta,
|
||||||
|
NestedMeta,
|
||||||
Variant,
|
Variant,
|
||||||
parse_macro_input
|
parse_macro_input
|
||||||
};
|
};
|
||||||
|
@ -17,11 +27,12 @@ pub fn expand(tokens : TokenStream) -> TokenStream
|
||||||
{
|
{
|
||||||
let input = parse_macro_input!(tokens as Item);
|
let input = parse_macro_input!(tokens as Item);
|
||||||
|
|
||||||
match input {
|
let output = match input {
|
||||||
Item::Enum(item) => expand_enum(item),
|
Item::Enum(item) => expand_enum(item),
|
||||||
Item::Struct(item) => expand_struct(item),
|
Item::Struct(item) => expand_struct(item),
|
||||||
_ => panic!("derive(OpenapiType) not supported for this context")
|
_ => panic!("derive(OpenapiType) not supported for this context")
|
||||||
}.into()
|
};
|
||||||
|
output.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_where(generics : &Generics) -> TokenStream2
|
fn expand_where(generics : &Generics) -> TokenStream2
|
||||||
|
@ -47,6 +58,73 @@ fn expand_where(generics : &Generics) -> TokenStream2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct Attrs
|
||||||
|
{
|
||||||
|
nullable : bool,
|
||||||
|
rename : Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_string(lit : &Lit) -> String
|
||||||
|
{
|
||||||
|
match lit {
|
||||||
|
Lit::Str(str) => str.value(),
|
||||||
|
_ => panic!("Expected str, found {}", quote!(#lit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bool(lit : &Lit) -> bool
|
||||||
|
{
|
||||||
|
match lit {
|
||||||
|
Lit::Bool(bool) => bool.value,
|
||||||
|
_ => panic!("Expected bool, found {}", quote!(#lit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_parens(input : TokenStream2) -> TokenStream2
|
||||||
|
{
|
||||||
|
let iter = input.into_iter().flat_map(|tt| {
|
||||||
|
if let TokenTree::Group(group) = &tt
|
||||||
|
{
|
||||||
|
if group.delimiter() == Delimiter::Parenthesis
|
||||||
|
{
|
||||||
|
return Box::new(group.stream().into_iter()) as Box<dyn Iterator<Item = TokenTree>>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box::new(iter::once(tt))
|
||||||
|
});
|
||||||
|
let output = TokenStream2::from_iter(iter);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_attributes(input : &[Attribute]) -> Result<Attrs, syn::Error>
|
||||||
|
{
|
||||||
|
let mut parsed = Attrs::default();
|
||||||
|
for attr in input
|
||||||
|
{
|
||||||
|
if attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("openapi".to_owned())
|
||||||
|
{
|
||||||
|
let tokens = remove_parens(attr.tokens.clone());
|
||||||
|
let nested = parse_macro_input::parse::<AttributeArgs>(tokens.into())?;
|
||||||
|
for meta in nested
|
||||||
|
{
|
||||||
|
match &meta {
|
||||||
|
NestedMeta::Meta(Meta::NameValue(kv)) => match kv.path.segments.last().map(|s| s.ident.to_string()) {
|
||||||
|
Some(key) => match key.as_ref() {
|
||||||
|
"nullable" => parsed.nullable = to_bool(&kv.lit),
|
||||||
|
"rename" => parsed.rename = Some(to_string(&kv.lit)),
|
||||||
|
_ => panic!("Unexpected key: {}", key),
|
||||||
|
},
|
||||||
|
_ => panic!("Unexpected token: {}", quote!(#meta))
|
||||||
|
},
|
||||||
|
_ => panic!("Unexpected token: {}", quote!(#meta))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(parsed)
|
||||||
|
}
|
||||||
|
|
||||||
fn expand_variant(variant : &Variant) -> TokenStream2
|
fn expand_variant(variant : &Variant) -> TokenStream2
|
||||||
{
|
{
|
||||||
if variant.fields != Fields::Unit
|
if variant.fields != Fields::Unit
|
||||||
|
@ -56,8 +134,14 @@ fn expand_variant(variant : &Variant) -> TokenStream2
|
||||||
|
|
||||||
let ident = &variant.ident;
|
let ident = &variant.ident;
|
||||||
|
|
||||||
|
let attrs = parse_attributes(&variant.attrs).expect("Unable to parse attributes");
|
||||||
|
let name = match attrs.rename {
|
||||||
|
Some(rename) => rename,
|
||||||
|
None => ident.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
enumeration.push(stringify!(#ident).to_string());
|
enumeration.push(#name.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +152,13 @@ fn expand_enum(input : ItemEnum) -> TokenStream2
|
||||||
let generics = input.generics;
|
let generics = input.generics;
|
||||||
let where_clause = expand_where(&generics);
|
let where_clause = expand_where(&generics);
|
||||||
|
|
||||||
|
let attrs = parse_attributes(&input.attrs).expect("Unable to parse attributes");
|
||||||
|
let nullable = attrs.nullable;
|
||||||
|
let name = match attrs.rename {
|
||||||
|
Some(rename) => rename,
|
||||||
|
None => ident.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
let variants : Vec<TokenStream2> = input.variants.iter().map(expand_variant).collect();
|
let variants : Vec<TokenStream2> = input.variants.iter().map(expand_variant).collect();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
|
@ -89,8 +180,8 @@ fn expand_enum(input : ItemEnum) -> TokenStream2
|
||||||
}));
|
}));
|
||||||
|
|
||||||
OpenapiSchema {
|
OpenapiSchema {
|
||||||
name: Some(stringify!(#ident).to_string()),
|
name: Some(#name.to_string()),
|
||||||
nullable: false,
|
nullable: #nullable,
|
||||||
schema,
|
schema,
|
||||||
dependencies: Default::default()
|
dependencies: Default::default()
|
||||||
}
|
}
|
||||||
|
@ -107,6 +198,13 @@ fn expand_field(field : &Field) -> TokenStream2
|
||||||
};
|
};
|
||||||
let ty = &field.ty;
|
let ty = &field.ty;
|
||||||
|
|
||||||
|
let attrs = parse_attributes(&field.attrs).expect("Unable to parse attributes");
|
||||||
|
let nullable = attrs.nullable;
|
||||||
|
let name = match attrs.rename {
|
||||||
|
Some(rename) => rename,
|
||||||
|
None => ident.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
quote! {{
|
quote! {{
|
||||||
let mut schema = <#ty>::schema();
|
let mut schema = <#ty>::schema();
|
||||||
|
|
||||||
|
@ -114,7 +212,7 @@ fn expand_field(field : &Field) -> TokenStream2
|
||||||
{
|
{
|
||||||
schema.nullable = false;
|
schema.nullable = false;
|
||||||
}
|
}
|
||||||
else
|
else if !#nullable
|
||||||
{
|
{
|
||||||
required.push(stringify!(#ident).to_string());
|
required.push(stringify!(#ident).to_string());
|
||||||
}
|
}
|
||||||
|
@ -130,16 +228,16 @@ fn expand_field(field : &Field) -> TokenStream2
|
||||||
}
|
}
|
||||||
|
|
||||||
match schema.name.clone() {
|
match schema.name.clone() {
|
||||||
Some(name) => {
|
Some(schema_name) => {
|
||||||
properties.insert(
|
properties.insert(
|
||||||
stringify!(#ident).to_string(),
|
#name.to_string(),
|
||||||
ReferenceOr::Reference { reference: format!("#/components/schemas/{}", name) }
|
ReferenceOr::Reference { reference: format!("#/components/schemas/{}", schema_name) }
|
||||||
);
|
);
|
||||||
dependencies.insert(name, schema);
|
dependencies.insert(schema_name, schema);
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
properties.insert(
|
properties.insert(
|
||||||
stringify!(#ident).to_string(),
|
#name.to_string(),
|
||||||
ReferenceOr::Item(Box::new(schema.into_schema()))
|
ReferenceOr::Item(Box::new(schema.into_schema()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -154,6 +252,13 @@ pub fn expand_struct(input : ItemStruct) -> TokenStream2
|
||||||
let generics = input.generics;
|
let generics = input.generics;
|
||||||
let where_clause = expand_where(&generics);
|
let where_clause = expand_where(&generics);
|
||||||
|
|
||||||
|
let attrs = parse_attributes(&input.attrs).expect("Unable to parse attributes");
|
||||||
|
let nullable = attrs.nullable;
|
||||||
|
let name = match attrs.rename {
|
||||||
|
Some(rename) => rename,
|
||||||
|
None => ident.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
let fields : Vec<TokenStream2> = match input.fields {
|
let fields : Vec<TokenStream2> = match input.fields {
|
||||||
Fields::Named(fields) => {
|
Fields::Named(fields) => {
|
||||||
fields.named.iter().map(|field| expand_field(field)).collect()
|
fields.named.iter().map(|field| expand_field(field)).collect()
|
||||||
|
@ -185,8 +290,8 @@ pub fn expand_struct(input : ItemStruct) -> TokenStream2
|
||||||
}));
|
}));
|
||||||
|
|
||||||
OpenapiSchema {
|
OpenapiSchema {
|
||||||
name: Some(stringify!(#ident).to_string()),
|
name: Some(#name.to_string()),
|
||||||
nullable: false,
|
nullable: #nullable,
|
||||||
schema,
|
schema,
|
||||||
dependencies
|
dependencies
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub fn expand_resource(tokens : TokenStream) -> TokenStream
|
||||||
let krate = super::krate();
|
let krate = super::krate();
|
||||||
let input = parse_macro_input!(tokens as ItemStruct);
|
let input = parse_macro_input!(tokens as ItemStruct);
|
||||||
let ident = input.ident;
|
let ident = input.ident;
|
||||||
|
let name = ident.to_string();
|
||||||
|
|
||||||
let methods : Vec<TokenStream2> = input.attrs.into_iter().filter(|attr|
|
let methods : Vec<TokenStream2> = input.attrs.into_iter().filter(|attr|
|
||||||
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("rest_resource".to_string()) // TODO wtf
|
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("rest_resource".to_string()) // TODO wtf
|
||||||
|
@ -39,8 +40,8 @@ pub fn expand_resource(tokens : TokenStream) -> TokenStream
|
||||||
m.0.into_iter()
|
m.0.into_iter()
|
||||||
}).map(|method| {
|
}).map(|method| {
|
||||||
let method = Method::from_str(&method.to_string()).expect("unknown method");
|
let method = Method::from_str(&method.to_string()).expect("unknown method");
|
||||||
let mod_ident = method.mod_ident(ident.to_string());
|
let mod_ident = method.mod_ident(&name);
|
||||||
let ident = method.setup_ident(ident.to_string());
|
let ident = method.setup_ident(&name);
|
||||||
quote!(#mod_ident::#ident(&mut route);)
|
quote!(#mod_ident::#ident(&mut route);)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue