1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-02-22 20:52:27 +00:00

Idiomatify error handling code in gotham_derive

This commit is contained in:
msrd0 2020-04-12 19:58:05 +00:00
parent 08a8f3557b
commit d610103750
5 changed files with 51 additions and 64 deletions

View file

@ -4,6 +4,8 @@ use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
mod util;
mod from_body;
use from_body::expand_from_body;
mod method;

View file

@ -1,3 +1,4 @@
use crate::util::CollectToResult;
use heck::{CamelCase, SnakeCase};
use proc_macro::TokenStream;
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");
// extract arguments into pattern, ident and type
let mut args : Vec<MethodArgument> = Vec::new();
let mut errors : Vec<Error> = Vec::new();
for (i, arg) in fun.sig.inputs.iter().enumerate()
{
let a = match arg {
let args = fun.sig.inputs.iter()
.enumerate()
.map(|(i, arg)| match arg {
FnArg::Typed(arg) => interpret_arg(i, arg),
FnArg::Receiver(_) => Err(Error::new(arg.span(), "Didn't expect self parameter"))
};
match a {
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 }));
}
})
.collect_to_result()?;
// extract the generic parameters to use
let ty_names = method.type_names();

View file

@ -1,3 +1,4 @@
use crate::util::CollectToResult;
use proc_macro::TokenStream;
use proc_macro2::{
Delimiter,
@ -163,21 +164,9 @@ fn expand_enum(input : ItemEnum) -> Result<TokenStream2, Error>
None => ident.to_string()
};
let mut variants : Vec<TokenStream2> = Vec::new();
let mut errors : Vec<Error> = Vec::new();
for variant in input.variants.iter().map(expand_variant)
{
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 }));
}
let variants = input.variants.iter()
.map(expand_variant)
.collect_to_result()?;
Ok(quote! {
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 {
Fields::Named(named_fields) => {
let mut fields : Vec<TokenStream2> = Vec::new();
let mut errors : Vec<Error> = Vec::new();
for field in named_fields.named.iter().map(expand_field)
{
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
named_fields.named.iter()
.map(expand_field)
.collect_to_result()?
},
Fields::Unnamed(fields) => return Err(Error::new(fields.span(), "Unnamed fields are not supported")),
Fields::Unit => Vec::new()

View file

@ -1,6 +1,8 @@
use crate::util::CollectToResult;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use std::iter;
use syn::{
parse::{Parse, ParseStream, Result as SynResult},
punctuated::Punctuated,
@ -61,22 +63,13 @@ fn expand(tokens : TokenStream) -> Result<TokenStream2, Error>
let ident = input.ident;
let generics = input.generics;
let mut types : Vec<Path> = Vec::new();
let mut errors : Vec<Error> = Vec::new();
for attr in input.attrs.into_iter().filter(|attr|
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("supported_types".to_string()) // TODO wtf
) {
match syn::parse2::<MimeList>(attr.tokens) {
Ok(m) => types.extend(m.0),
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 = input.attrs.into_iter()
.filter(|attr| attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("supported_types".to_string()))
.flat_map(|attr|
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>>>)
.unwrap_or_else(|err| Box::new(iter::once(Err(err)))))
.collect_to_result()?;
let types = match types {
ref types if types.is_empty() => quote!(None),

View 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) }
}
})
}
}