use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{format_ident, quote}; use syn::{ parse::{Parse, ParseStream}, parse_macro_input, token::Comma, Ident, LitInt, Result, }; struct InputInfo { macro_ident: Ident, start: usize, end: usize, } impl Parse for InputInfo { fn parse(input: ParseStream) -> Result { let macro_ident = input.parse::()?; input.parse::()?; let start = input.parse::()?.base10_parse()?; input.parse::()?; let end = input.parse::()?.base10_parse()?; Ok(Self { macro_ident, start, end, }) } } struct TupleType { little: Ident, big: Ident, } #[proc_macro] pub fn implement_pair_update(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as InputInfo); let mut generic_count = Vec::new(); for lhs in input.start..=input.end { for rhs in input.start..=input.end { generic_count.push((lhs, rhs)); } } let generic_tuples: Vec<(Vec, Vec)> = generic_count .iter() .map(|(lhs_count, rhs_count)| { let lhs = (input.start..(input.start + lhs_count)) .map(|i| TupleType { little: format_ident!("l{}", i), big: format_ident!("L{}", i), }) .collect(); let rhs = (input.start..(input.start + rhs_count)) .map(|i| TupleType { little: format_ident!("r{}", i), big: format_ident!("R{}", i), }) .collect(); (lhs, rhs) }) .collect(); let invocations: Vec = generic_tuples .iter() .map(|(lhs, rhs)| { let lhs_expr = LitInt::new(&format!("{}", lhs.len()), Span::call_site()); let rhs_expr = LitInt::new(&format!("{}", rhs.len()), Span::call_site()); let lhs_args: Vec = lhs .iter() .map(|tuple| { let little = &tuple.little; let big = &tuple.big; quote! { [#little: #big], } }) .collect(); let rhs_args: Vec = rhs .iter() .map(|tuple| { let little = &tuple.little; let big = &tuple.big; quote! { [#little: #big], } }) .collect(); let macro_ident = &input.macro_ident; quote! { #macro_ident!( #lhs_expr, (#(#lhs_args)*), #rhs_expr, (#(#rhs_args)*) ); } }) .collect(); TokenStream::from(quote! { #( #invocations )* }) }