diff --git a/src/lib.rs b/src/lib.rs index 4ccbfd9..a56122a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,19 +3,18 @@ use quote::quote; use syn::{parse_macro_input, ItemEnum, DeriveInput, Fields, 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(_) => { + // Impl for struct: deserialize entire response body as Self quote! { #[async_trait::async_trait] impl Responsable for #name @@ -23,30 +22,26 @@ pub fn http_response(_attr: TokenStream, item: TokenStream) -> TokenStream { Self: serde::de::DeserializeOwned + Sized + Send, { async fn receive(mut resp: actix_web::ClientResponse) -> Result> { - let parsed = resp.json::().await - .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; + let parsed = resp.json::().await?; Ok(parsed) } } } } Data::Enum(data_enum) => { - // For each tuple-like variant with one field, try to parse resp body as that inner type + // Impl for enum with tuple variants of length 1 (newtype variants) let variant_arms = data_enum.variants.iter().filter_map(|variant| { let vname = &variant.ident; - if let Fields::Unnamed(fields) = &variant.fields { - if fields.unnamed.len() == 1 { + match &variant.fields { + Fields::Unnamed(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 } - } else { - None + _ => None, } }); @@ -57,11 +52,8 @@ pub fn http_response(_attr: TokenStream, item: TokenStream) -> TokenStream { 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()))?; - + let body = resp.body().await?; #(#variant_arms)* - Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, concat!("No matching enum variant in ", stringify!(#name)) @@ -73,10 +65,8 @@ 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