2020-12-16 05:57:16 +00:00
|
|
|
use super::system_param::FetchSystemParam;
|
2020-11-16 04:32:23 +00:00
|
|
|
use crate::{
|
|
|
|
ArchetypeComponent, Commands, QueryAccess, Resources, System, SystemId, SystemParam,
|
2021-02-09 20:14:10 +00:00
|
|
|
TypeAccess, World,
|
2020-11-16 04:32:23 +00:00
|
|
|
};
|
2020-11-08 20:34:05 +00:00
|
|
|
use parking_lot::Mutex;
|
2020-12-16 05:57:16 +00:00
|
|
|
use std::{any::TypeId, borrow::Cow, cell::UnsafeCell, sync::Arc};
|
2020-11-08 20:34:05 +00:00
|
|
|
|
|
|
|
pub struct SystemState {
|
|
|
|
pub(crate) id: SystemId,
|
|
|
|
pub(crate) name: Cow<'static, str>,
|
|
|
|
pub(crate) archetype_component_access: TypeAccess<ArchetypeComponent>,
|
2021-02-09 20:14:10 +00:00
|
|
|
pub(crate) component_access: TypeAccess<TypeId>,
|
2020-11-08 20:34:05 +00:00
|
|
|
pub(crate) resource_access: TypeAccess<TypeId>,
|
2021-02-09 20:14:10 +00:00
|
|
|
pub(crate) is_non_send: bool,
|
2020-11-15 20:42:43 +00:00
|
|
|
pub(crate) local_resource_access: TypeAccess<TypeId>,
|
2020-11-08 20:34:05 +00:00
|
|
|
pub(crate) query_archetype_component_accesses: Vec<TypeAccess<ArchetypeComponent>>,
|
|
|
|
pub(crate) query_accesses: Vec<Vec<QueryAccess>>,
|
|
|
|
pub(crate) query_type_names: Vec<&'static str>,
|
2020-12-16 05:57:16 +00:00
|
|
|
pub(crate) commands: UnsafeCell<Commands>,
|
2020-11-08 20:34:05 +00:00
|
|
|
pub(crate) arc_commands: Option<Arc<Mutex<Commands>>>,
|
2020-12-16 05:57:16 +00:00
|
|
|
pub(crate) current_query_index: UnsafeCell<usize>,
|
2020-11-08 20:34:05 +00:00
|
|
|
}
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
// SAFE: UnsafeCell<Commands> and UnsafeCell<usize> only accessed from the thread they are scheduled on
|
|
|
|
unsafe impl Sync for SystemState {}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
impl SystemState {
|
|
|
|
pub fn reset_indices(&mut self) {
|
2020-12-16 05:57:16 +00:00
|
|
|
// SAFE: done with unique mutable access to Self
|
|
|
|
unsafe {
|
|
|
|
*self.current_query_index.get() = 0;
|
|
|
|
}
|
2020-11-08 20:34:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update(&mut self, world: &World) {
|
|
|
|
self.archetype_component_access.clear();
|
|
|
|
let mut conflict_index = None;
|
|
|
|
let mut conflict_name = None;
|
|
|
|
for (i, (query_accesses, component_access)) in self
|
|
|
|
.query_accesses
|
|
|
|
.iter()
|
|
|
|
.zip(self.query_archetype_component_accesses.iter_mut())
|
|
|
|
.enumerate()
|
|
|
|
{
|
|
|
|
component_access.clear();
|
|
|
|
for query_access in query_accesses.iter() {
|
|
|
|
query_access.get_world_archetype_access(world, Some(component_access));
|
|
|
|
}
|
|
|
|
if !component_access.is_compatible(&self.archetype_component_access) {
|
|
|
|
conflict_index = Some(i);
|
|
|
|
conflict_name = component_access
|
|
|
|
.get_conflict(&self.archetype_component_access)
|
|
|
|
.and_then(|archetype_component| {
|
|
|
|
query_accesses
|
|
|
|
.iter()
|
|
|
|
.filter_map(|query_access| {
|
|
|
|
query_access.get_type_name(archetype_component.component)
|
|
|
|
})
|
|
|
|
.next()
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
2021-02-09 20:14:10 +00:00
|
|
|
self.archetype_component_access.extend(component_access);
|
2020-11-08 20:34:05 +00:00
|
|
|
}
|
|
|
|
if let Some(conflict_index) = conflict_index {
|
|
|
|
let mut conflicts_with_index = None;
|
|
|
|
for prior_index in 0..conflict_index {
|
|
|
|
if !self.query_archetype_component_accesses[conflict_index]
|
|
|
|
.is_compatible(&self.query_archetype_component_accesses[prior_index])
|
|
|
|
{
|
|
|
|
conflicts_with_index = Some(prior_index);
|
|
|
|
}
|
|
|
|
}
|
2020-12-02 19:31:16 +00:00
|
|
|
panic!("System {} has conflicting queries. {} conflicts with the component access [{}] in this prior query: {}.",
|
2020-11-08 21:48:00 +00:00
|
|
|
self.name,
|
2020-11-08 20:34:05 +00:00
|
|
|
self.query_type_names[conflict_index],
|
|
|
|
conflict_name.unwrap_or("Unknown"),
|
|
|
|
conflicts_with_index.map(|index| self.query_type_names[index]).unwrap_or("Unknown"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
pub struct FuncSystem<Out> {
|
|
|
|
func:
|
|
|
|
Box<dyn FnMut(&mut SystemState, &World, &Resources) -> Option<Out> + Send + Sync + 'static>,
|
|
|
|
init_func: Box<dyn FnMut(&mut SystemState, &World, &mut Resources) + Send + Sync + 'static>,
|
|
|
|
state: SystemState,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Out: 'static> System for FuncSystem<Out> {
|
|
|
|
type In = ();
|
|
|
|
type Out = Out;
|
|
|
|
|
|
|
|
fn name(&self) -> std::borrow::Cow<'static, str> {
|
|
|
|
self.state.name.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn id(&self) -> SystemId {
|
|
|
|
self.state.id
|
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn update_access(&mut self, world: &World) {
|
2020-12-16 05:57:16 +00:00
|
|
|
self.state.update(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
|
|
|
|
&self.state.archetype_component_access
|
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn component_access(&self) -> &TypeAccess<TypeId> {
|
|
|
|
&self.state.component_access
|
|
|
|
}
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
fn resource_access(&self) -> &TypeAccess<std::any::TypeId> {
|
|
|
|
&self.state.resource_access
|
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn is_non_send(&self) -> bool {
|
|
|
|
self.state.is_non_send
|
2020-12-16 05:57:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn run_unsafe(
|
|
|
|
&mut self,
|
|
|
|
_input: Self::In,
|
|
|
|
world: &World,
|
|
|
|
resources: &Resources,
|
|
|
|
) -> Option<Out> {
|
|
|
|
(self.func)(&mut self.state, world, resources)
|
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn apply_buffers(&mut self, world: &mut World, resources: &mut Resources) {
|
|
|
|
// SAFE: this is called with unique access to SystemState
|
|
|
|
unsafe {
|
|
|
|
(&mut *self.state.commands.get()).apply(world, resources);
|
|
|
|
}
|
|
|
|
if let Some(ref commands) = self.state.arc_commands {
|
|
|
|
let mut commands = commands.lock();
|
|
|
|
commands.apply(world, resources);
|
|
|
|
}
|
2020-12-16 05:57:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn initialize(&mut self, world: &mut World, resources: &mut Resources) {
|
|
|
|
(self.init_func)(&mut self.state, world, resources);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InputFuncSystem<In, Out> {
|
2020-11-17 02:18:00 +00:00
|
|
|
func: Box<
|
2020-12-13 02:04:42 +00:00
|
|
|
dyn FnMut(In, &mut SystemState, &World, &Resources) -> Option<Out> + Send + Sync + 'static,
|
2020-11-17 02:18:00 +00:00
|
|
|
>,
|
|
|
|
init_func: Box<dyn FnMut(&mut SystemState, &World, &mut Resources) + Send + Sync + 'static>,
|
2020-11-08 20:34:05 +00:00
|
|
|
state: SystemState,
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
impl<In: 'static, Out: 'static> System for InputFuncSystem<In, Out> {
|
2020-12-13 02:04:42 +00:00
|
|
|
type In = In;
|
|
|
|
type Out = Out;
|
2020-11-17 02:18:00 +00:00
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
fn name(&self) -> std::borrow::Cow<'static, str> {
|
|
|
|
self.state.name.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn id(&self) -> SystemId {
|
|
|
|
self.state.id
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn update_access(&mut self, world: &World) {
|
2020-11-08 20:34:05 +00:00
|
|
|
self.state.update(world);
|
2020-07-14 02:29:34 +00:00
|
|
|
}
|
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
|
2020-11-08 20:34:05 +00:00
|
|
|
&self.state.archetype_component_access
|
2020-07-14 02:29:34 +00:00
|
|
|
}
|
2020-07-17 00:23:50 +00:00
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn component_access(&self) -> &TypeAccess<TypeId> {
|
|
|
|
&self.state.component_access
|
|
|
|
}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
fn resource_access(&self) -> &TypeAccess<std::any::TypeId> {
|
|
|
|
&self.state.resource_access
|
2020-07-16 00:20:36 +00:00
|
|
|
}
|
2020-07-14 02:29:34 +00:00
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn is_non_send(&self) -> bool {
|
|
|
|
self.state.is_non_send
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 02:18:00 +00:00
|
|
|
unsafe fn run_unsafe(
|
|
|
|
&mut self,
|
2020-12-13 02:04:42 +00:00
|
|
|
input: In,
|
2020-11-17 02:18:00 +00:00
|
|
|
world: &World,
|
|
|
|
resources: &Resources,
|
2020-12-13 02:04:42 +00:00
|
|
|
) -> Option<Out> {
|
2020-11-17 02:18:00 +00:00
|
|
|
(self.func)(input, &mut self.state, world, resources)
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
fn apply_buffers(&mut self, world: &mut World, resources: &mut Resources) {
|
|
|
|
// SAFE: this is called with unique access to SystemState
|
|
|
|
unsafe {
|
|
|
|
(&mut *self.state.commands.get()).apply(world, resources);
|
|
|
|
}
|
|
|
|
if let Some(ref commands) = self.state.arc_commands {
|
|
|
|
let mut commands = commands.lock();
|
|
|
|
commands.apply(world, resources);
|
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-09-18 00:16:38 +00:00
|
|
|
fn initialize(&mut self, world: &mut World, resources: &mut Resources) {
|
2020-11-08 20:34:05 +00:00
|
|
|
(self.init_func)(&mut self.state, world, resources);
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
pub trait IntoSystem<Params, SystemType> {
|
2020-11-17 02:18:00 +00:00
|
|
|
fn system(self) -> SystemType;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Systems implicitly implement IntoSystem
|
|
|
|
impl<Sys: System> IntoSystem<(), Sys> for Sys {
|
|
|
|
fn system(self) -> Sys {
|
|
|
|
self
|
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
2020-12-16 05:57:16 +00:00
|
|
|
pub struct In<In>(pub In);
|
2020-07-10 04:18:35 +00:00
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
macro_rules! impl_into_system {
|
|
|
|
($($param: ident),*) => {
|
2020-12-16 05:57:16 +00:00
|
|
|
impl<Func, Out, $($param: SystemParam),*> IntoSystem<($($param,)*), FuncSystem<Out>> for Func
|
|
|
|
where
|
|
|
|
Func:
|
|
|
|
FnMut($($param),*) -> Out +
|
|
|
|
FnMut($(<<$param as SystemParam>::Fetch as FetchSystemParam>::Item),*) -> Out +
|
|
|
|
Send + Sync + 'static, Out: 'static
|
2020-07-10 04:18:35 +00:00
|
|
|
{
|
|
|
|
#[allow(unused_variables)]
|
2020-07-12 19:06:43 +00:00
|
|
|
#[allow(unused_unsafe)]
|
2020-07-10 04:18:35 +00:00
|
|
|
#[allow(non_snake_case)]
|
2020-12-16 05:57:16 +00:00
|
|
|
fn system(mut self) -> FuncSystem<Out> {
|
2020-11-17 02:18:00 +00:00
|
|
|
FuncSystem {
|
2020-11-08 20:34:05 +00:00
|
|
|
state: SystemState {
|
|
|
|
name: std::any::type_name::<Self>().into(),
|
|
|
|
archetype_component_access: TypeAccess::default(),
|
2021-02-09 20:14:10 +00:00
|
|
|
component_access: TypeAccess::default(),
|
2020-11-08 20:34:05 +00:00
|
|
|
resource_access: TypeAccess::default(),
|
2021-02-09 20:14:10 +00:00
|
|
|
is_non_send: false,
|
2020-11-15 20:42:43 +00:00
|
|
|
local_resource_access: TypeAccess::default(),
|
2020-11-08 20:34:05 +00:00
|
|
|
id: SystemId::new(),
|
2020-12-16 05:57:16 +00:00
|
|
|
commands: Default::default(),
|
2020-11-08 20:34:05 +00:00
|
|
|
arc_commands: Default::default(),
|
2020-12-16 05:57:16 +00:00
|
|
|
current_query_index: Default::default(),
|
2020-11-08 20:34:05 +00:00
|
|
|
query_archetype_component_accesses: Vec::new(),
|
|
|
|
query_accesses: Vec::new(),
|
|
|
|
query_type_names: Vec::new(),
|
2020-07-15 02:05:39 +00:00
|
|
|
},
|
2020-12-16 05:57:16 +00:00
|
|
|
func: Box::new(move |state, world, resources| {
|
2020-11-08 20:34:05 +00:00
|
|
|
state.reset_indices();
|
2020-12-16 05:57:16 +00:00
|
|
|
// let mut input = Some(input);
|
2020-11-08 20:34:05 +00:00
|
|
|
unsafe {
|
2020-12-16 05:57:16 +00:00
|
|
|
if let Some(($($param,)*)) = <<($($param,)*) as SystemParam>::Fetch as FetchSystemParam>::get_param(state, world, resources) {
|
2020-11-17 02:18:00 +00:00
|
|
|
Some(self($($param),*))
|
|
|
|
} else {
|
|
|
|
None
|
2020-09-10 20:15:02 +00:00
|
|
|
}
|
2020-07-12 19:27:11 +00:00
|
|
|
}
|
2020-11-17 02:18:00 +00:00
|
|
|
}),
|
2020-12-16 05:57:16 +00:00
|
|
|
init_func: Box::new(|state, world, resources| {
|
|
|
|
<<($($param,)*) as SystemParam>::Fetch as FetchSystemParam>::init(state, world, resources)
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<Func, Input, Out, $($param: SystemParam),*> IntoSystem<(Input, $($param,)*), InputFuncSystem<Input, Out>> for Func
|
|
|
|
where
|
|
|
|
Func:
|
|
|
|
FnMut(In<Input>, $($param),*) -> Out +
|
|
|
|
FnMut(In<Input>, $(<<$param as SystemParam>::Fetch as FetchSystemParam>::Item),*) -> Out +
|
|
|
|
Send + Sync + 'static, Input: 'static, Out: 'static
|
|
|
|
{
|
|
|
|
#[allow(unused_variables)]
|
|
|
|
#[allow(unused_unsafe)]
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
fn system(mut self) -> InputFuncSystem<Input, Out> {
|
|
|
|
InputFuncSystem {
|
|
|
|
state: SystemState {
|
|
|
|
name: std::any::type_name::<Self>().into(),
|
|
|
|
archetype_component_access: TypeAccess::default(),
|
2021-02-09 20:14:10 +00:00
|
|
|
component_access: TypeAccess::default(),
|
2020-12-16 05:57:16 +00:00
|
|
|
resource_access: TypeAccess::default(),
|
2021-02-09 20:14:10 +00:00
|
|
|
is_non_send: false,
|
2020-12-16 05:57:16 +00:00
|
|
|
local_resource_access: TypeAccess::default(),
|
|
|
|
id: SystemId::new(),
|
|
|
|
commands: Default::default(),
|
|
|
|
arc_commands: Default::default(),
|
|
|
|
current_query_index: Default::default(),
|
|
|
|
query_archetype_component_accesses: Vec::new(),
|
|
|
|
query_accesses: Vec::new(),
|
|
|
|
query_type_names: Vec::new(),
|
|
|
|
},
|
|
|
|
func: Box::new(move |input, state, world, resources| {
|
|
|
|
state.reset_indices();
|
|
|
|
// let mut input = Some(input);
|
|
|
|
unsafe {
|
|
|
|
if let Some(($($param,)*)) = <<($($param,)*) as SystemParam>::Fetch as FetchSystemParam>::get_param(state, world, resources) {
|
|
|
|
Some(self(In(input), $($param),*))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
2020-11-17 02:18:00 +00:00
|
|
|
init_func: Box::new(|state, world, resources| {
|
2020-12-16 05:57:16 +00:00
|
|
|
<<($($param,)*) as SystemParam>::Fetch as FetchSystemParam>::init(state, world, resources)
|
2020-11-17 02:18:00 +00:00
|
|
|
}),
|
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
impl_into_system!();
|
|
|
|
impl_into_system!(A);
|
|
|
|
impl_into_system!(A, B);
|
|
|
|
impl_into_system!(A, B, C);
|
|
|
|
impl_into_system!(A, B, C, D);
|
|
|
|
impl_into_system!(A, B, C, D, E);
|
|
|
|
impl_into_system!(A, B, C, D, E, F);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I, J);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
|
|
|
|
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
2020-07-15 02:05:39 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-11-08 20:34:05 +00:00
|
|
|
use super::IntoSystem;
|
2020-07-17 02:20:51 +00:00
|
|
|
use crate::{
|
2020-12-13 02:04:42 +00:00
|
|
|
clear_trackers_system,
|
2020-11-15 20:42:43 +00:00
|
|
|
resource::{Res, ResMut, Resources},
|
2020-07-17 02:20:51 +00:00
|
|
|
schedule::Schedule,
|
2021-03-03 01:59:40 +00:00
|
|
|
Entity, IntoExclusiveSystem, Local, Query, QuerySet, Stage, System, SystemStage, With,
|
|
|
|
World,
|
2020-07-17 02:20:51 +00:00
|
|
|
};
|
2020-07-15 02:05:39 +00:00
|
|
|
|
2020-11-15 20:42:43 +00:00
|
|
|
#[derive(Debug, Eq, PartialEq, Default)]
|
2020-07-15 02:05:39 +00:00
|
|
|
struct A;
|
|
|
|
struct B;
|
|
|
|
struct C;
|
|
|
|
struct D;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn query_system_gets() {
|
|
|
|
fn query_system(
|
|
|
|
mut ran: ResMut<bool>,
|
2020-11-11 04:48:34 +00:00
|
|
|
entity_query: Query<Entity, With<A>>,
|
2020-07-15 02:05:39 +00:00
|
|
|
b_query: Query<&B>,
|
|
|
|
a_c_query: Query<(&A, &C)>,
|
|
|
|
d_query: Query<&D>,
|
|
|
|
) {
|
2020-10-30 06:39:55 +00:00
|
|
|
let entities = entity_query.iter().collect::<Vec<Entity>>();
|
2020-07-15 02:05:39 +00:00
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<B>(entities[0]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 0 should not have B"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<B>(entities[1]).is_ok(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 1 should have B"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<A>(entities[1]).is_err(),
|
2020-10-30 06:39:55 +00:00
|
|
|
"entity 1 should have A, but b_query shouldn't have access to it"
|
|
|
|
);
|
2020-07-15 02:05:39 +00:00
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<D>(entities[3]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 3 should have D, but it shouldn't be accessible from b_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<C>(entities[2]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 2 has C, but it shouldn't be accessible from b_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
a_c_query.get_component::<C>(entities[2]).is_ok(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 2 has C, and it should be accessible from a_c_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
a_c_query.get_component::<D>(entities[3]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 3 should have D, but it shouldn't be accessible from b_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
d_query.get_component::<D>(entities[3]).is_ok(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 3 should have D"
|
|
|
|
);
|
|
|
|
|
|
|
|
*ran = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
resources.insert(false);
|
|
|
|
world.spawn((A,));
|
|
|
|
world.spawn((A, B));
|
|
|
|
world.spawn((A, C));
|
|
|
|
world.spawn((A, D));
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
run_system(&mut world, &mut resources, query_system.system());
|
2020-07-15 02:05:39 +00:00
|
|
|
|
|
|
|
assert!(*resources.get::<bool>().unwrap(), "system ran");
|
|
|
|
}
|
2020-09-10 20:15:02 +00:00
|
|
|
|
2020-11-02 00:51:51 +00:00
|
|
|
#[test]
|
|
|
|
fn or_query_set_system() {
|
|
|
|
// Regression test for issue #762
|
|
|
|
use crate::{Added, Changed, Mutated, Or};
|
2020-12-16 05:57:16 +00:00
|
|
|
fn query_system(
|
|
|
|
mut ran: ResMut<bool>,
|
|
|
|
set: QuerySet<(
|
|
|
|
Query<(), Or<(Changed<A>, Changed<B>)>>,
|
|
|
|
Query<(), Or<(Added<A>, Added<B>)>>,
|
|
|
|
Query<(), Or<(Mutated<A>, Mutated<B>)>>,
|
|
|
|
)>,
|
|
|
|
) {
|
2020-11-02 00:51:51 +00:00
|
|
|
let changed = set.q0().iter().count();
|
|
|
|
let added = set.q1().iter().count();
|
|
|
|
let mutated = set.q2().iter().count();
|
|
|
|
|
|
|
|
assert_eq!(changed, 1);
|
|
|
|
assert_eq!(added, 1);
|
|
|
|
assert_eq!(mutated, 0);
|
|
|
|
|
|
|
|
*ran = true;
|
2020-12-31 22:05:37 +00:00
|
|
|
}
|
2020-11-02 00:51:51 +00:00
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
resources.insert(false);
|
|
|
|
world.spawn((A, B));
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
run_system(&mut world, &mut resources, query_system.system());
|
2020-11-08 20:34:05 +00:00
|
|
|
|
|
|
|
assert!(*resources.get::<bool>().unwrap(), "system ran");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn changed_resource_system() {
|
2021-03-03 01:59:40 +00:00
|
|
|
fn incr_e_on_flip(run_on_flip: Res<bool>, mut query: Query<&mut i32>) {
|
|
|
|
if !Res::changed(&run_on_flip) {
|
|
|
|
return;
|
2020-11-08 20:34:05 +00:00
|
|
|
}
|
2020-11-02 00:51:51 +00:00
|
|
|
|
2020-11-08 20:34:05 +00:00
|
|
|
for mut i in query.iter_mut() {
|
|
|
|
*i += 1;
|
|
|
|
}
|
2020-09-10 20:15:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
resources.insert(false);
|
|
|
|
let ent = world.spawn((0,));
|
|
|
|
|
|
|
|
let mut schedule = Schedule::default();
|
2020-12-13 02:04:42 +00:00
|
|
|
let mut update = SystemStage::parallel();
|
2020-12-16 05:57:16 +00:00
|
|
|
update.add_system(incr_e_on_flip.system());
|
2020-12-13 02:04:42 +00:00
|
|
|
schedule.add_stage("update", update);
|
2020-12-16 05:57:16 +00:00
|
|
|
schedule.add_stage(
|
|
|
|
"clear_trackers",
|
2021-02-09 20:14:10 +00:00
|
|
|
SystemStage::single(clear_trackers_system.exclusive_system()),
|
2020-12-16 05:57:16 +00:00
|
|
|
);
|
2020-09-10 20:15:02 +00:00
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
schedule.run(&mut world, &mut resources);
|
2020-09-10 20:15:02 +00:00
|
|
|
assert_eq!(*(world.get::<i32>(ent).unwrap()), 1);
|
|
|
|
|
2021-02-09 20:14:10 +00:00
|
|
|
schedule.run(&mut world, &mut resources);
|
2020-09-10 20:15:02 +00:00
|
|
|
assert_eq!(*(world.get::<i32>(ent).unwrap()), 1);
|
|
|
|
|
|
|
|
*resources.get_mut::<bool>().unwrap() = true;
|
2021-02-09 20:14:10 +00:00
|
|
|
schedule.run(&mut world, &mut resources);
|
2020-09-10 20:15:02 +00:00
|
|
|
assert_eq!(*(world.get::<i32>(ent).unwrap()), 2);
|
|
|
|
}
|
2020-10-30 06:39:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_mut_system() {
|
|
|
|
fn sys(_q1: Query<&mut A>, _q2: Query<&mut A>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
world.spawn((A,));
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
run_system(&mut world, &mut resources, sys.system());
|
2020-10-30 06:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_immut_system() {
|
|
|
|
fn sys(_q1: Query<&A>, _q2: Query<&mut A>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
world.spawn((A,));
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
run_system(&mut world, &mut resources, sys.system());
|
2020-10-30 06:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn query_set_system() {
|
|
|
|
fn sys(_set: QuerySet<(Query<&mut A>, Query<&B>)>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
world.spawn((A,));
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
run_system(&mut world, &mut resources, sys.system());
|
2020-10-30 06:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_with_query_set_system() {
|
|
|
|
fn sys(_query: Query<&mut A>, _set: QuerySet<(Query<&mut A>, Query<&B>)>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
world.spawn((A,));
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
run_system(&mut world, &mut resources, sys.system());
|
2020-10-30 06:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_sets_system() {
|
|
|
|
fn sys(_set_1: QuerySet<(Query<&mut A>,)>, _set_2: QuerySet<(Query<&mut A>, Query<&B>)>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
world.spawn((A,));
|
2020-12-16 05:57:16 +00:00
|
|
|
run_system(&mut world, &mut resources, sys.system());
|
2020-11-08 20:34:05 +00:00
|
|
|
}
|
2020-10-30 06:39:55 +00:00
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
fn run_system<S: System<In = (), Out = ()>>(
|
2020-11-17 02:18:00 +00:00
|
|
|
world: &mut World,
|
|
|
|
resources: &mut Resources,
|
2020-12-16 05:57:16 +00:00
|
|
|
system: S,
|
2020-11-17 02:18:00 +00:00
|
|
|
) {
|
2020-10-30 06:39:55 +00:00
|
|
|
let mut schedule = Schedule::default();
|
2020-12-13 02:04:42 +00:00
|
|
|
let mut update = SystemStage::parallel();
|
|
|
|
update.add_system(system);
|
|
|
|
schedule.add_stage("update", update);
|
2021-02-09 20:14:10 +00:00
|
|
|
schedule.run(world, resources);
|
2020-10-30 06:39:55 +00:00
|
|
|
}
|
2020-11-15 20:42:43 +00:00
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct BufferRes {
|
|
|
|
_buffer: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
2020-12-16 05:57:16 +00:00
|
|
|
fn test_for_conflicting_resources<S: System<In = (), Out = ()>>(sys: S) {
|
2020-11-15 20:42:43 +00:00
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
resources.insert(BufferRes::default());
|
|
|
|
resources.insert(A);
|
|
|
|
resources.insert(B);
|
2021-02-09 20:14:10 +00:00
|
|
|
run_system(&mut world, &mut resources, sys);
|
2020-11-15 20:42:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_system_resources() {
|
|
|
|
fn sys(_: ResMut<BufferRes>, _: Res<BufferRes>) {}
|
2020-12-16 05:57:16 +00:00
|
|
|
test_for_conflicting_resources(sys.system())
|
2020-11-15 20:42:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_system_resources_reverse_order() {
|
|
|
|
fn sys(_: Res<BufferRes>, _: ResMut<BufferRes>) {}
|
2020-12-16 05:57:16 +00:00
|
|
|
test_for_conflicting_resources(sys.system())
|
2020-11-15 20:42:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_system_resources_multiple_mutable() {
|
|
|
|
fn sys(_: ResMut<BufferRes>, _: ResMut<BufferRes>) {}
|
2020-12-16 05:57:16 +00:00
|
|
|
test_for_conflicting_resources(sys.system())
|
2020-11-15 20:42:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_system_local_resources() {
|
|
|
|
fn sys(_: Local<BufferRes>, _: Local<BufferRes>) {}
|
2020-12-16 05:57:16 +00:00
|
|
|
test_for_conflicting_resources(sys.system())
|
2020-11-15 20:42:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn nonconflicting_system_resources() {
|
|
|
|
fn sys(_: Local<BufferRes>, _: ResMut<BufferRes>, _: Local<A>, _: ResMut<A>) {}
|
2020-12-16 05:57:16 +00:00
|
|
|
test_for_conflicting_resources(sys.system())
|
2020-11-15 20:42:43 +00:00
|
|
|
}
|
2020-07-15 02:05:39 +00:00
|
|
|
}
|