118 lines
3 KiB
Rust
118 lines
3 KiB
Rust
|
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<Self> {
|
||
|
let macro_ident = input.parse::<Ident>()?;
|
||
|
input.parse::<Comma>()?;
|
||
|
let start = input.parse::<LitInt>()?.base10_parse()?;
|
||
|
input.parse::<Comma>()?;
|
||
|
let end = input.parse::<LitInt>()?.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<TupleType>, Vec<TupleType>)> = 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<TokenStream2> = 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<TokenStream2> = lhs
|
||
|
.iter()
|
||
|
.map(|tuple| {
|
||
|
let little = &tuple.little;
|
||
|
let big = &tuple.big;
|
||
|
|
||
|
quote! {
|
||
|
[#little: #big],
|
||
|
}
|
||
|
})
|
||
|
.collect();
|
||
|
|
||
|
let rhs_args: Vec<TokenStream2> = 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
|
||
|
)*
|
||
|
})
|
||
|
}
|