diff --git a/lyra-ecs/src/lib.rs b/lyra-ecs/src/lib.rs index f1c21fc..008adcb 100644 --- a/lyra-ecs/src/lib.rs +++ b/lyra-ecs/src/lib.rs @@ -29,6 +29,7 @@ mod tests; #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Access { + None, Read, Write, } \ No newline at end of file diff --git a/lyra-ecs/src/system/mod.rs b/lyra-ecs/src/system/mod.rs index c636a53..9b6d035 100644 --- a/lyra-ecs/src/system/mod.rs +++ b/lyra-ecs/src/system/mod.rs @@ -17,29 +17,33 @@ pub trait IntoSystem { fn into_system(self) -> Self::System; } -trait FnArg { - type Arg<'a>; +pub trait FnArgFetcher { + type Arg<'a>: FnArg; fn new() -> Self; - unsafe fn get<'a>(&mut self, world: &'a World) -> Self::Arg<'a>; + /// Return the appropriate world access if this fetcher gets the world directly. + /// Return [`Access::None`] if you're only fetching components, or resources. + fn world_access(&self) -> Access { + Access::None + } + + /// Get the arg from the world + unsafe fn get<'a>(&mut self, world: NonNull) -> Self::Arg<'a>; +} + +pub trait FnArg { + type Fetcher: FnArgFetcher; } pub struct FnSystem { - inner: F,//for<'a> fn(Args) -> anyhow::Result<()> - //args: Args, - _p: PhantomData, + inner: F, + args: Args, } -/* impl<'a, F, Q> System for FnSystem -where - Q: FnArg, - F: Fn(Q::Arg<'a>,) -> anyhow::Result<()>, */ - - impl System for FnSystem where - A: FnArg, + A: FnArgFetcher, F: for<'a> FnMut(A::Arg<'a>) -> anyhow::Result<()>, { fn world_access(&self) -> Access { @@ -47,8 +51,6 @@ where } fn execute(&mut self, world: NonNull) -> anyhow::Result<()> { - let world = unsafe { world.as_ref() }; - let mut a = A::new(); let a = unsafe { a.get(world) }; @@ -59,65 +61,42 @@ where } } -/* impl IntoSystem for F +impl IntoSystem for F where A: FnArg, - F: for<'a> Fn(A::Arg<'a>) -> anyhow::Result<()>, + F: FnMut(A) -> anyhow::Result<()>, + F: for<'a> FnMut(::Arg<'a>) -> anyhow::Result<()>, { - type System = FnSystem; + type System = FnSystem; fn into_system(self) -> Self::System { FnSystem { - _p: PhantomData, - inner: self - } - } -} */ - -/* impl IntoSystem for F -where - Q: Query, - F: for<'a> Fn( as FnArg>::Arg<'a>) -> anyhow::Result<()>, -{ - type System = FnSystem>; - - fn into_system(self) -> Self::System { - FnSystem { - _p: PhantomData, - inner: self - } - } -} */ - -impl IntoSystem for F -where - Q: Query, - F: for<'a> FnMut( as FnArg>::Arg<'a>) -> anyhow::Result<()>, -{ - type System = FnSystem>; - - fn into_system(self) -> Self::System { - FnSystem { - _p: PhantomData, + args: A::Fetcher::new(), inner: self } } } -pub struct FnArgStorage { - query: Q, +/// An ArgFetcher implementation for query [`View`]s +pub struct ViewArgFetcher { + query: Q } -impl FnArg for FnArgStorage { - type Arg<'b> = View<'b, Q>; +impl<'a, Q: Query> FnArg for View<'a, Q> { + type Fetcher = ViewArgFetcher; +} + +impl FnArgFetcher for ViewArgFetcher { + type Arg<'a> = View<'a, Q>; fn new() -> Self { - FnArgStorage { + ViewArgFetcher { query: Q::new(), } } - unsafe fn get<'b>(&mut self, world: &'b World) -> Self::Arg<'b> { + unsafe fn get<'a>(&mut self, world: NonNull) -> Self::Arg<'a> { + let world = &*world.as_ptr(); let arch = world.archetypes.values().collect(); let v = View::new(world, self.query, arch); @@ -125,25 +104,80 @@ impl FnArg for FnArgStorage { } } +/// An ArgFetcher implementation for borrowing the [`World`]. +pub struct WorldArgFetcher; + +impl<'a> FnArg for &'a World { + type Fetcher = WorldArgFetcher; +} + +impl FnArgFetcher for WorldArgFetcher { + type Arg<'a> = &'a World; + + fn new() -> Self { + WorldArgFetcher + } + + fn world_access(&self) -> Access { + Access::Read + } + + unsafe fn get<'a>(&mut self, world: NonNull) -> Self::Arg<'a> { + &*world.as_ptr() + } + +} + +/// An ArgFetcher implementation for mutably borrowing the [`World`]. +pub struct WorldMutArgFetcher; + +impl<'a> FnArg for &'a mut World { + type Fetcher = WorldMutArgFetcher; +} + +impl FnArgFetcher for WorldMutArgFetcher { + type Arg<'a> = &'a mut World; + + fn new() -> Self { + WorldMutArgFetcher + } + + fn world_access(&self) -> Access { + Access::Write + } + + unsafe fn get<'a>(&mut self, world: NonNull) -> Self::Arg<'a> { + &mut *world.as_ptr() + } +} + #[cfg(test)] mod tests { - use std::{ptr::NonNull, sync::atomic::{AtomicU8, Ordering}, rc::Rc, ops::Add}; + use std::ptr::NonNull; use crate::{tests::{Vec2, Vec3}, View, QueryBorrow, world::World}; use super::{System, IntoSystem}; + struct SomeCounter(u32); + #[test] fn simple_system() { let mut world = World::new(); - world.spawn((Vec2::rand(),)); - world.spawn((Vec2::rand(),)); - world.spawn((Vec2::rand(),)); - world.spawn((Vec2::rand(),)); + let vecs = &[Vec2::rand(), Vec2::rand(), Vec2::rand(), Vec2::rand()]; + world.spawn((vecs[0],)); + world.spawn((vecs[1],)); + world.spawn((vecs[2],)); + world.spawn((vecs[3],)); let mut count = 0; let test_system = |view: View>| -> anyhow::Result<()> { + let mut vecs = vecs.to_vec(); for v in view.into_iter() { + let pos = vecs.iter().position(|vec| *vec == *v) + .expect("Failure to find vec inside list"); + vecs.remove(pos); + println!("Got v at: {:?}", v); count += 1; } @@ -179,4 +213,24 @@ mod tests { assert_eq!(count, 2); } + + #[test] + fn world_system() { + let mut world = World::new(); + world.spawn((Vec2::rand(), Vec3::rand())); + world.spawn((Vec2::rand(), Vec3::rand())); + world.add_resource(SomeCounter(0)); + + let test_system = |world: &World| -> anyhow::Result<()> { + let mut counter = world.get_resource_mut::(); + counter.0 += 10; + + Ok(()) + }; + + test_system.into_system().execute(NonNull::from(&world)).unwrap(); + + let counter = world.get_resource::(); + assert_eq!(counter.0, 10); + } } \ No newline at end of file