engine/scene_update_macros/src/lib.rs
2024-08-23 13:22:09 +02:00

117 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
)*
})
}