mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 14:10:19 +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::{
|
use legion::{
|
||||||
filter::EntityFilter,
|
|
||||||
prelude::{
|
prelude::{
|
||||||
into_resource_for_each_system, into_resource_system, IntoQuery, ResourceSet, Resources,
|
Resources,
|
||||||
Runnable, Schedulable, World,
|
Runnable, Schedulable, World,
|
||||||
},
|
},
|
||||||
query::{DefaultFilter, View},
|
|
||||||
};
|
};
|
||||||
pub enum System {
|
pub enum System {
|
||||||
Schedulable(Box<dyn Schedulable>),
|
Schedulable(Box<dyn Schedulable>),
|
||||||
|
@ -31,25 +29,4 @@ where
|
||||||
fn from(system: T) -> Self {
|
fn from(system: T) -> Self {
|
||||||
System::ThreadLocalFn(Box::new(system))
|
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 bit_set;
|
||||||
pub use system::*;
|
pub use system::*;
|
||||||
pub use system_fn::*;
|
pub use system_fn::*;
|
||||||
|
pub use system_fn_types::{ResourceMut, Resource};
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
|
@ -17,11 +18,12 @@ pub mod prelude {
|
||||||
into_resource_system,
|
into_resource_system,
|
||||||
// aliased preparedread and preparedwrite used by system_fn
|
// aliased preparedread and preparedwrite used by system_fn
|
||||||
resource::{
|
resource::{
|
||||||
PreparedRead as Resource, PreparedWrite as ResourceMut, ResourceSet, Resources,
|
ResourceSet, Resources,
|
||||||
},
|
},
|
||||||
schedule::{Executor, Runnable, Schedulable, Schedule},
|
schedule::{Executor, Runnable, Schedulable, Schedule},
|
||||||
IntoSystem,
|
IntoSystem,
|
||||||
System,
|
System,
|
||||||
SystemBuilder,
|
SystemBuilder,
|
||||||
|
Resource, ResourceMut,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -630,7 +630,7 @@ pub struct SubWorld {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubWorld {
|
impl SubWorld {
|
||||||
unsafe fn new(
|
pub(super) unsafe fn new(
|
||||||
world: &World,
|
world: &World,
|
||||||
access: &Access<ComponentTypeId>,
|
access: &Access<ComponentTypeId>,
|
||||||
archetypes: &ArchetypeAccess,
|
archetypes: &ArchetypeAccess,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
resource::{PreparedRead, Resource, ResourceSet, ResourceTypeId},
|
resource::{ResourceSet, ResourceTypeId},
|
||||||
schedule::{ArchetypeAccess, Schedulable},
|
schedule::{ArchetypeAccess, Schedulable},
|
||||||
Access, System, SystemAccess, SystemFnWrapper, SystemQuery,
|
Access, SystemAccess, SystemQuery, system_fn_types::{FuncSystem, FuncSystemFnWrapper},
|
||||||
};
|
};
|
||||||
use bit_set::BitSet;
|
use bit_set::BitSet;
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
|
@ -20,9 +20,9 @@ pub fn into_resource_for_each_system<'a, Q, F, R, X>(
|
||||||
where
|
where
|
||||||
Q: IntoQuery + DefaultFilter<Filter = R>,
|
Q: IntoQuery + DefaultFilter<Filter = R>,
|
||||||
<Q as View<'a>>::Iter: Iterator<Item = Q> + 'a,
|
<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,
|
R: EntityFilter + Sync + 'static,
|
||||||
X: ResourceSet<PreparedResources = X> + 'static,
|
X: ResourceSet<PreparedResources = X> + 'static + Clone,
|
||||||
{
|
{
|
||||||
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
||||||
resource_access.reads.extend(X::read_types().iter());
|
resource_access.reads.extend(X::read_types().iter());
|
||||||
|
@ -32,19 +32,19 @@ where
|
||||||
component_access.reads.extend(Q::read_types().iter());
|
component_access.reads.extend(Q::read_types().iter());
|
||||||
component_access.writes.extend(Q::write_types().iter());
|
component_access.writes.extend(Q::write_types().iter());
|
||||||
|
|
||||||
let run_fn = SystemFnWrapper(
|
let run_fn = FuncSystemFnWrapper(
|
||||||
move |_,
|
move |_,
|
||||||
world,
|
world,
|
||||||
resources: &mut X,
|
resources: X,
|
||||||
query: &mut SystemQuery<Q, <Q as DefaultFilter>::Filter>| {
|
query: &mut SystemQuery<Q, <Q as DefaultFilter>::Filter>| {
|
||||||
for components in query.iter_mut(world) {
|
for components in query.iter_mut(world) {
|
||||||
system(resources, components);
|
system(resources.clone(), components);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PhantomData,
|
PhantomData,
|
||||||
);
|
);
|
||||||
|
|
||||||
Box::new(System {
|
Box::new(FuncSystem {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
queries: AtomicRefCell::new(Q::query()),
|
queries: AtomicRefCell::new(Q::query()),
|
||||||
access: SystemAccess {
|
access: SystemAccess {
|
||||||
|
@ -61,7 +61,7 @@ where
|
||||||
|
|
||||||
pub fn into_resource_system<'a, F, X>(name: &'static str, mut system: F) -> Box<dyn Schedulable>
|
pub fn into_resource_system<'a, F, X>(name: &'static str, mut system: F) -> Box<dyn Schedulable>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut X) + Send + Sync + 'static,
|
F: FnMut(X) + Send + Sync + 'static,
|
||||||
X: ResourceSet<PreparedResources = X> + 'static,
|
X: ResourceSet<PreparedResources = X> + 'static,
|
||||||
{
|
{
|
||||||
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
||||||
|
@ -69,14 +69,14 @@ where
|
||||||
resource_access.writes.extend(X::write_types().iter());
|
resource_access.writes.extend(X::write_types().iter());
|
||||||
|
|
||||||
let component_access: Access<ComponentTypeId> = Access::default();
|
let component_access: Access<ComponentTypeId> = Access::default();
|
||||||
let run_fn = SystemFnWrapper(
|
let run_fn = FuncSystemFnWrapper(
|
||||||
move |_, _, resources: &mut X, _| {
|
move |_, _, resources: X, _| {
|
||||||
system(resources);
|
system(resources);
|
||||||
},
|
},
|
||||||
PhantomData,
|
PhantomData,
|
||||||
);
|
);
|
||||||
|
|
||||||
Box::new(System {
|
Box::new(FuncSystem {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
queries: AtomicRefCell::new(()),
|
queries: AtomicRefCell::new(()),
|
||||||
access: SystemAccess {
|
access: SystemAccess {
|
||||||
|
@ -98,72 +98,17 @@ where
|
||||||
fn into_system(self, name: &'static str) -> Box<dyn Schedulable>;
|
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<
|
impl<
|
||||||
'a,
|
'a,
|
||||||
F,
|
F,
|
||||||
X: Resource + Send + Sync + 'static,
|
X: ResourceSet<PreparedResources = X> + 'static + Clone,
|
||||||
A: for<'b> View<'b> + DefaultFilter<Filter = AF> + ViewElement,
|
A: for<'b> View<'b> + DefaultFilter<Filter = AF> + ViewElement,
|
||||||
AF: EntityFilter + Sync + 'static,
|
AF: EntityFilter + Sync + 'static,
|
||||||
B: for<'b> View<'b> + DefaultFilter<Filter = BF> + ViewElement,
|
B: for<'b> View<'b> + DefaultFilter<Filter = BF> + ViewElement,
|
||||||
BF: EntityFilter + Sync + 'static,
|
BF: EntityFilter + Sync + 'static,
|
||||||
> IntoSystem<'a, (X,), (A, B)> for F
|
> IntoSystem<'a, (X,), (A, B)> for F
|
||||||
where
|
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>,
|
<A as View<'a>>::Iter: Iterator<Item = A>,
|
||||||
<B as View<'a>>::Iter: Iterator<Item = B>,
|
<B as View<'a>>::Iter: Iterator<Item = B>,
|
||||||
{
|
{
|
||||||
|
@ -171,10 +116,10 @@ where
|
||||||
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
let mut resource_access: Access<ResourceTypeId> = Access::default();
|
||||||
resource_access
|
resource_access
|
||||||
.reads
|
.reads
|
||||||
.extend(<PreparedRead<X>>::read_types().iter());
|
.extend(<X>::read_types().iter());
|
||||||
resource_access
|
resource_access
|
||||||
.writes
|
.writes
|
||||||
.extend(<PreparedRead<X>>::write_types().iter());
|
.extend(<X>::write_types().iter());
|
||||||
let mut component_access: Access<ComponentTypeId> = Access::default();
|
let mut component_access: Access<ComponentTypeId> = Access::default();
|
||||||
component_access
|
component_access
|
||||||
.reads
|
.reads
|
||||||
|
@ -183,10 +128,10 @@ where
|
||||||
.writes
|
.writes
|
||||||
.extend(<(A, B) as View>::write_types().iter());
|
.extend(<(A, B) as View>::write_types().iter());
|
||||||
|
|
||||||
let run_fn = SystemFnWrapper(
|
let run_fn = FuncSystemFnWrapper(
|
||||||
move |_,
|
move |_,
|
||||||
world,
|
world,
|
||||||
x: &mut PreparedRead<X>,
|
x: X::PreparedResources,
|
||||||
query: &mut SystemQuery<
|
query: &mut SystemQuery<
|
||||||
(A, B),
|
(A, B),
|
||||||
EntityFilterTuple<
|
EntityFilterTuple<
|
||||||
|
@ -205,13 +150,13 @@ where
|
||||||
>,
|
>,
|
||||||
>| {
|
>| {
|
||||||
for (a, b) in query.iter_mut(world) {
|
for (a, b) in query.iter_mut(world) {
|
||||||
self(&*x, a, b);
|
self(x.clone(), a, b);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PhantomData,
|
PhantomData,
|
||||||
);
|
);
|
||||||
|
|
||||||
Box::new(System {
|
Box::new(FuncSystem {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
queries: AtomicRefCell::new(<(A, B)>::query()),
|
queries: AtomicRefCell::new(<(A, B)>::query()),
|
||||||
access: SystemAccess {
|
access: SystemAccess {
|
||||||
|
@ -220,7 +165,7 @@ where
|
||||||
tags: Access::default(),
|
tags: Access::default(),
|
||||||
},
|
},
|
||||||
archetypes: ArchetypeAccess::Some(BitSet::default()),
|
archetypes: ArchetypeAccess::Some(BitSet::default()),
|
||||||
_resources: PhantomData::<PreparedRead<X>>,
|
_resources: PhantomData::<X::PreparedResources>,
|
||||||
command_buffer: FxHashMap::default(),
|
command_buffer: FxHashMap::default(),
|
||||||
run_fn: AtomicRefCell::new(run_fn),
|
run_fn: AtomicRefCell::new(run_fn),
|
||||||
})
|
})
|
||||||
|
@ -242,10 +187,10 @@ macro_rules! impl_system {
|
||||||
let resource_access: Access<ResourceTypeId> = Access::default();
|
let resource_access: Access<ResourceTypeId> = Access::default();
|
||||||
let component_access: Access<ComponentTypeId> = component_access!(($($view),+));
|
let component_access: Access<ComponentTypeId> = component_access!(($($view),+));
|
||||||
|
|
||||||
let run_fn = SystemFnWrapper(
|
let run_fn = FuncSystemFnWrapper(
|
||||||
move |_,
|
move |_,
|
||||||
world,
|
world,
|
||||||
_: &mut (),
|
_: (),
|
||||||
query: &mut system_query!($($view, $filter),+)
|
query: &mut system_query!($($view, $filter),+)
|
||||||
,
|
,
|
||||||
| {
|
| {
|
||||||
|
@ -256,7 +201,7 @@ macro_rules! impl_system {
|
||||||
PhantomData,
|
PhantomData,
|
||||||
);
|
);
|
||||||
|
|
||||||
Box::new(System {
|
Box::new(FuncSystem {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
queries: AtomicRefCell::new(query!($($view),+)),
|
queries: AtomicRefCell::new(query!($($view),+)),
|
||||||
access: SystemAccess {
|
access: SystemAccess {
|
||||||
|
@ -357,7 +302,7 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
into_resource_for_each_system,
|
into_resource_for_each_system,
|
||||||
resource::{PreparedRead, PreparedWrite, Resources},
|
resource::{PreparedRead, PreparedWrite, Resources},
|
||||||
IntoSystem,
|
IntoSystem, system_fn_types::{ResourceMut, Resource},
|
||||||
};
|
};
|
||||||
use legion_core::{
|
use legion_core::{
|
||||||
borrow::{Ref, RefMut},
|
borrow::{Ref, RefMut},
|
||||||
|
@ -375,30 +320,53 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_into_system() {
|
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 world = World::new();
|
||||||
let mut resources = Resources::default();
|
let mut resources = Resources::default();
|
||||||
resources.insert(A(0));
|
resources.insert(A(0));
|
||||||
world.insert((), vec![(X(1), Y(1)), (X(2), Y(2))]);
|
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);
|
system.run(&mut world, &mut resources);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system_fn() {
|
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 world = World::new();
|
||||||
let mut resources = Resources::default();
|
let mut resources = Resources::default();
|
||||||
|
@ -410,34 +378,34 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_resource_system_fn() {
|
fn test_resource_system_fn() {
|
||||||
fn my_system(
|
// fn my_system(
|
||||||
(a, b): &mut (PreparedWrite<A>, PreparedRead<B>),
|
// (a,): (Resource<A>,),
|
||||||
(x, mut y): (Ref<X>, RefMut<Y>),
|
// (x, mut y): (Ref<X>, RefMut<Y>),
|
||||||
) {
|
// ) {
|
||||||
assert_eq!(**b, B(1));
|
// assert_eq!(*a, A(1));
|
||||||
// assert_eq!(**b, B(0));
|
// // assert_eq!(**b, B(0));
|
||||||
if a.0 == 0 {
|
// if a.0 == 0 {
|
||||||
assert_eq!(*x, X(2));
|
// assert_eq!(*x, X(2));
|
||||||
assert_eq!(*y, Y(3));
|
// assert_eq!(*y, Y(3));
|
||||||
} else if a.0 == 1 {
|
// } else if a.0 == 1 {
|
||||||
assert_eq!(*x, X(4));
|
// assert_eq!(*x, X(4));
|
||||||
assert_eq!(*y, Y(5));
|
// assert_eq!(*y, Y(5));
|
||||||
y.0 += 1;
|
// y.0 += 1;
|
||||||
assert_eq!(*y, Y(6));
|
// assert_eq!(*y, Y(6));
|
||||||
} else {
|
// } else {
|
||||||
panic!("unexpected value");
|
// panic!("unexpected value");
|
||||||
}
|
// }
|
||||||
|
|
||||||
a.0 += 1;
|
// // a.0 += 1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
let mut world = World::new();
|
// let mut world = World::new();
|
||||||
let mut resources = Resources::default();
|
// let mut resources = Resources::default();
|
||||||
|
|
||||||
resources.insert(A(0));
|
// resources.insert(A(0));
|
||||||
resources.insert(B(1));
|
// resources.insert(B(1));
|
||||||
world.insert((), vec![(X(2), Y(3)), (X(4), Y(5))]);
|
// world.insert((), vec![(X(2), Y(3)), (X(4), Y(5))]);
|
||||||
let mut my_system = into_resource_for_each_system("read_resources", my_system);
|
// let mut my_system = into_resource_for_each_system("read_resources", my_system);
|
||||||
my_system.run(&mut world, &mut resources);
|
// my_system.run(&mut world, &mut resources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,186 @@
|
||||||
use crate::resource::{
|
use crate::{schedule::{ArchetypeAccess, Runnable}, resource::{
|
||||||
PreparedRead, PreparedWrite, Resource, ResourceSet, ResourceTypeId, Resources,
|
PreparedRead, PreparedWrite, ResourceSet, ResourceTypeId, Resources, self
|
||||||
};
|
}, QuerySet, SystemId, SubWorld, SystemAccess};
|
||||||
use std::ops::{Deref, DerefMut};
|
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>;
|
type PreparedResources = PreparedRead<T>;
|
||||||
|
|
||||||
unsafe fn fetch_unchecked(resources: &Resources) -> Self::PreparedResources {
|
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() }
|
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>;
|
type PreparedResources = PreparedWrite<T>;
|
||||||
|
|
||||||
unsafe fn fetch_unchecked(resources: &Resources) -> Self::PreparedResources {
|
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 read_types() -> Vec<ResourceTypeId> { Vec::new() }
|
||||||
fn write_types() -> Vec<ResourceTypeId> { vec![ResourceTypeId::of::<T>()] }
|
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::{
|
systems::{
|
||||||
bit_set::BitSet,
|
bit_set::BitSet,
|
||||||
resource::{
|
resource::{
|
||||||
PreparedRead as Resource, PreparedWrite as ResourceMut, ResourceSet, Resources,
|
ResourceSet, Resources,
|
||||||
},
|
},
|
||||||
schedule::{Executor, Runnable, Schedulable, Schedule},
|
schedule::{Executor, Runnable, Schedulable, Schedule},
|
||||||
IntoSystem, SubWorld, SystemBuilder,
|
IntoSystem, SubWorld, SystemBuilder,
|
||||||
|
Resource, ResourceMut,
|
||||||
},
|
},
|
||||||
world::{Universe, World},
|
world::{Universe, World},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue