mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-23 04:52:28 +00:00
Idiomatify error handling code in gotham_derive
This commit is contained in:
parent
08a8f3557b
commit
d610103750
5 changed files with 51 additions and 64 deletions
|
@ -4,6 +4,8 @@ use proc_macro::TokenStream;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
|
mod util;
|
||||||
|
|
||||||
mod from_body;
|
mod from_body;
|
||||||
use from_body::expand_from_body;
|
use from_body::expand_from_body;
|
||||||
mod method;
|
mod method;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::util::CollectToResult;
|
||||||
use heck::{CamelCase, SnakeCase};
|
use heck::{CamelCase, SnakeCase};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
|
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
|
||||||
|
@ -320,25 +321,13 @@ fn expand(method : Method, attrs : TokenStream, item : TokenStream) -> Result<To
|
||||||
let auth_ident = format_ident!("auth");
|
let auth_ident = format_ident!("auth");
|
||||||
|
|
||||||
// extract arguments into pattern, ident and type
|
// extract arguments into pattern, ident and type
|
||||||
let mut args : Vec<MethodArgument> = Vec::new();
|
let args = fun.sig.inputs.iter()
|
||||||
let mut errors : Vec<Error> = Vec::new();
|
.enumerate()
|
||||||
for (i, arg) in fun.sig.inputs.iter().enumerate()
|
.map(|(i, arg)| match arg {
|
||||||
{
|
|
||||||
let a = match arg {
|
|
||||||
FnArg::Typed(arg) => interpret_arg(i, arg),
|
FnArg::Typed(arg) => interpret_arg(i, arg),
|
||||||
FnArg::Receiver(_) => Err(Error::new(arg.span(), "Didn't expect self parameter"))
|
FnArg::Receiver(_) => Err(Error::new(arg.span(), "Didn't expect self parameter"))
|
||||||
};
|
})
|
||||||
match a {
|
.collect_to_result()?;
|
||||||
Ok(a) => args.push(a),
|
|
||||||
Err(e) => errors.push(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !errors.is_empty()
|
|
||||||
{
|
|
||||||
let mut iter = errors.into_iter();
|
|
||||||
let first = iter.nth(0).unwrap();
|
|
||||||
return Err(iter.fold(first, |mut e0, e1| { e0.combine(e1); e0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract the generic parameters to use
|
// extract the generic parameters to use
|
||||||
let ty_names = method.type_names();
|
let ty_names = method.type_names();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::util::CollectToResult;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{
|
use proc_macro2::{
|
||||||
Delimiter,
|
Delimiter,
|
||||||
|
@ -163,21 +164,9 @@ fn expand_enum(input : ItemEnum) -> Result<TokenStream2, Error>
|
||||||
None => ident.to_string()
|
None => ident.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut variants : Vec<TokenStream2> = Vec::new();
|
let variants = input.variants.iter()
|
||||||
let mut errors : Vec<Error> = Vec::new();
|
.map(expand_variant)
|
||||||
for variant in input.variants.iter().map(expand_variant)
|
.collect_to_result()?;
|
||||||
{
|
|
||||||
match variant {
|
|
||||||
Ok(variant) => variants.push(variant),
|
|
||||||
Err(e) => errors.push(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !errors.is_empty()
|
|
||||||
{
|
|
||||||
let mut iter = errors.into_iter();
|
|
||||||
let first = iter.nth(0).unwrap();
|
|
||||||
return Err(iter.fold(first, |mut e0, e1| { e0.combine(e1); e0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
impl #generics #krate::OpenapiType for #ident #generics
|
impl #generics #krate::OpenapiType for #ident #generics
|
||||||
|
@ -279,22 +268,9 @@ pub fn expand_struct(input : ItemStruct) -> Result<TokenStream2, Error>
|
||||||
|
|
||||||
let fields : Vec<TokenStream2> = match input.fields {
|
let fields : Vec<TokenStream2> = match input.fields {
|
||||||
Fields::Named(named_fields) => {
|
Fields::Named(named_fields) => {
|
||||||
let mut fields : Vec<TokenStream2> = Vec::new();
|
named_fields.named.iter()
|
||||||
let mut errors : Vec<Error> = Vec::new();
|
.map(expand_field)
|
||||||
for field in named_fields.named.iter().map(expand_field)
|
.collect_to_result()?
|
||||||
{
|
|
||||||
match field {
|
|
||||||
Ok(field) => fields.push(field),
|
|
||||||
Err(e) => errors.push(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !errors.is_empty()
|
|
||||||
{
|
|
||||||
let mut iter = errors.into_iter();
|
|
||||||
let first = iter.nth(0).unwrap();
|
|
||||||
return Err(iter.fold(first, |mut e0, e1| { e0.combine(e1); e0 }));
|
|
||||||
}
|
|
||||||
fields
|
|
||||||
},
|
},
|
||||||
Fields::Unnamed(fields) => return Err(Error::new(fields.span(), "Unnamed fields are not supported")),
|
Fields::Unnamed(fields) => return Err(Error::new(fields.span(), "Unnamed fields are not supported")),
|
||||||
Fields::Unit => Vec::new()
|
Fields::Unit => Vec::new()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
use crate::util::CollectToResult;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use std::iter;
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream, Result as SynResult},
|
parse::{Parse, ParseStream, Result as SynResult},
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
|
@ -61,22 +63,13 @@ fn expand(tokens : TokenStream) -> Result<TokenStream2, Error>
|
||||||
let ident = input.ident;
|
let ident = input.ident;
|
||||||
let generics = input.generics;
|
let generics = input.generics;
|
||||||
|
|
||||||
let mut types : Vec<Path> = Vec::new();
|
let types = input.attrs.into_iter()
|
||||||
let mut errors : Vec<Error> = Vec::new();
|
.filter(|attr| attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("supported_types".to_string()))
|
||||||
for attr in input.attrs.into_iter().filter(|attr|
|
.flat_map(|attr|
|
||||||
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("supported_types".to_string()) // TODO wtf
|
syn::parse2::<MimeList>(attr.tokens)
|
||||||
) {
|
.map(|list| Box::new(list.0.into_iter().map(|mime| Ok(mime))) as Box<dyn Iterator<Item = Result<Path, Error>>>)
|
||||||
match syn::parse2::<MimeList>(attr.tokens) {
|
.unwrap_or_else(|err| Box::new(iter::once(Err(err)))))
|
||||||
Ok(m) => types.extend(m.0),
|
.collect_to_result()?;
|
||||||
Err(e) => errors.push(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !errors.is_empty()
|
|
||||||
{
|
|
||||||
let mut iter = errors.into_iter();
|
|
||||||
let first = iter.nth(0).unwrap();
|
|
||||||
return Err(iter.fold(first, |mut e0, e1| { e0.combine(e1); e0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
let types = match types {
|
let types = match types {
|
||||||
ref types if types.is_empty() => quote!(None),
|
ref types if types.is_empty() => quote!(None),
|
||||||
|
|
27
gotham_restful_derive/src/util.rs
Normal file
27
gotham_restful_derive/src/util.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
use syn::Error;
|
||||||
|
|
||||||
|
pub trait CollectToResult
|
||||||
|
{
|
||||||
|
type Item;
|
||||||
|
|
||||||
|
fn collect_to_result(self) -> Result<Vec<Self::Item>, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Item, I> CollectToResult for I
|
||||||
|
where
|
||||||
|
I : Iterator<Item = Result<Item, Error>>
|
||||||
|
{
|
||||||
|
type Item = Item;
|
||||||
|
|
||||||
|
fn collect_to_result(self) -> Result<Vec<Item>, Error>
|
||||||
|
{
|
||||||
|
self.fold(<Result<Vec<Item>, Error>>::Ok(Vec::new()), |res, code| {
|
||||||
|
match (code, res) {
|
||||||
|
(Ok(code), Ok(mut codes)) => { codes.push(code); Ok(codes) },
|
||||||
|
(Ok(_), Err(errors)) => Err(errors),
|
||||||
|
(Err(err), Ok(_)) => Err(err),
|
||||||
|
(Err(err), Err(mut errors)) => { errors.combine(err); Err(errors) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue