#[macro_export] macro_rules! system { ($name:ident ( $($pat:tt)* ) { $($rest:tt)* } ) => { pub struct $name; impl<'a> specs::System<'a> for $name { type SystemData = args_to_systemdata!(($($pat)*,)); fn run(&mut self, args_to_fn_pat!(($($pat)*)): Self::SystemData) { use specs::join::Join; for args_to_join_pat!(($($pat)*,)) in args_to_join!(($($pat)*,)).join() { $($rest)* } } } }; ($name:ident $pat:tt { $($rest:tt)* } finally { $($finally:tt)* }) => { pub struct $name; impl<'a> specs::System<'a> for $name { type SystemData = args_to_systemdata!($pat); fn run(&mut self, args_to_fn_pat!($pat): Self::SystemData) { use specs::join::Join; for args_to_join_pat!($pat) in args_to_join!($pat).join() { $($rest)* } $($finally)* } } }; } #[macro_export] macro_rules! system_impl { ($name:ident ( $($pat:tt)* ) { $($rest:tt)* } ) => { pub struct $name; impl<'a> specs::System<'a> for $name { type SystemData = args_to_systemdata!(($($pat)*,)); fn run(&mut self, args_to_fn_pat!(($($pat)*)): Self::SystemData) { use specs::join::Join; $($rest)* } } }; } #[macro_export] macro_rules! args_to_systemdata { ( ( $name:ident : Entity $(,)? ) ) => { ( specs::Entities<'a>, ) }; ( ( $name:ident : $ty:ty $(,)? ) ) => { ( specs::ReadStorage<'a, $ty> ,) }; ( ( mut $name:ident : $ty:ty $(,)? ) ) => { ( specs::WriteStorage<'a, $ty> ,) }; ( ( resource $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( resource mut $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( $name:ident : Entity , $($tok:tt)* ) ) => { ( specs::Entities<'a>, args_to_systemdata!( ( $( $tok )* ) ) ) }; ( ( $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( specs::ReadStorage<'a, $ty>, args_to_systemdata!( ( $( $tok )* ) ) ) }; ( ( mut $name:ident : $ty:ty , $( $tok:tt )* ) ) => { ( specs::WriteStorage<'a, $ty>, args_to_systemdata!( ( $( $tok )* ) ) ) }; ( ( resource $name:ident : $ty:ty , $( $tok:tt )* ) ) => { ( specs::ReadExpect<'a, $ty>, args_to_systemdata!( ( $( $tok )* ) ) ) }; ( ( resource mut $name:ident : $ty:ty , $( $tok:tt )* ) ) => { ( specs::WriteExpect<'a, $ty>, args_to_systemdata!( ( $( $tok )* ) ) ) }; } #[macro_export] macro_rules! args_to_fn_pat { ( ( $name:ident : $ty:ty $(,)? ) ) => { ( $name ,) }; ( ( mut $name:ident : $ty:ty $(,)? ) ) => { ( mut $name ,) }; ( ( resource $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( resource mut $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( $name, args_to_fn_pat!( ( $($tok)* ) ) ) }; ( ( mut $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( mut $name, args_to_fn_pat!( ( $($tok)* ) ) ) }; ( ( resource $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( $name, args_to_fn_pat!( ( $($tok)* ) ) ) }; ( ( resource mut $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( mut $name, args_to_fn_pat!( ( $($tok)* ) ) ) }; } #[macro_export] macro_rules! args_to_join_pat { ( ( $name:ident : $ty:ty $(,)? ) ) => { ( $name ,) }; ( ( mut $name:ident : $ty:ty $(,)? ) ) => { ( mut $name ,) }; ( ( resource $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( resource mut $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( $name, args_to_join_pat!( ( $($tok)* ) ) ) }; ( ( mut $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( mut $name, args_to_join_pat!( ( $($tok)* ) ) ) }; ( ( resource $name:ident : $ty:ty , $($tok:tt)* ) ) => { args_to_join_pat!( ( $($tok)* ) ) }; ( ( resource mut $name:ident : $ty:ty , $($tok:tt)* ) ) => { args_to_join_pat!( ( $($tok)* ) ) }; } #[macro_export] macro_rules! args_to_join { ( ( $name:ident : $ty:ty $(,)? ) ) => { ( & $name ,) }; ( ( mut $name:ident : $ty:ty $(,)? ) ) => { ( &mut $name ,) }; ( ( resource $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( resource mut $name:ident : $ty:ty $(,)? ) ) => { compile_error!("Resources cannot come at the end of the argument block.") }; ( ( $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( & $name, args_to_join!( ( $($tok)* ) ) ) }; ( ( mut $name:ident : $ty:ty , $($tok:tt)* ) ) => { ( &mut $name, args_to_join!( ( $($tok)* ) ) ) }; ( ( resource $name:ident : $ty:ty , $($tok:tt)* ) ) => { args_to_join!( ( $($tok)* ) ) }; ( ( resource mut $name:ident : $ty:ty , $($tok:tt)* ) ) => { args_to_join!( ( $($tok)* ) ) }; } #[cfg(test)] mod tests { pub struct Pos { x: usize, } impl specs::Component for Pos { type Storage = specs::VecStorage; } pub struct Mov; impl specs::Component for Mov { type Storage = specs::VecStorage; } system! { Foo (_x: Mov, mut y: Pos) { y.x += 1; } } system_impl! { FooAlt (x: Mov, mut y: Pos) { for (_, mut y) in (&x, &mut y).join() { y.x += 1; } } } system! { Bar (_x: Mov, mut y: Pos) { y.x += 1; } finally { println!("Done!"); } } system_impl! { BarAlt (x: Mov, mut y: Pos) { for (_, mut y) in (&x, &mut y).join() { y.x += 1; } println!("Done!"); } } system! { Baz (resource n: usize, _x: Mov, mut y: Pos) { y.x += *n; } } system_impl! { BazAlt (resource n: usize, x: Mov, mut y: Pos) { for (_, mut y) in (&x, &mut y).join() { y.x += *n; } } } system! { Quux (resource mut n: usize, _x: Mov, mut y: Pos) { y.x += *n; *n += 1; } finally { *n += 1; } } system_impl! { QuuxAlt (resource mut n: usize, x: Mov, mut y: Pos) { for (_, mut y) in (&x, &mut y).join() { y.x += *n; } *n += 1; } } system! { Pippo (_e: Entity, _x: Mov, mut y: Pos) { y.x += 1; } } system_impl! { PippoAlt (_e: Entity, x: Mov, mut y: Pos) { for (_, mut y) in (&x, &mut y).join() { y.x += 1; } } } }