From 808cb77040131b793397ff506af4841aa38970f9 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Fri, 8 Dec 2023 18:10:08 -0500 Subject: [PATCH] Implement multiple argument fn systems --- lyra-ecs/src/system/mod.rs | 108 ++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/lyra-ecs/src/system/mod.rs b/lyra-ecs/src/system/mod.rs index 800210f..5fc677d 100644 --- a/lyra-ecs/src/system/mod.rs +++ b/lyra-ecs/src/system/mod.rs @@ -41,42 +41,60 @@ pub struct FnSystem { args: Args, } -impl System for FnSystem -where - A: FnArgFetcher, - F: for<'a> FnMut(A::Arg<'a>) -> anyhow::Result<()>, -{ - fn world_access(&self) -> Access { - todo!() - } +macro_rules! impl_fn_system_tuple { + ( $($name: ident),+ ) => ( + #[allow(non_snake_case)] + impl System for FnSystem + where + F: for<'a> FnMut($($name::Arg<'a>,)+) -> anyhow::Result<()>, + { + fn world_access(&self) -> Access { + todo!() + } - fn execute(&mut self, world: NonNull) -> anyhow::Result<()> { - let mut a = A::new(); + fn execute(&mut self, world: NonNull) -> anyhow::Result<()> { + $(let $name = unsafe { $name::new().get(world) };)+ - let a = unsafe { a.get(world) }; - - (self.inner)(a)?; - - Ok(()) - } -} - -impl IntoSystem for F -where - A: FnArg, - F: FnMut(A) -> anyhow::Result<()>, - F: for<'a> FnMut(::Arg<'a>) -> anyhow::Result<()>, -{ - type System = FnSystem; - - fn into_system(self) -> Self::System { - FnSystem { - args: A::Fetcher::new(), - inner: self + (self.inner)($($name,)+)?; + + Ok(()) + } } - } + + impl IntoSystem<($($name,)+)> for F + where + F: FnMut($($name,)+) -> anyhow::Result<()>, + F: for<'a> FnMut($(<$name::Fetcher as FnArgFetcher>::Arg<'a>,)+) -> anyhow::Result<()>, + { + type System = FnSystem; + + fn into_system(self) -> Self::System { + FnSystem { + args: ($($name::Fetcher::new(),)+), + inner: self + } + } + } + ); } +// Hopefully up to 16 arguments in a system is good enough. +impl_fn_system_tuple!{ A } +impl_fn_system_tuple!{ A, B } +impl_fn_system_tuple!{ A, B, C } +impl_fn_system_tuple!{ A, B, C, D } +impl_fn_system_tuple!{ A, B, C, D, E } +impl_fn_system_tuple!{ A, B, C, D, E, F2 } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H, I } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H, I, J } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H, I, J, K, L } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H, I, J, K, L, M } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H, I, J, K, L, M, N } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H, I, J, K, L, M, N, O } +impl_fn_system_tuple!{ A, B, C, D, E, F2, G, H, I, J, K, L, M, N, O, P } + /// An ArgFetcher implementation for query [`View`]s pub struct ViewArgFetcher { query: Q @@ -95,6 +113,10 @@ impl FnArgFetcher for ViewArgFetcher { } } + fn world_access(&self) -> Access { + todo!() + } + unsafe fn get<'a>(&mut self, world: NonNull) -> Self::Arg<'a> { let world = &*world.as_ptr(); let arch = world.archetypes.values().collect(); @@ -237,7 +259,7 @@ mod tests { } #[test] - fn multi_system() { + fn multi_view_system() { let mut world = World::new(); world.spawn((Vec2::rand(), Vec3::rand())); world.spawn((Vec2::rand(), Vec3::rand())); @@ -307,4 +329,26 @@ mod tests { let counter = world.get_resource::(); assert_eq!(counter.0, 10); } + + #[test] + fn multi_arg_system() { + let mut world = World::new(); + world.spawn((Vec2::rand(), )); + world.spawn((Vec2::rand(), )); + world.add_resource(SomeCounter(0)); + + let test_system = |mut counter: RefMut, view: View>| -> anyhow::Result<()> { + for v2 in view.into_iter() { + println!("Got v2 at '{:?}'", v2); + counter.0 += 1; + } + + Ok(()) + }; + + test_system.into_system().execute(NonNull::from(&world)).unwrap(); + + let counter = world.get_resource::(); + assert_eq!(counter.0, 2); + } } \ No newline at end of file