2020-04-12 19:58:05 +00:00
|
|
|
use crate::util::CollectToResult;
|
2020-05-04 19:08:22 +02:00
|
|
|
use proc_macro2::{Ident, TokenStream};
|
2019-10-20 14:49:53 +00:00
|
|
|
use quote::quote;
|
2020-04-12 19:58:05 +00:00
|
|
|
use std::iter;
|
2019-10-20 14:49:53 +00:00
|
|
|
use syn::{
|
2020-05-04 19:08:22 +02:00
|
|
|
parse::{Parse, ParseStream},
|
2019-10-20 14:49:53 +00:00
|
|
|
punctuated::Punctuated,
|
2020-05-19 21:07:29 +02:00
|
|
|
spanned::Spanned,
|
2020-09-15 15:10:41 +02:00
|
|
|
DeriveInput, Error, Generics, Path, Result, Token
|
2019-10-20 14:49:53 +00:00
|
|
|
};
|
|
|
|
|
2020-05-03 23:25:48 +02:00
|
|
|
struct MimeList(Punctuated<Path, Token![,]>);
|
2019-10-20 14:49:53 +00:00
|
|
|
|
2020-09-15 15:10:41 +02:00
|
|
|
impl Parse for MimeList {
|
2021-01-18 01:05:56 +01:00
|
|
|
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
2020-05-19 21:07:29 +02:00
|
|
|
let list = Punctuated::parse_separated_nonempty(&input)?;
|
2019-10-20 14:49:53 +00:00
|
|
|
Ok(Self(list))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "openapi"))]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn impl_openapi_type(_ident: &Ident, _generics: &Generics) -> TokenStream {
|
2019-10-20 14:49:53 +00:00
|
|
|
quote!()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn impl_openapi_type(ident: &Ident, generics: &Generics) -> TokenStream {
|
2019-10-20 14:49:53 +00:00
|
|
|
let krate = super::krate();
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
quote! {
|
|
|
|
impl #generics #krate::OpenapiType for #ident #generics
|
|
|
|
{
|
|
|
|
fn schema() -> #krate::OpenapiSchema
|
|
|
|
{
|
|
|
|
use #krate::{export::openapi::*, OpenapiSchema};
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
OpenapiSchema::new(SchemaKind::Type(Type::String(StringType {
|
|
|
|
format: VariantOrUnknownOrEmpty::Item(StringFormat::Binary),
|
2020-01-17 21:37:41 +01:00
|
|
|
..Default::default()
|
2019-10-20 14:49:53 +00:00
|
|
|
})))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 15:10:41 +02:00
|
|
|
pub fn expand_request_body(input: DeriveInput) -> Result<TokenStream> {
|
2019-10-20 14:49:53 +00:00
|
|
|
let krate = super::krate();
|
|
|
|
let ident = input.ident;
|
|
|
|
let generics = input.generics;
|
2020-09-15 15:10:41 +02:00
|
|
|
|
|
|
|
let types = input
|
|
|
|
.attrs
|
|
|
|
.into_iter()
|
|
|
|
.filter(|attr| {
|
|
|
|
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("supported_types".to_string())
|
|
|
|
})
|
2020-05-19 21:07:29 +02:00
|
|
|
.flat_map(|attr| {
|
|
|
|
let span = attr.span();
|
|
|
|
attr.parse_args::<MimeList>()
|
2020-05-04 19:08:22 +02:00
|
|
|
.map(|list| Box::new(list.0.into_iter().map(Ok)) as Box<dyn Iterator<Item = Result<Path>>>)
|
2020-05-19 21:07:29 +02:00
|
|
|
.unwrap_or_else(|mut err| {
|
2020-09-15 15:10:41 +02:00
|
|
|
err.combine(Error::new(
|
|
|
|
span,
|
|
|
|
"Hint: Types list should look like #[supported_types(TEXT_PLAIN, APPLICATION_JSON)]"
|
|
|
|
));
|
2020-05-19 21:07:29 +02:00
|
|
|
Box::new(iter::once(Err(err)))
|
|
|
|
})
|
|
|
|
})
|
2020-04-12 19:58:05 +00:00
|
|
|
.collect_to_result()?;
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
let types = match types {
|
|
|
|
ref types if types.is_empty() => quote!(None),
|
|
|
|
types => quote!(Some(vec![#(#types),*]))
|
|
|
|
};
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
let impl_openapi_type = impl_openapi_type(&ident, &generics);
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-04-07 23:01:26 +02:00
|
|
|
Ok(quote! {
|
2019-10-20 14:49:53 +00:00
|
|
|
impl #generics #krate::RequestBody for #ident #generics
|
|
|
|
where #ident #generics : #krate::FromBody
|
|
|
|
{
|
|
|
|
fn supported_types() -> Option<Vec<#krate::Mime>>
|
|
|
|
{
|
|
|
|
#types
|
|
|
|
}
|
|
|
|
}
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
#impl_openapi_type
|
2020-04-07 23:01:26 +02:00
|
|
|
})
|
|
|
|
}
|