mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Resource and ResourceMut pointers
This commit is contained in:
parent
45a710fe6a
commit
2d3903299b
6 changed files with 410 additions and 153 deletions
|
@ -1,10 +1,8 @@
|
|||
use legion::{
|
||||
filter::EntityFilter,
|
||||
prelude::{
|
||||
into_resource_for_each_system, into_resource_system, IntoQuery, ResourceSet, Resources,
|
||||
Resources,
|
||||
Runnable, Schedulable, World,
|
||||
},
|
||||
query::{DefaultFilter, View},
|
||||
};
|
||||
pub enum System {
|
||||
Schedulable(Box<dyn Schedulable>),
|
||||
|
@ -31,25 +29,4 @@ where
|
|||
fn from(system: T) -> Self {
|
||||
System::ThreadLocalFn(Box::new(system))
|
||||
}
|
||||
}
|
||||
|
||||
impl System {
|
||||
pub fn resource_for_each<'a, Q, F, R, X>(name: &'static str, system: F) -> Self
|
||||
where
|
||||
Q: IntoQuery + DefaultFilter<Filter = R>,
|
||||
<Q as View<'a>>::Iter: Iterator<Item = Q> + 'a,
|
||||
F: FnMut(&mut X, Q) + Send + Sync + 'static,
|
||||
R: EntityFilter + Sync + 'static,
|
||||
X: ResourceSet<PreparedResources = X> + 'static,
|
||||
{
|
||||
into_resource_for_each_system(name, system).into()
|
||||
}
|
||||
|
||||
pub fn resource<'a, F, X>(name: &'static str, system: F) -> Self
|
||||
where
|
||||
F: FnMut(&mut X) + Send + Sync + 'static,
|
||||
X: ResourceSet<PreparedResources = X> + 'static,
|
||||
{
|
||||
into_resource_system(name, system).into()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ mod system_fn_types;
|
|||
pub use bit_set;
|
||||
pub use system::*;
|
||||
pub use system_fn::*;
|
||||
pub use system_fn_types::{ResourceMut, Resource};
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::{
|
||||
|
@ -17,11 +18,12 @@ pub mod prelude {
|
|||
into_resource_system,
|
||||
// aliased preparedread and preparedwrite used by system_fn
|
||||
resource::{
|
||||
PreparedRead as Resource, PreparedWrite as ResourceMut, ResourceSet, Resources,
|
||||
ResourceSet, Resources,
|
||||
},
|
||||
schedule::{Executor, Runnable, Schedulable, Schedule},
|
||||
IntoSystem,
|
||||
System,
|
||||
SystemBuilder,
|
||||
Resource, ResourceMut,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -630,7 +630,7 @@ pub struct SubWorld {
|
|||
}
|
||||
|
||||
impl SubWorld {
|
||||
unsafe fn new(
|
||||
pub(super) unsafe fn new(
|
||||
world: &World,
|
||||
access: &Access<ComponentTypeId>,
|
||||
archetypes: &ArchetypeAccess,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
resource::{PreparedRead, Resource, ResourceSet, ResourceTypeId},
|
||||
resource::{ResourceSet, ResourceTypeId},
|
||||
schedule::{ArchetypeAccess, Schedulable},
|
||||
Access, System, SystemAccess, SystemFnWrapper, SystemQuery,
|
||||
Access, SystemAccess, SystemQuery, system_fn_types::{FuncSystem, FuncSystemFnWrapper},
|
||||
};
|
||||
use bit_set::BitSet;
|
||||
use fxhash::FxHashMap;
|
||||
|
@ -20,9 +20,9 @@ pub fn into_resource_for_each_system<'a, Q, F, R, X>(
|
|||
where
|
||||
Q: IntoQuery + DefaultFilter<Filter = R>,
|
||||
<Q as View<'a>>::Iter: Iterator<Item = Q> + 'a,
|
||||
F: FnMut(&mut X, Q) + Send + Sync + 'static,
|
||||
F: FnMut(X, Q) + Send + Sync + 'static,
|
||||
R: EntityFilter + Sync + 'static,
|
||||
X: ResourceSet<PreparedResources = X> + 'static,
|
||||
X: ResourceSet<PreparedResources = X> + 'static + Clone,
|
||||
{
|
||||
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
||||
resource_access.reads.extend(X::read_types().iter());
|
||||
|
@ -32,19 +32,19 @@ where
|
|||
component_access.reads.extend(Q::read_types().iter());
|
||||
component_access.writes.extend(Q::write_types().iter());
|
||||
|
||||
let run_fn = SystemFnWrapper(
|
||||
let run_fn = FuncSystemFnWrapper(
|
||||
move |_,
|
||||
world,
|
||||
resources: &mut X,
|
||||
resources: X,
|
||||
query: &mut SystemQuery<Q, <Q as DefaultFilter>::Filter>| {
|
||||
for components in query.iter_mut(world) {
|
||||
system(resources, components);
|
||||
system(resources.clone(), components);
|
||||
}
|
||||
},
|
||||
PhantomData,
|
||||
);
|
||||
|
||||
Box::new(System {
|
||||
Box::new(FuncSystem {
|
||||
name: name.into(),
|
||||
queries: AtomicRefCell::new(Q::query()),
|
||||
access: SystemAccess {
|
||||
|
@ -61,7 +61,7 @@ where
|
|||
|
||||
pub fn into_resource_system<'a, F, X>(name: &'static str, mut system: F) -> Box<dyn Schedulable>
|
||||
where
|
||||
F: FnMut(&mut X) + Send + Sync + 'static,
|
||||
F: FnMut(X) + Send + Sync + 'static,
|
||||
X: ResourceSet<PreparedResources = X> + 'static,
|
||||
{
|
||||
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
||||
|
@ -69,14 +69,14 @@ where
|
|||
resource_access.writes.extend(X::write_types().iter());
|
||||
|
||||
let component_access: Access<ComponentTypeId> = Access::default();
|
||||
let run_fn = SystemFnWrapper(
|
||||
move |_, _, resources: &mut X, _| {
|
||||
let run_fn = FuncSystemFnWrapper(
|
||||
move |_, _, resources: X, _| {
|
||||
system(resources);
|
||||
},
|
||||
PhantomData,
|
||||
);
|
||||
|
||||
Box::new(System {
|
||||
Box::new(FuncSystem {
|
||||
name: name.into(),
|
||||
queries: AtomicRefCell::new(()),
|
||||
access: SystemAccess {
|
||||
|
@ -98,72 +98,17 @@ where
|
|||
fn into_system(self, name: &'static str) -> Box<dyn Schedulable>;
|
||||
}
|
||||
|
||||
// impl<F, X: Resource + Send + Sync + 'static, A: Component, B: Component> IntoSystem<(X,), (A, B)> for F
|
||||
// where
|
||||
// F: for<'a> FnMut(&X, Ref<'a, A>, Ref<'a, B>) + Send + Sync + 'static,
|
||||
// {
|
||||
// fn into_system(mut self, name: &'static str) -> Box<dyn Schedulable> {
|
||||
// let mut resource_access: Access<ResourceTypeId> = Access::default();
|
||||
// resource_access
|
||||
// .reads
|
||||
// .extend(<PreparedRead<X>>::read_types().iter());
|
||||
// resource_access
|
||||
// .writes
|
||||
// .extend(<PreparedRead<X>>::write_types().iter());
|
||||
// let mut component_access: Access<ComponentTypeId> = Access::default();
|
||||
// component_access
|
||||
// .reads
|
||||
// .extend(<(Ref<A>, Ref<B>) as View>::read_types().iter());
|
||||
// component_access
|
||||
// .writes
|
||||
// .extend(<(Ref<A>, Ref<B>) as View>::write_types().iter());
|
||||
|
||||
// let run_fn = SystemFnWrapper(
|
||||
// move |_,
|
||||
// world,
|
||||
// x: &mut PreparedRead<X>,
|
||||
// query: &mut SystemQuery<
|
||||
// (Ref<A>, Ref<B>),
|
||||
// EntityFilterTuple<
|
||||
// And<(ComponentFilter<A>, ComponentFilter<B>)>,
|
||||
// And<(Passthrough, Passthrough)>,
|
||||
// And<(Passthrough, Passthrough)>,
|
||||
// >,
|
||||
// >| {
|
||||
// for (a, b) in query.iter_mut(world) {
|
||||
// self(&*x, a, b);
|
||||
// }
|
||||
// },
|
||||
// PhantomData,
|
||||
// );
|
||||
|
||||
// Box::new(System {
|
||||
// name: name.into(),
|
||||
// queries: AtomicRefCell::new(<(Ref<A>, Ref<B>)>::query()),
|
||||
// access: SystemAccess {
|
||||
// resources: resource_access,
|
||||
// components: component_access,
|
||||
// tags: Access::default(),
|
||||
// },
|
||||
// archetypes: ArchetypeAccess::Some(BitSet::default()),
|
||||
// _resources: PhantomData::<PreparedRead<X>>,
|
||||
// command_buffer: FxHashMap::default(),
|
||||
// run_fn: AtomicRefCell::new(run_fn),
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<
|
||||
'a,
|
||||
F,
|
||||
X: Resource + Send + Sync + 'static,
|
||||
X: ResourceSet<PreparedResources = X> + 'static + Clone,
|
||||
A: for<'b> View<'b> + DefaultFilter<Filter = AF> + ViewElement,
|
||||
AF: EntityFilter + Sync + 'static,
|
||||
B: for<'b> View<'b> + DefaultFilter<Filter = BF> + ViewElement,
|
||||
BF: EntityFilter + Sync + 'static,
|
||||
> IntoSystem<'a, (X,), (A, B)> for F
|
||||
where
|
||||
F: FnMut(&X, A, B) + Send + Sync + 'static,
|
||||
F: FnMut(X, A, B) + Send + Sync + 'static,
|
||||
<A as View<'a>>::Iter: Iterator<Item = A>,
|
||||
<B as View<'a>>::Iter: Iterator<Item = B>,
|
||||
{
|
||||
|
@ -171,10 +116,10 @@ where
|
|||
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
||||
resource_access
|
||||
.reads
|
||||
.extend(<PreparedRead<X>>::read_types().iter());
|
||||
.extend(<X>::read_types().iter());
|
||||
resource_access
|
||||
.writes
|
||||
.extend(<PreparedRead<X>>::write_types().iter());
|
||||
.extend(<X>::write_types().iter());
|
||||
let mut component_access: Access<ComponentTypeId> = Access::default();
|
||||
component_access
|
||||
.reads
|
||||
|
@ -183,10 +128,10 @@ where
|
|||
.writes
|
||||
.extend(<(A, B) as View>::write_types().iter());
|
||||
|
||||
let run_fn = SystemFnWrapper(
|
||||
let run_fn = FuncSystemFnWrapper(
|
||||
move |_,
|
||||
world,
|
||||
x: &mut PreparedRead<X>,
|
||||
x: X::PreparedResources,
|
||||
query: &mut SystemQuery<
|
||||
(A, B),
|
||||
EntityFilterTuple<
|
||||
|
@ -205,13 +150,13 @@ where
|
|||
>,
|
||||
>| {
|
||||
for (a, b) in query.iter_mut(world) {
|
||||
self(&*x, a, b);
|
||||
self(x.clone(), a, b);
|
||||
}
|
||||
},
|
||||
PhantomData,
|
||||
);
|
||||
|
||||
Box::new(System {
|
||||
Box::new(FuncSystem {
|
||||
name: name.into(),
|
||||
queries: AtomicRefCell::new(<(A, B)>::query()),
|
||||
access: SystemAccess {
|
||||
|
@ -220,7 +165,7 @@ where
|
|||
tags: Access::default(),
|
||||
},
|
||||
archetypes: ArchetypeAccess::Some(BitSet::default()),
|
||||
_resources: PhantomData::<PreparedRead<X>>,
|
||||
_resources: PhantomData::<X::PreparedResources>,
|
||||
command_buffer: FxHashMap::default(),
|
||||
run_fn: AtomicRefCell::new(run_fn),
|
||||
})
|
||||
|
@ -242,10 +187,10 @@ macro_rules! impl_system {
|
|||
let resource_access: Access<ResourceTypeId> = Access::default();
|
||||
let component_access: Access<ComponentTypeId> = component_access!(($($view),+));
|
||||
|
||||
let run_fn = SystemFnWrapper(
|
||||
let run_fn = FuncSystemFnWrapper(
|
||||
move |_,
|
||||
world,
|
||||
_: &mut (),
|
||||
_: (),
|
||||
query: &mut system_query!($($view, $filter),+)
|
||||
,
|
||||
| {
|
||||
|
@ -256,7 +201,7 @@ macro_rules! impl_system {
|
|||
PhantomData,
|
||||
);
|
||||
|
||||
Box::new(System {
|
||||
Box::new(FuncSystem {
|
||||
name: name.into(),
|
||||
queries: AtomicRefCell::new(query!($($view),+)),
|
||||
access: SystemAccess {
|
||||
|
@ -357,7 +302,7 @@ mod tests {
|
|||
use crate::{
|
||||
into_resource_for_each_system,
|
||||
resource::{PreparedRead, PreparedWrite, Resources},
|
||||
IntoSystem,
|
||||
IntoSystem, system_fn_types::{ResourceMut, Resource},
|
||||
};
|
||||
use legion_core::{
|
||||
borrow::{Ref, RefMut},
|
||||
|
@ -375,30 +320,53 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_into_system() {
|
||||
// fn read_system(a: &A, x: Ref<X>, y: Ref<Y>) {
|
||||
// println!("{} {} {}", a.0, x.0, y.0);
|
||||
// }
|
||||
|
||||
// fn read_system(x: Ref<X>) {
|
||||
// println!("{}", x.0);
|
||||
// }
|
||||
fn read_system(x: Ref<X>, y: Ref<Y>, mut z: RefMut<A>) {
|
||||
z.0 += 1;
|
||||
println!("{} {} {}", x.0, y.0, z.0);
|
||||
}
|
||||
|
||||
let mut world = World::new();
|
||||
let mut resources = Resources::default();
|
||||
resources.insert(A(0));
|
||||
world.insert((), vec![(X(1), Y(1)), (X(2), Y(2))]);
|
||||
|
||||
let mut system = read_system.into_system("hi");
|
||||
// fn single_read_system(x: Ref<X>) {
|
||||
// println!("{}", x.0);
|
||||
// }
|
||||
// let mut system = single_read_system.into_system("hi");
|
||||
// system.run(&mut world, &mut resources);
|
||||
|
||||
// fn read_write_system(x: Ref<X>, y: Ref<Y>, mut z: RefMut<A>) {
|
||||
// z.0 += 1;
|
||||
// println!("{} {} {}", x.0, y.0, z.0);
|
||||
// }
|
||||
|
||||
// (
|
||||
// {
|
||||
// |x: Resource<A>, y: Ref<Y>, mut z: RefMut<A>| {
|
||||
// z.0 += 1;
|
||||
// println!("{} {} {}", x.0, y.0, z.0);
|
||||
// }}).into_system("bleh");
|
||||
|
||||
// let mut system = read_write_system.into_system("read_write");
|
||||
// system.run(&mut world, &mut resources);
|
||||
|
||||
// fn resource_system(a: Resource<A>, x: Ref<X>, y: Ref<Y>) {
|
||||
// println!("{} {} {}", a.0, x.0, y.0);
|
||||
// }
|
||||
|
||||
// let mut system = resource_system.into_system("hi");
|
||||
// system.run(&mut world, &mut resources);
|
||||
|
||||
fn resource_system_mut(mut a: ResourceMut<A>, x: Ref<X>, y: Ref<Y>) {
|
||||
let hi = &mut a;
|
||||
a.0 += 1;
|
||||
println!("{} {} {}", a.0, x.0, y.0);
|
||||
}
|
||||
let mut system = resource_system_mut.into_system("hi");
|
||||
system.run(&mut world, &mut resources);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_system_fn() {
|
||||
fn read_write_system(_: &mut (), (_x, mut y): (Ref<X>, RefMut<Y>)) { y.0 += 1; }
|
||||
fn read_write_system(_: (), (_x, mut y): (Ref<X>, RefMut<Y>)) { y.0 += 1; }
|
||||
|
||||
let mut world = World::new();
|
||||
let mut resources = Resources::default();
|
||||
|
@ -410,34 +378,34 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_resource_system_fn() {
|
||||
fn my_system(
|
||||
(a, b): &mut (PreparedWrite<A>, PreparedRead<B>),
|
||||
(x, mut y): (Ref<X>, RefMut<Y>),
|
||||
) {
|
||||
assert_eq!(**b, B(1));
|
||||
// assert_eq!(**b, B(0));
|
||||
if a.0 == 0 {
|
||||
assert_eq!(*x, X(2));
|
||||
assert_eq!(*y, Y(3));
|
||||
} else if a.0 == 1 {
|
||||
assert_eq!(*x, X(4));
|
||||
assert_eq!(*y, Y(5));
|
||||
y.0 += 1;
|
||||
assert_eq!(*y, Y(6));
|
||||
} else {
|
||||
panic!("unexpected value");
|
||||
}
|
||||
// fn my_system(
|
||||
// (a,): (Resource<A>,),
|
||||
// (x, mut y): (Ref<X>, RefMut<Y>),
|
||||
// ) {
|
||||
// assert_eq!(*a, A(1));
|
||||
// // assert_eq!(**b, B(0));
|
||||
// if a.0 == 0 {
|
||||
// assert_eq!(*x, X(2));
|
||||
// assert_eq!(*y, Y(3));
|
||||
// } else if a.0 == 1 {
|
||||
// assert_eq!(*x, X(4));
|
||||
// assert_eq!(*y, Y(5));
|
||||
// y.0 += 1;
|
||||
// assert_eq!(*y, Y(6));
|
||||
// } else {
|
||||
// panic!("unexpected value");
|
||||
// }
|
||||
|
||||
a.0 += 1;
|
||||
}
|
||||
// // a.0 += 1;
|
||||
// }
|
||||
|
||||
let mut world = World::new();
|
||||
let mut resources = Resources::default();
|
||||
// let mut world = World::new();
|
||||
// let mut resources = Resources::default();
|
||||
|
||||
resources.insert(A(0));
|
||||
resources.insert(B(1));
|
||||
world.insert((), vec![(X(2), Y(3)), (X(4), Y(5))]);
|
||||
let mut my_system = into_resource_for_each_system("read_resources", my_system);
|
||||
my_system.run(&mut world, &mut resources);
|
||||
// resources.insert(A(0));
|
||||
// resources.insert(B(1));
|
||||
// world.insert((), vec![(X(2), Y(3)), (X(4), Y(5))]);
|
||||
// let mut my_system = into_resource_for_each_system("read_resources", my_system);
|
||||
// my_system.run(&mut world, &mut resources);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,186 @@
|
|||
use crate::resource::{
|
||||
PreparedRead, PreparedWrite, Resource, ResourceSet, ResourceTypeId, Resources,
|
||||
};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use crate::{schedule::{ArchetypeAccess, Runnable}, resource::{
|
||||
PreparedRead, PreparedWrite, ResourceSet, ResourceTypeId, Resources, self
|
||||
}, QuerySet, SystemId, SubWorld, SystemAccess};
|
||||
use std::{marker::PhantomData, ops::{Deref, DerefMut}, hash::{Hasher, Hash}};
|
||||
use legion_core::{world::{World, WorldId}, storage::ComponentTypeId, borrow::{AtomicRefCell, RefMut}, command::CommandBuffer};
|
||||
use tracing::{debug, span, info, Level};
|
||||
use fxhash::FxHashMap;
|
||||
#[derive(Debug)]
|
||||
pub struct Resource<'a, T: 'a> {
|
||||
#[allow(dead_code)]
|
||||
// held for drop impl
|
||||
_marker: PhantomData<&'a ()>,
|
||||
value: *const T,
|
||||
}
|
||||
|
||||
impl<T: Resource> ResourceSet for PreparedRead<T> {
|
||||
unsafe impl<'a, T: resource::Resource> Send for Resource<'a, T> {}
|
||||
unsafe impl<'a, T: resource::Resource> Sync for Resource<'a, T> {}
|
||||
impl<'a, T: 'a> Clone for Resource<'a, T> {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Self { Resource::new(self.value) }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Resource<'a, T> {
|
||||
#[inline(always)]
|
||||
fn new(resource: *const T) -> Self { Self { value: resource, _marker: PhantomData::default()} }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn map<K: 'a, F: FnMut(&T) -> &K>(&self, mut f: F) -> Resource<'a, K> {
|
||||
Resource::new(f(&self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Deref for Resource<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target { unsafe { &*self.value } }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> AsRef<T> for Resource<'a, T> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &T { unsafe { &*self.value } }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> std::borrow::Borrow<T> for Resource<'a, T> {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &T { unsafe { &*self.value } }
|
||||
}
|
||||
|
||||
impl<'a, T> PartialEq for Resource<'a, T>
|
||||
where
|
||||
T: 'a + PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool { self.value == other.value }
|
||||
}
|
||||
impl<'a, T> Eq for Resource<'a, T> where T: 'a + Eq {}
|
||||
|
||||
impl<'a, T> PartialOrd for Resource<'a, T>
|
||||
where
|
||||
T: 'a + PartialOrd,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.value.partial_cmp(&other.value)
|
||||
}
|
||||
}
|
||||
impl<'a, T> Ord for Resource<'a, T>
|
||||
where
|
||||
T: 'a + Ord,
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value.cmp(&other.value) }
|
||||
}
|
||||
|
||||
impl<'a, T> Hash for Resource<'a, T>
|
||||
where
|
||||
T: 'a + Hash,
|
||||
{
|
||||
fn hash<H: Hasher>(&self, state: &mut H) { self.value.hash(state); }
|
||||
}
|
||||
|
||||
impl<'a, T: resource::Resource> ResourceSet for Resource<'a, T> {
|
||||
type PreparedResources = Resource<'a, T>;
|
||||
|
||||
unsafe fn fetch_unchecked(resources: &Resources) -> Self::PreparedResources {
|
||||
let resource = resources
|
||||
.get::<T>()
|
||||
.unwrap_or_else(|| panic!("Failed to fetch resource!: {}", std::any::type_name::<T>()));
|
||||
Resource::new(resource.deref() as *const T)
|
||||
}
|
||||
fn read_types() -> Vec<ResourceTypeId> { vec![ResourceTypeId::of::<T>()] }
|
||||
fn write_types() -> Vec<ResourceTypeId> { Vec::new() }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ResourceMut<'a, T: 'a> {
|
||||
// held for drop impl
|
||||
_marker: PhantomData<&'a mut ()>,
|
||||
value: *mut T,
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: resource::Resource> Send for ResourceMut<'a, T> {}
|
||||
unsafe impl<'a, T: resource::Resource> Sync for ResourceMut<'a, T> {}
|
||||
impl<'a, T: 'a> Clone for ResourceMut<'a, T> {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Self { ResourceMut::new(self.value) }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> ResourceMut<'a, T> {
|
||||
#[inline(always)]
|
||||
fn new(resource: *mut T) -> Self { Self { value: resource, _marker: PhantomData::default()} }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn map_into<K: 'a, F: FnMut(&mut T) -> K>(mut self, mut f: F) -> ResourceMut<'a, K> {
|
||||
ResourceMut::new(&mut f(&mut self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Deref for ResourceMut<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target { unsafe { &*self.value } }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> DerefMut for ResourceMut<'a, T> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *self.value } }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> AsRef<T> for ResourceMut<'a, T> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &T { unsafe { &*self.value } }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> std::borrow::Borrow<T> for ResourceMut<'a, T> {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &T { unsafe { &*self.value } }
|
||||
}
|
||||
|
||||
impl<'a, T> PartialEq for ResourceMut<'a, T>
|
||||
where
|
||||
T: 'a + PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool { self.value == other.value }
|
||||
}
|
||||
impl<'a, T> Eq for ResourceMut<'a, T> where T: 'a + Eq {}
|
||||
|
||||
impl<'a, T> PartialOrd for ResourceMut<'a, T>
|
||||
where
|
||||
T: 'a + PartialOrd,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.value.partial_cmp(&other.value)
|
||||
}
|
||||
}
|
||||
impl<'a, T> Ord for ResourceMut<'a, T>
|
||||
where
|
||||
T: 'a + Ord,
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value.cmp(&other.value) }
|
||||
}
|
||||
|
||||
impl<'a, T> Hash for ResourceMut<'a, T>
|
||||
where
|
||||
T: 'a + Hash,
|
||||
{
|
||||
fn hash<H: Hasher>(&self, state: &mut H) { self.value.hash(state); }
|
||||
}
|
||||
|
||||
impl<'a, T: resource::Resource> ResourceSet for ResourceMut<'a, T> {
|
||||
type PreparedResources = ResourceMut<'a, T>;
|
||||
|
||||
unsafe fn fetch_unchecked(resources: &Resources) -> Self::PreparedResources {
|
||||
let mut resource = resources
|
||||
.get_mut::<T>()
|
||||
.unwrap_or_else(|| panic!("Failed to fetch resource!: {}", std::any::type_name::<T>()));
|
||||
ResourceMut::new(resource.deref_mut() as *mut T)
|
||||
}
|
||||
fn read_types() -> Vec<ResourceTypeId> { vec![ResourceTypeId::of::<T>()] }
|
||||
fn write_types() -> Vec<ResourceTypeId> { Vec::new() }
|
||||
}
|
||||
|
||||
|
||||
impl<T: resource::Resource> ResourceSet for PreparedRead<T> {
|
||||
type PreparedResources = PreparedRead<T>;
|
||||
|
||||
unsafe fn fetch_unchecked(resources: &Resources) -> Self::PreparedResources {
|
||||
|
@ -16,7 +193,7 @@ impl<T: Resource> ResourceSet for PreparedRead<T> {
|
|||
fn write_types() -> Vec<ResourceTypeId> { Vec::new() }
|
||||
}
|
||||
|
||||
impl<T: Resource> ResourceSet for PreparedWrite<T> {
|
||||
impl<T: resource::Resource> ResourceSet for PreparedWrite<T> {
|
||||
type PreparedResources = PreparedWrite<T>;
|
||||
|
||||
unsafe fn fetch_unchecked(resources: &Resources) -> Self::PreparedResources {
|
||||
|
@ -28,3 +205,135 @@ impl<T: Resource> ResourceSet for PreparedWrite<T> {
|
|||
fn read_types() -> Vec<ResourceTypeId> { Vec::new() }
|
||||
fn write_types() -> Vec<ResourceTypeId> { vec![ResourceTypeId::of::<T>()] }
|
||||
}
|
||||
|
||||
|
||||
/// The concrete type which contains the system closure provided by the user. This struct should
|
||||
/// not be instantiated directly, and instead should be created using `SystemBuilder`.
|
||||
///
|
||||
/// Implements `Schedulable` which is consumable by the `StageExecutor`, executing the closure.
|
||||
///
|
||||
/// Also handles caching of archetype information in a `BitSet`, as well as maintaining the provided
|
||||
/// information about what queries this system will run and, as a result, its data access.
|
||||
///
|
||||
/// Queries are stored generically within this struct, and the `SystemQuery` types are generated
|
||||
/// on each `run` call, wrapping the world and providing the set to the user in their closure.
|
||||
pub struct FuncSystem<R, Q, F>
|
||||
where
|
||||
R: ResourceSet,
|
||||
Q: QuerySet,
|
||||
F: FuncSystemFn<
|
||||
Resources = <R as ResourceSet>::PreparedResources,
|
||||
Queries = <Q as QuerySet>::Queries,
|
||||
>,
|
||||
{
|
||||
pub name: SystemId,
|
||||
pub _resources: PhantomData<R>,
|
||||
pub queries: AtomicRefCell<Q>,
|
||||
pub run_fn: AtomicRefCell<F>,
|
||||
pub archetypes: ArchetypeAccess,
|
||||
|
||||
// These are stored statically instead of always iterated and created from the
|
||||
// query types, which would make allocations every single request
|
||||
pub access: SystemAccess,
|
||||
|
||||
// We pre-allocate a command buffer for ourself. Writes are self-draining so we never have to rellocate.
|
||||
pub command_buffer: FxHashMap<WorldId, AtomicRefCell<CommandBuffer>>,
|
||||
}
|
||||
|
||||
impl<R, Q, F> Runnable for FuncSystem<R, Q, F>
|
||||
where
|
||||
R: ResourceSet,
|
||||
Q: QuerySet,
|
||||
F: FuncSystemFn<
|
||||
Resources = <R as ResourceSet>::PreparedResources,
|
||||
Queries = <Q as QuerySet>::Queries,
|
||||
>,
|
||||
{
|
||||
fn name(&self) -> &SystemId { &self.name }
|
||||
|
||||
fn reads(&self) -> (&[ResourceTypeId], &[ComponentTypeId]) {
|
||||
(&self.access.resources.reads, &self.access.components.reads)
|
||||
}
|
||||
fn writes(&self) -> (&[ResourceTypeId], &[ComponentTypeId]) {
|
||||
(
|
||||
&self.access.resources.writes,
|
||||
&self.access.components.writes,
|
||||
)
|
||||
}
|
||||
|
||||
fn prepare(&mut self, world: &World) {
|
||||
if let ArchetypeAccess::Some(bitset) = &mut self.archetypes {
|
||||
self.queries.get_mut().filter_archetypes(world, bitset);
|
||||
}
|
||||
}
|
||||
|
||||
fn accesses_archetypes(&self) -> &ArchetypeAccess { &self.archetypes }
|
||||
|
||||
fn command_buffer_mut(&self, world: WorldId) -> Option<RefMut<CommandBuffer>> {
|
||||
self.command_buffer.get(&world).map(|cmd| cmd.get_mut())
|
||||
}
|
||||
|
||||
unsafe fn run_unsafe(&mut self, world: &World, resources: &Resources) {
|
||||
let span = span!(Level::INFO, "System", system = %self.name);
|
||||
let _guard = span.enter();
|
||||
|
||||
debug!("Initializing");
|
||||
let resources = R::fetch_unchecked(resources);
|
||||
let mut queries = self.queries.get_mut();
|
||||
let mut prepared_queries = queries.prepare();
|
||||
let mut world_shim = SubWorld::new(world, &self.access.components, &self.archetypes);
|
||||
let cmd = self
|
||||
.command_buffer
|
||||
.entry(world.id())
|
||||
.or_insert_with(|| AtomicRefCell::new(CommandBuffer::new(world)));
|
||||
|
||||
info!("Running");
|
||||
let mut borrow = self.run_fn.get_mut();
|
||||
borrow.deref_mut().run(
|
||||
&mut cmd.get_mut(),
|
||||
&mut world_shim,
|
||||
resources,
|
||||
&mut prepared_queries,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Supertrait used for defining systems. All wrapper objects for systems implement this trait.
|
||||
///
|
||||
/// This trait will generally not be used by users.
|
||||
pub trait FuncSystemFn {
|
||||
type Resources;
|
||||
type Queries;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
commands: &mut CommandBuffer,
|
||||
world: &mut SubWorld,
|
||||
resources: Self::Resources,
|
||||
queries: &mut Self::Queries,
|
||||
);
|
||||
}
|
||||
|
||||
pub struct FuncSystemFnWrapper<
|
||||
R,
|
||||
Q,
|
||||
F: FnMut(&mut CommandBuffer, &mut SubWorld, R, &mut Q) + 'static,
|
||||
>(pub F, pub PhantomData<(R, Q)>);
|
||||
|
||||
impl<F, R, Q> FuncSystemFn for FuncSystemFnWrapper<R, Q, F>
|
||||
where
|
||||
F: FnMut(&mut CommandBuffer, &mut SubWorld, R, &mut Q) + 'static,
|
||||
{
|
||||
type Resources = R;
|
||||
type Queries = Q;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
commands: &mut CommandBuffer,
|
||||
world: &mut SubWorld,
|
||||
resources: Self::Resources,
|
||||
queries: &mut Self::Queries,
|
||||
) {
|
||||
(self.0)(commands, world, resources, queries);
|
||||
}
|
||||
}
|
|
@ -54,10 +54,11 @@ pub use legion::{
|
|||
systems::{
|
||||
bit_set::BitSet,
|
||||
resource::{
|
||||
PreparedRead as Resource, PreparedWrite as ResourceMut, ResourceSet, Resources,
|
||||
ResourceSet, Resources,
|
||||
},
|
||||
schedule::{Executor, Runnable, Schedulable, Schedule},
|
||||
IntoSystem, SubWorld, SystemBuilder,
|
||||
Resource, ResourceMut,
|
||||
},
|
||||
world::{Universe, World},
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue