Add &World as SystemParam (#2923)

# Objective
Make it possible to use `&World` as a system parameter

## Solution
It seems like all the pieces were already in place, very simple impl


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
bilsen 2022-02-03 23:43:25 +00:00
parent c216738b33
commit 1f99363de9
4 changed files with 90 additions and 1 deletions

View File

@ -186,6 +186,10 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
self.with.union_with(&access.with); self.with.union_with(&access.with);
self.without.union_with(&access.without); self.without.union_with(&access.without);
} }
pub fn read_all(&mut self) {
self.access.read_all();
}
} }
pub struct FilteredAccessSet<T: SparseSetIndex> { pub struct FilteredAccessSet<T: SparseSetIndex> {

View File

@ -443,6 +443,35 @@ mod tests {
assert_eq!(receive_events(&world), vec![StartedSystems(2),]); assert_eq!(receive_events(&world), vec![StartedSystems(2),]);
} }
#[test]
fn world() {
let mut world = World::new();
world.spawn().insert(W(0usize));
fn wants_world(_: &World) {}
fn wants_mut(_: Query<&mut W<usize>>) {}
let mut stage = SystemStage::parallel()
.with_system(wants_mut)
.with_system(wants_mut);
stage.run(&mut world);
assert_eq!(
receive_events(&world),
vec![StartedSystems(1), StartedSystems(1),]
);
let mut stage = SystemStage::parallel()
.with_system(wants_mut)
.with_system(wants_world);
stage.run(&mut world);
assert_eq!(
receive_events(&world),
vec![StartedSystems(1), StartedSystems(1),]
);
let mut stage = SystemStage::parallel()
.with_system(wants_world)
.with_system(wants_world);
stage.run(&mut world);
assert_eq!(receive_events(&world), vec![StartedSystems(2),]);
}
#[test] #[test]
fn non_send_resource() { fn non_send_resource() {
use std::thread; use std::thread;

View File

@ -56,6 +56,7 @@
//! - [`EventWriter`](crate::event::EventWriter) //! - [`EventWriter`](crate::event::EventWriter)
//! - [`NonSend`] and `Option<NonSend>` //! - [`NonSend`] and `Option<NonSend>`
//! - [`NonSendMut`] and `Option<NonSendMut>` //! - [`NonSendMut`] and `Option<NonSendMut>`
//! - [`&World`](crate::world::World)
//! - [`RemovedComponents`] //! - [`RemovedComponents`]
//! - [`SystemChangeTick`] //! - [`SystemChangeTick`]
//! - [`Archetypes`](crate::archetype::Archetypes) (Provides Archetype metadata) //! - [`Archetypes`](crate::archetype::Archetypes) (Provides Archetype metadata)

View File

@ -6,7 +6,8 @@ use crate::{
component::{Component, ComponentId, ComponentTicks, Components}, component::{Component, ComponentId, ComponentTicks, Components},
entity::{Entities, Entity}, entity::{Entities, Entity},
query::{ query::{
FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery, Access, FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch,
WorldQuery,
}, },
system::{CommandQueue, Commands, Query, SystemMeta}, system::{CommandQueue, Commands, Query, SystemMeta},
world::{FromWorld, World}, world::{FromWorld, World},
@ -532,6 +533,60 @@ impl<'w, 's> SystemParamFetch<'w, 's> for CommandQueue {
} }
} }
/// SAFE: only reads world
unsafe impl ReadOnlySystemParamFetch for WorldState {}
/// The [`SystemParamState`] of [`&World`](crate::world::World).
pub struct WorldState;
impl<'w, 's> SystemParam for &'w World {
type Fetch = WorldState;
}
unsafe impl<'w, 's> SystemParamState for WorldState {
type Config = ();
fn init(_world: &mut World, system_meta: &mut SystemMeta, _config: Self::Config) -> Self {
let mut access = Access::default();
access.read_all();
if !system_meta
.archetype_component_access
.is_compatible(&access)
{
panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
}
system_meta.archetype_component_access.extend(&access);
let mut filtered_access = FilteredAccess::default();
filtered_access.read_all();
if !system_meta
.component_access_set
.get_conflicts(&filtered_access)
.is_empty()
{
panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
}
system_meta.component_access_set.add(filtered_access);
WorldState
}
fn default_config() -> Self::Config {}
}
impl<'w, 's> SystemParamFetch<'w, 's> for WorldState {
type Item = &'w World;
unsafe fn get_param(
_state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
world
}
}
/// A system local [`SystemParam`]. /// A system local [`SystemParam`].
/// ///
/// A local may only be accessed by the system itself and is therefore not visible to other systems. /// A local may only be accessed by the system itself and is therefore not visible to other systems.