diff --git a/src/lib.rs b/src/lib.rs index c44c7c9..7725152 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -248,3 +248,59 @@ pub fn alpaca_cli(_attr: TokenStream, item: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +#[proc_macro_attribute] +pub fn api_dispatch(attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as syn::ItemEnum); + let enum_ident = &input.ident; + + // Parse attribute input: input = "MyQuery" + let meta_args = attr.to_string(); + let input_type: syn::Ident = { + let cleaned = meta_args.trim().replace("input", "").replace('=', "").replace('"', "").trim().to_string(); + syn::Ident::new(&cleaned, proc_macro2::Span::call_site()) + }; + + let expanded = quote! { + #input + + impl ApiDispatch for #enum_ident { + fn send_all( + &self, + client: &awc::Client, + keys: &std::collections::HashMap, + ) -> std::pin::Pin>> + Send>> { + Box::pin(async move { + match self { + #enum_ident::Single { query } => { + let parsed: #input_type = serde_json::from_str(query)?; + parsed.send(client, keys).await?; + } + #enum_ident::Bulk { input } => { + let json = if let Some(raw) = input { + if std::path::Path::new(&raw).exists() { + std::fs::read_to_string(raw)? + } else { + raw.clone() + } + } else { + use std::io::Read; + let mut buf = String::new(); + std::io::stdin().read_to_string(&mut buf)?; + buf + }; + + let items: Vec<#input_type> = serde_json::from_str(&json)?; + for item in items { + item.send(client, keys).await?; + } + } + } + Ok(()) + }) + } + } + }; + + TokenStream::from(expanded) +}