Rewrite FnSystem stuff, add World argument fetcher

This commit is contained in:
SeanOMik 2023-12-08 17:12:33 -05:00
parent 27b0b87bd7
commit 5f5f875783
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
2 changed files with 115 additions and 60 deletions

View File

@ -29,6 +29,7 @@ mod tests;
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Access { pub enum Access {
None,
Read, Read,
Write, Write,
} }

View File

@ -17,29 +17,33 @@ pub trait IntoSystem<T> {
fn into_system(self) -> Self::System; fn into_system(self) -> Self::System;
} }
trait FnArg { pub trait FnArgFetcher {
type Arg<'a>; type Arg<'a>: FnArg<Fetcher = Self>;
fn new() -> Self; 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<World>) -> Self::Arg<'a>;
}
pub trait FnArg {
type Fetcher: FnArgFetcher;
} }
pub struct FnSystem<F, Args> { pub struct FnSystem<F, Args> {
inner: F,//for<'a> fn(Args) -> anyhow::Result<()> inner: F,
//args: Args, args: Args,
_p: PhantomData<Args>,
} }
/* impl<'a, F, Q> System for FnSystem<F, Q>
where
Q: FnArg,
F: Fn(Q::Arg<'a>,) -> anyhow::Result<()>, */
impl<F, A> System for FnSystem<F, A> impl<F, A> System for FnSystem<F, A>
where where
A: FnArg, A: FnArgFetcher,
F: for<'a> FnMut(A::Arg<'a>) -> anyhow::Result<()>, F: for<'a> FnMut(A::Arg<'a>) -> anyhow::Result<()>,
{ {
fn world_access(&self) -> Access { fn world_access(&self) -> Access {
@ -47,8 +51,6 @@ where
} }
fn execute(&mut self, world: NonNull<World>) -> anyhow::Result<()> { fn execute(&mut self, world: NonNull<World>) -> anyhow::Result<()> {
let world = unsafe { world.as_ref() };
let mut a = A::new(); let mut a = A::new();
let a = unsafe { a.get(world) }; let a = unsafe { a.get(world) };
@ -59,65 +61,42 @@ where
} }
} }
/* impl<F, A> IntoSystem<A> for F impl<F, A> IntoSystem<A> for F
where where
A: FnArg, A: FnArg,
F: for<'a> Fn(A::Arg<'a>) -> anyhow::Result<()>, F: FnMut(A) -> anyhow::Result<()>,
F: for<'a> FnMut(<A::Fetcher as FnArgFetcher>::Arg<'a>) -> anyhow::Result<()>,
{ {
type System = FnSystem<F, A>; type System = FnSystem<F, A::Fetcher>;
fn into_system(self) -> Self::System { fn into_system(self) -> Self::System {
FnSystem { FnSystem {
_p: PhantomData, args: A::Fetcher::new(),
inner: self
}
}
} */
/* impl<F, Q> IntoSystem<Q> for F
where
Q: Query,
F: for<'a> Fn(<FnArgStorage<Q> as FnArg>::Arg<'a>) -> anyhow::Result<()>,
{
type System = FnSystem<F, FnArgStorage<Q>>;
fn into_system(self) -> Self::System {
FnSystem {
_p: PhantomData,
inner: self
}
}
} */
impl<F, Q> IntoSystem<Q> for F
where
Q: Query,
F: for<'a> FnMut(<FnArgStorage<Q> as FnArg>::Arg<'a>) -> anyhow::Result<()>,
{
type System = FnSystem<F, FnArgStorage<Q>>;
fn into_system(self) -> Self::System {
FnSystem {
_p: PhantomData,
inner: self inner: self
} }
} }
} }
pub struct FnArgStorage<Q: Query> { /// An ArgFetcher implementation for query [`View`]s
query: Q, pub struct ViewArgFetcher<Q> {
query: Q
} }
impl<Q: Query> FnArg for FnArgStorage<Q> { impl<'a, Q: Query> FnArg for View<'a, Q> {
type Arg<'b> = View<'b, Q>; type Fetcher = ViewArgFetcher<Q>;
}
impl<Q: Query> FnArgFetcher for ViewArgFetcher<Q> {
type Arg<'a> = View<'a, Q>;
fn new() -> Self { fn new() -> Self {
FnArgStorage { ViewArgFetcher {
query: Q::new(), query: Q::new(),
} }
} }
unsafe fn get<'b>(&mut self, world: &'b World) -> Self::Arg<'b> { unsafe fn get<'a>(&mut self, world: NonNull<World>) -> Self::Arg<'a> {
let world = &*world.as_ptr();
let arch = world.archetypes.values().collect(); let arch = world.archetypes.values().collect();
let v = View::new(world, self.query, arch); let v = View::new(world, self.query, arch);
@ -125,25 +104,80 @@ impl<Q: Query> FnArg for FnArgStorage<Q> {
} }
} }
/// 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<World>) -> 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<World>) -> Self::Arg<'a> {
&mut *world.as_ptr()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { 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 crate::{tests::{Vec2, Vec3}, View, QueryBorrow, world::World};
use super::{System, IntoSystem}; use super::{System, IntoSystem};
struct SomeCounter(u32);
#[test] #[test]
fn simple_system() { fn simple_system() {
let mut world = World::new(); let mut world = World::new();
world.spawn((Vec2::rand(),)); let vecs = &[Vec2::rand(), Vec2::rand(), Vec2::rand(), Vec2::rand()];
world.spawn((Vec2::rand(),)); world.spawn((vecs[0],));
world.spawn((Vec2::rand(),)); world.spawn((vecs[1],));
world.spawn((Vec2::rand(),)); world.spawn((vecs[2],));
world.spawn((vecs[3],));
let mut count = 0; let mut count = 0;
let test_system = |view: View<QueryBorrow<Vec2>>| -> anyhow::Result<()> { let test_system = |view: View<QueryBorrow<Vec2>>| -> anyhow::Result<()> {
let mut vecs = vecs.to_vec();
for v in view.into_iter() { 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); println!("Got v at: {:?}", v);
count += 1; count += 1;
} }
@ -179,4 +213,24 @@ mod tests {
assert_eq!(count, 2); 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::<SomeCounter>();
counter.0 += 10;
Ok(())
};
test_system.into_system().execute(NonNull::from(&world)).unwrap();
let counter = world.get_resource::<SomeCounter>();
assert_eq!(counter.0, 10);
}
} }