ecs: Add world query, make it possible to request resources from function systems
This commit is contained in:
parent
74f43e9ffe
commit
0f062217ca
|
@ -1,6 +1,6 @@
|
|||
use std::{marker::PhantomData, ptr::NonNull, cell::{Ref, RefMut}};
|
||||
|
||||
use crate::{world::World, ComponentColumn, DynTypeId, Tick};
|
||||
use crate::{world::World, ComponentColumn, DynTypeId, Tick, Component};
|
||||
|
||||
use super::{Fetch, Query, AsQuery};
|
||||
|
||||
|
@ -97,11 +97,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> AsQuery for QueryBorrow<T> {
|
||||
impl<T: Component> AsQuery for QueryBorrow<T> {
|
||||
type Query = Self;
|
||||
}
|
||||
|
||||
impl<T: 'static> AsQuery for &T {
|
||||
impl<T: Component> AsQuery for &T {
|
||||
type Query = QueryBorrow<T>;
|
||||
}
|
||||
|
||||
|
@ -209,11 +209,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> AsQuery for QueryBorrowMut<T> {
|
||||
impl<T: Component> AsQuery for QueryBorrowMut<T> {
|
||||
type Query = Self;
|
||||
}
|
||||
|
||||
impl<T: 'static> AsQuery for &mut T {
|
||||
impl<T: Component> AsQuery for &mut T {
|
||||
type Query = QueryBorrowMut<T>;
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ mod tests {
|
|||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||
let v = View::new(&world, borrow, archetypes);
|
||||
let v = View::<QueryBorrow<Vec2>>::new(&world, borrow, archetypes);
|
||||
|
||||
for e in v.into_iter() {
|
||||
println!("Found entity at {:?}", e);
|
||||
|
@ -260,7 +260,7 @@ mod tests {
|
|||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||
let v = View::new(&world, borrow, archetypes);
|
||||
let v = View::<QueryBorrowMut<Vec2>>::new(&world, borrow, archetypes);
|
||||
|
||||
let mut orig = vec![];
|
||||
|
||||
|
@ -277,7 +277,7 @@ mod tests {
|
|||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||
let v = View::new(&world, borrow, archetypes);
|
||||
let v = View::<QueryBorrow<Vec2>>::new(&world, borrow, archetypes);
|
||||
|
||||
for (new, orig) in v.into_iter().zip(orig.iter()) {
|
||||
assert!(new.x - orig.x == 10.0);
|
||||
|
|
|
@ -23,6 +23,10 @@ pub mod tick;
|
|||
#[allow(unused_imports)]
|
||||
pub use tick::*;
|
||||
|
||||
pub mod world;
|
||||
#[allow(unused_imports)]
|
||||
pub use world::*;
|
||||
|
||||
pub mod dynamic;
|
||||
|
||||
/// A [`Fetch`]er implementation gets data out of an archetype.
|
||||
|
@ -100,7 +104,7 @@ mod tests {
|
|||
|
||||
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||
|
||||
let v = View::new(&world, entities, archetypes);
|
||||
let v = View::<Entities>::new(&world, entities, archetypes);
|
||||
|
||||
for e in v.into_iter() {
|
||||
println!("Got entity! {:?}", e);
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct FetchResource<'a, T> {
|
|||
}
|
||||
|
||||
impl<'a, T: 'a + 'static> Fetch<'a> for FetchResource<'a, T> {
|
||||
type Item = Ref<'a, T>;
|
||||
type Item = Res<'a, T>;
|
||||
|
||||
fn dangling() -> Self {
|
||||
Self {
|
||||
|
@ -25,7 +25,7 @@ impl<'a, T: 'a + 'static> Fetch<'a> for FetchResource<'a, T> {
|
|||
|
||||
unsafe fn get_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||
let w = self.world.unwrap();
|
||||
w.get_resource::<T>()
|
||||
Res(w.get_resource::<T>())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ impl<'a, T: 'a + 'static> Fetch<'a> for FetchResource<'a, T> {
|
|||
pub struct QueryResource<T: ResourceObject> {
|
||||
_phantom: PhantomData<T>
|
||||
}
|
||||
pub type Resource<T> = QueryResource<T>;
|
||||
//pub type Resource<T> = QueryResource<T>;
|
||||
|
||||
impl<T: ResourceObject> Copy for QueryResource<T> {}
|
||||
|
||||
|
@ -45,7 +45,7 @@ impl<T: ResourceObject> Clone for QueryResource<T> {
|
|||
}
|
||||
|
||||
impl<T: ResourceObject + 'static> Query for QueryResource<T> {
|
||||
type Item<'a> = Ref<'a, T>;
|
||||
type Item<'a> = Res<'a, T>;
|
||||
|
||||
type Fetch<'a> = FetchResource<'a, T>;
|
||||
|
||||
|
@ -78,13 +78,28 @@ impl<R: ResourceObject> AsQuery for QueryResource<R> {
|
|||
type Query = QueryResource<R>;
|
||||
}
|
||||
|
||||
/// A struct used for querying resources from the World.
|
||||
pub struct Res<'a, T>(Ref<'a, T>);
|
||||
|
||||
impl<'a, T: ResourceObject> std::ops::Deref for Res<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ResourceObject> AsQuery for Res<'a, T> {
|
||||
type Query = QueryResource<T>;
|
||||
}
|
||||
|
||||
pub struct FetchResourceMut<'a, T> {
|
||||
world: Option<&'a World>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + 'static> Fetch<'a> for FetchResourceMut<'a, T> {
|
||||
type Item = RefMut<'a, T>;
|
||||
type Item = ResMut<'a, T>;
|
||||
|
||||
fn dangling() -> Self {
|
||||
Self {
|
||||
|
@ -99,7 +114,7 @@ impl<'a, T: 'a + 'static> Fetch<'a> for FetchResourceMut<'a, T> {
|
|||
|
||||
unsafe fn get_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||
let w = self.world.unwrap();
|
||||
w.get_resource_mut::<T>()
|
||||
ResMut(w.get_resource_mut::<T>())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -109,8 +124,6 @@ pub struct QueryResourceMut<T: ResourceObject> {
|
|||
_phantom: PhantomData<T>
|
||||
}
|
||||
|
||||
pub type ResourceMut<T> = QueryResourceMut<T>;
|
||||
|
||||
impl<T: ResourceObject> Copy for QueryResourceMut<T> {}
|
||||
|
||||
impl<T: ResourceObject> Clone for QueryResourceMut<T> {
|
||||
|
@ -120,7 +133,7 @@ impl<T: ResourceObject> Clone for QueryResourceMut<T> {
|
|||
}
|
||||
|
||||
impl<T: ResourceObject + 'static> Query for QueryResourceMut<T> {
|
||||
type Item<'a> = RefMut<'a, T>;
|
||||
type Item<'a> = ResMut<'a, T>;
|
||||
|
||||
type Fetch<'a> = FetchResourceMut<'a, T>;
|
||||
|
||||
|
@ -152,8 +165,33 @@ impl<T: ResourceObject + 'static> Query for QueryResourceMut<T> {
|
|||
impl<R: ResourceObject> AsQuery for QueryResourceMut<R> {
|
||||
type Query = QueryResourceMut<R>;
|
||||
}
|
||||
|
||||
/// A struct used for querying resources from the World.
|
||||
pub struct ResMut<'a, T>(RefMut<'a, T>);
|
||||
|
||||
impl<'a, T: ResourceObject> std::ops::Deref for ResMut<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ResourceObject> std::ops::DerefMut for ResMut<'a, T> {
|
||||
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.0.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ResourceObject> AsQuery for ResMut<'a, T> {
|
||||
type Query = QueryResourceMut<T>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::{world::World, tests::{Vec2, Vec3}, query::QueryResourceMut};
|
||||
|
||||
use super::QueryResource;
|
||||
|
@ -171,6 +209,7 @@ mod tests {
|
|||
|
||||
let mut res_iter = world.view_iter::<QueryResource<SomeCounter>>();
|
||||
let res = res_iter.next().unwrap();
|
||||
let res = res.deref();
|
||||
assert_eq!(res.0, 0);
|
||||
}
|
||||
|
||||
|
@ -195,7 +234,7 @@ mod tests {
|
|||
assert_eq!(i.count(), 3);
|
||||
|
||||
for (res, e) in world.view_iter::<(QueryResource<SomeCounter>, &Vec2)>() {
|
||||
println!("Got res {}! and entity at {:?}", res.0, e);
|
||||
println!("Got res {}! and entity at {:?}", res.deref().0, e);
|
||||
}
|
||||
|
||||
let i = world.view_iter::<QueryResource<SomeCounter>>();
|
||||
|
@ -214,12 +253,14 @@ mod tests {
|
|||
{
|
||||
let mut resmut_iter = world.view_iter::<QueryResourceMut<SomeCounter>>();
|
||||
let mut resmut = resmut_iter.next().unwrap();
|
||||
let resmut = resmut.deref_mut();
|
||||
assert_eq!(resmut.0, 0);
|
||||
resmut.0 += 20;
|
||||
}
|
||||
|
||||
let mut res_iter = world.view_iter::<QueryResource<SomeCounter>>();
|
||||
let res = res_iter.next().unwrap();
|
||||
let res = res.deref();
|
||||
assert_eq!(res.0, 20);
|
||||
}
|
||||
}
|
|
@ -2,19 +2,19 @@ use std::ops::Range;
|
|||
|
||||
use crate::{archetype::Archetype, world::{ArchetypeEntityId, World}, EntityId, Tick};
|
||||
|
||||
use super::{Query, Fetch};
|
||||
use super::{Query, Fetch, AsQuery};
|
||||
|
||||
pub struct View<'a, Q: Query> {
|
||||
pub struct View<'a, Q: AsQuery> {
|
||||
world: &'a World,
|
||||
query: Q,
|
||||
query: Q::Query,
|
||||
archetypes: Vec<&'a Archetype>,
|
||||
}
|
||||
|
||||
impl<'a, Q> View<'a, Q>
|
||||
where
|
||||
Q: Query,
|
||||
Q: AsQuery,
|
||||
{
|
||||
pub fn new(world: &'a World, query: Q, archetypes: Vec<&'a Archetype>) -> Self {
|
||||
pub fn new(world: &'a World, query: Q::Query, archetypes: Vec<&'a Archetype>) -> Self {
|
||||
Self {
|
||||
world,
|
||||
query,
|
||||
|
@ -25,14 +25,14 @@ where
|
|||
|
||||
impl<'a, Q> IntoIterator for View<'a, Q>
|
||||
where
|
||||
Q: Query,
|
||||
Q: AsQuery,
|
||||
{
|
||||
type Item = Q::Item<'a>;
|
||||
type Item = <Q::Query as Query>::Item<'a>;
|
||||
|
||||
type IntoIter = ViewIter<'a, Q>;
|
||||
type IntoIter = ViewIter<'a, Q::Query>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let tick = self.world.tick_tracker().tick_when(Q::MUTATES);
|
||||
let tick = self.world.tick_tracker().tick_when(Q::Query::MUTATES);
|
||||
|
||||
ViewIter {
|
||||
world: self.world,
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
use std::ptr::NonNull;
|
||||
|
||||
use crate::World;
|
||||
|
||||
use super::{Fetch, Query, AsQuery};
|
||||
|
||||
pub struct FetchWorldRef<'a> {
|
||||
world: &'a World
|
||||
}
|
||||
|
||||
impl<'a> Fetch<'a> for FetchWorldRef<'a> {
|
||||
type Item = &'a World;
|
||||
|
||||
fn dangling() -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn can_visit_item(&mut self, _entity: crate::ArchetypeEntityId) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
unsafe fn get_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||
self.world
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct QueryWorldRef;
|
||||
|
||||
impl Default for QueryWorldRef {
|
||||
fn default() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Query for QueryWorldRef {
|
||||
type Item<'a> = &'a World;
|
||||
|
||||
type Fetch<'a> = FetchWorldRef<'a>;
|
||||
|
||||
const ALWAYS_FETCHES: bool = true;
|
||||
|
||||
fn new() -> Self {
|
||||
QueryWorldRef
|
||||
}
|
||||
|
||||
fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
unsafe fn fetch<'a>(&self, world: &'a World, _archetype: &'a crate::archetype::Archetype, _tick: crate::Tick) -> Self::Fetch<'a> {
|
||||
FetchWorldRef {
|
||||
world
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option<Self::Fetch<'a>> {
|
||||
Some(FetchWorldRef {
|
||||
world,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsQuery for QueryWorldRef {
|
||||
type Query = Self;
|
||||
}
|
||||
|
||||
impl AsQuery for &World {
|
||||
type Query = QueryWorldRef;
|
||||
}
|
||||
|
||||
pub struct FetchWorldRefMut<'a> {
|
||||
world: &'a mut World
|
||||
}
|
||||
|
||||
impl<'a> Fetch<'a> for FetchWorldRefMut<'a> {
|
||||
type Item = &'a mut World;
|
||||
|
||||
fn dangling() -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn can_visit_item(&mut self, _entity: crate::ArchetypeEntityId) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
unsafe fn get_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||
// safety: world outlives the fetcher
|
||||
let mut world_ptr = NonNull::from(&self.world);
|
||||
unsafe { world_ptr.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct QueryWorldRefMut;
|
||||
|
||||
impl Default for QueryWorldRefMut {
|
||||
fn default() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Query for QueryWorldRefMut {
|
||||
type Item<'a> = &'a mut World;
|
||||
|
||||
type Fetch<'a> = FetchWorldRefMut<'a>;
|
||||
|
||||
const ALWAYS_FETCHES: bool = true;
|
||||
|
||||
fn new() -> Self {
|
||||
QueryWorldRefMut
|
||||
}
|
||||
|
||||
fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
unsafe fn fetch<'a>(&self, world: &'a World, _archetype: &'a crate::archetype::Archetype, _tick: crate::Tick) -> Self::Fetch<'a> {
|
||||
self.fetch_world(world).unwrap()
|
||||
}
|
||||
|
||||
unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option<Self::Fetch<'a>> {
|
||||
// safety: the queries are expected to be executed by an executor that would
|
||||
// not cause multiple mutable borrows
|
||||
let mut world_ptr = NonNull::from(world);
|
||||
let world = unsafe { world_ptr.as_mut() };
|
||||
|
||||
Some(FetchWorldRefMut {
|
||||
world,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsQuery for QueryWorldRefMut {
|
||||
type Query = Self;
|
||||
}
|
||||
|
||||
impl AsQuery for &mut World {
|
||||
type Query = QueryWorldRefMut;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
use std::{any::{TypeId, Any}, cell::{RefCell, Ref, RefMut}};
|
||||
|
||||
/// Shorthand for `Send + Sync + 'static`, so it never needs to be implemented manually.
|
||||
pub trait ResourceObject: Send + Sync + 'static {}
|
||||
impl<T: Send + Sync + 'static> ResourceObject for T {}
|
||||
pub trait ResourceObject: 'static {}
|
||||
impl<T: 'static> ResourceObject for T {}
|
||||
|
||||
/// A type erased storage for a Resource.
|
||||
pub struct ResourceData {
|
||||
|
|
|
@ -108,7 +108,7 @@ impl GraphExecutor {
|
|||
mod tests {
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use crate::{world::World, query::{ResourceMut, View}, system::IntoSystem};
|
||||
use crate::{world::World, query::{ResMut, View}, system::IntoSystem};
|
||||
|
||||
use super::GraphExecutor;
|
||||
|
||||
|
@ -120,7 +120,7 @@ mod tests {
|
|||
|
||||
let mut exec = GraphExecutor::new();
|
||||
|
||||
let a_system = |view: View<ResourceMut<Vec<String>>>| -> anyhow::Result<()> {
|
||||
let a_system = |view: View<ResMut<Vec<String>>>| -> anyhow::Result<()> {
|
||||
println!("System 'a' ran!");
|
||||
|
||||
let mut order = view.into_iter().next().unwrap();
|
||||
|
@ -129,7 +129,7 @@ mod tests {
|
|||
Ok(())
|
||||
};
|
||||
|
||||
let b_system = |view: View<ResourceMut<Vec<String>>>| -> anyhow::Result<()> {
|
||||
let b_system = |view: View<ResMut<Vec<String>>>| -> anyhow::Result<()> {
|
||||
println!("System 'b' ran!");
|
||||
|
||||
let mut order = view.into_iter().next().unwrap();
|
||||
|
@ -138,7 +138,7 @@ mod tests {
|
|||
Ok(())
|
||||
};
|
||||
|
||||
let c_system = |view: View<ResourceMut<Vec<String>>>| -> anyhow::Result<()> {
|
||||
let c_system = |view: View<ResMut<Vec<String>>>| -> anyhow::Result<()> {
|
||||
println!("System 'c' ran!");
|
||||
|
||||
let mut order = view.into_iter().next().unwrap();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{ptr::NonNull, marker::PhantomData, cell::{Ref, RefMut}};
|
||||
|
||||
use crate::{world::World, Access, ResourceObject, query::{Query, View}};
|
||||
use crate::{world::World, Access, ResourceObject, query::{Query, View, AsQuery}};
|
||||
|
||||
pub mod graph;
|
||||
pub use graph::*;
|
||||
|
@ -131,20 +131,20 @@ 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<Q> {
|
||||
query: Q
|
||||
pub struct ViewArgFetcher<Q: AsQuery> {
|
||||
query: Q::Query
|
||||
}
|
||||
|
||||
impl<'a, Q: Query> FnArg for View<'a, Q> {
|
||||
impl<'a, Q: AsQuery> FnArg for View<'a, Q> {
|
||||
type Fetcher = ViewArgFetcher<Q>;
|
||||
}
|
||||
|
||||
impl<Q: Query> FnArgFetcher for ViewArgFetcher<Q> {
|
||||
impl<Q: AsQuery> FnArgFetcher for ViewArgFetcher<Q> {
|
||||
type Arg<'a> = View<'a, Q>;
|
||||
|
||||
fn new() -> Self {
|
||||
ViewArgFetcher {
|
||||
query: Q::new(),
|
||||
query: <Q::Query as Query>::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -213,7 +213,7 @@ impl World {
|
|||
/// View into the world for a set of entities that satisfy the queries.
|
||||
pub fn view_iter<T: 'static + AsQuery>(&self) -> ViewIter<T::Query> {
|
||||
let archetypes = self.archetypes.values().collect();
|
||||
let v = View::new(self, T::Query::new(), archetypes);
|
||||
let v = View::<T>::new(self, T::Query::new(), archetypes);
|
||||
v.into_iter()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue