working??
This commit is contained in:
		
							
								
								
									
										22
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								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<Self, Box<dyn std::error::Error>> { | ||||
|                         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 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user