fn foo<T> { println!("foo: {:?}", std::any::type_name::<T>()); }
let functions = (foo::<i32>,build_fn!(i64,u64,f32,f64;foo),foo::<u32>);
// the final `functions` is
let functions = (foo::<i32>, foo::<i64>, foo::<u64>, foo::<f32>, foo::<f64> ,foo::<u32>);
// maybe more complex like build_fn!(i64,u64,f32,f64;foo,boo)
Is it possible to write build_fn
macro ?
------------- edit line --------------
In my case, I was doing something with bevy. I managed to get something like this. Which is little ackward solution, but still working thanks to the flexibility of bevy ecs.
macro_rules! unit_team_system {
($($team:ty),* ; $sys:tt) => {
($(unit_team_system!(@make_fun $team; $sys),)*)
};
(@make_fun $team:ty; ($($sys:ident),* $(,)?) ) =>{
($($sys::<$team>,)*)
};
}
#[derive(Debug)]
struct TeamA;
#[derive(Debug)]
struct TeamB;
#[derive(Debug)]
struct TeamC;
fn system_a<T>() {
println!("system_a: {:?}", std::any::type_name::<T>());
}
fn system_b<T>() {
println!("system_b: {:?}", std::any::type_name::<T>());
}
fn main() {
let systems = unit_team_system!(TeamA, TeamB, TeamC;
(
system_a,
system_b,
)
);
systems.1.0();
}
----------------- proc_macro -----------------
Still not posssible to generate subitems of a tuple.
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{Ident, Token, Type};
use syn::parse::{Parse, ParseStream};
struct UnitTeamSystem {
teams: Vec<Type>,
systems: Vec<Ident>,
}
impl Parse for UnitTeamSystem {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut teams = Vec::new();
let mut systems = Vec::new();
while !input.is_empty() {
if input.peek(Token![;]) {
break;
}
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
let team: Type = input.parse()?;
teams.push(team);
}
input.parse::<Token![;]>()?;
while !input.is_empty() {
let system: Ident = input.parse()?;
systems.push(system);
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
}
Ok(UnitTeamSystem {
teams,
systems,
})
}
}
#[proc_macro]
pub fn unit_team_system(input: TokenStream) -> TokenStream {
let UnitTeamSystem { teams, systems } = syn::parse_macro_input!(input as UnitTeamSystem);
let mut tokens = Vec::with_capacity(teams.len());
for team in teams {
for system in &systems {
tokens.push(quote! {
#system::<#team>,
});
}
}
eprintln!("{:?}", tokens);
TokenStream::from(quote! {
(#(#tokens)*)
})
}
Is it possible to write
build_fn
macro ?
Not with declarative macros, because a declarative macro has to generate an entire language item (statement, expression, type, pattern, ...).
Here you're trying to generate a section of tuple, which is not an item of the rust language.
It might be possible using a procedural macro, because IIRC procedural macros operate in terms of token streams, so while they are generally used to generate items, they might be able to generate sub-items or partial items (I've never actually used them that way).