Skip to content

Commit

Permalink
Add &World as SystemParam (#2923)
Browse files Browse the repository at this point in the history
# 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>
  • Loading branch information
bilsen and cart committed Feb 3, 2022
1 parent af22cc1 commit ba919e5
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 1 deletion.
4 changes: 4 additions & 0 deletions crates/bevy_ecs/src/query/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
self.with.union_with(&access.with);
self.without.union_with(&access.without);
}

pub fn read_all(&mut self) {
self.access.read_all();
}
}

pub struct FilteredAccessSet<T: SparseSetIndex> {
Expand Down
29 changes: 29 additions & 0 deletions crates/bevy_ecs/src/schedule/executor_parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,35 @@ mod tests {
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]
fn non_send_resource() {
use std::thread;
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/src/system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
//! - [`EventWriter`](crate::event::EventWriter)
//! - [`NonSend`] and `Option<NonSend>`
//! - [`NonSendMut`] and `Option<NonSendMut>`
//! - [`&World`](crate::world::World)
//! - [`RemovedComponents`]
//! - [`SystemChangeTick`]
//! - [`Archetypes`](crate::archetype::Archetypes) (Provides Archetype metadata)
Expand Down
57 changes: 56 additions & 1 deletion crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crate::{
component::{Component, ComponentId, ComponentTicks, Components},
entity::{Entities, Entity},
query::{
FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery,
Access, FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch,
WorldQuery,
},
system::{CommandQueue, Commands, Query, SystemMeta},
world::{FromWorld, World},
Expand Down Expand Up @@ -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 local may only be accessed by the system itself and is therefore not visible to other systems.
Expand Down

0 comments on commit ba919e5

Please sign in to comment.