diff --git a/src/lib.rs b/src/lib.rs index e733501..8405e1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,12 +5,15 @@ use syn::{parse_macro_input, ItemEnum, DeriveInput, Data}; #[proc_macro_attribute] pub fn http_response(_attr: TokenStream, item: TokenStream) -> TokenStream { + // Clone the input for multiple parsing let item_for_ast = item.clone(); let item_for_quote = item.clone(); + // Parse the input into a syntax tree let ast: DeriveInput = parse_macro_input!(item_for_ast as DeriveInput); let name = &ast.ident; + // Generate impl block depending on struct or enum let impl_block = match &ast.data { Data::Struct(_) => { quote! { @@ -27,26 +30,32 @@ pub fn http_response(_attr: TokenStream, item: TokenStream) -> TokenStream { } } } - Data::Enum(data_enum) => { + // For each tuple-like variant with one field, try to parse resp body as that inner type let variant_arms = data_enum.variants.iter().filter_map(|variant| { let vname = &variant.ident; - match &variant.fields { - syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { + if let Fields::Unnamed(fields) = &variant.fields { + if fields.unnamed.len() == 1 { let inner_ty = &fields.unnamed.first().unwrap().ty; Some(quote! { if let Ok(inner) = serde_json::from_slice::<#inner_ty>(&body) { return Ok(#name::#vname(inner)); } }) + } else { + None } - _ => None, + } else { + None } }); quote! { #[async_trait::async_trait] - impl Responsable for #name { + impl Responsable for #name + where + Self: Sized + Send, + { async fn receive(mut resp: actix_web::ClientResponse) -> Result> { let body = resp.body().await .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; @@ -61,12 +70,13 @@ pub fn http_response(_attr: TokenStream, item: TokenStream) -> TokenStream { } } } - _ => panic!("#[http_response] only supports structs and tuple-style enum variants"), }; + // Parse the original item as syn::Item (struct or enum) let original: syn::Item = syn::parse(item_for_quote).expect("Failed to parse item as syn::Item"); + // Return original plus generated impl block let output = quote! { #original #impl_block