Skip to content

Commit ba919e5

Browse files
bilsencart
andcommitted
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 <[email protected]>
1 parent af22cc1 commit ba919e5

File tree

4 files changed

+90
-1
lines changed

4 files changed

+90
-1
lines changed

crates/bevy_ecs/src/query/access.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
186186
self.with.union_with(&access.with);
187187
self.without.union_with(&access.without);
188188
}
189+
190+
pub fn read_all(&mut self) {
191+
self.access.read_all();
192+
}
189193
}
190194

191195
pub struct FilteredAccessSet<T: SparseSetIndex> {

crates/bevy_ecs/src/schedule/executor_parallel.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,35 @@ mod tests {
443443
assert_eq!(receive_events(&world), vec![StartedSystems(2),]);
444444
}
445445

446+
#[test]
447+
fn world() {
448+
let mut world = World::new();
449+
world.spawn().insert(W(0usize));
450+
fn wants_world(_: &World) {}
451+
fn wants_mut(_: Query<&mut W<usize>>) {}
452+
let mut stage = SystemStage::parallel()
453+
.with_system(wants_mut)
454+
.with_system(wants_mut);
455+
stage.run(&mut world);
456+
assert_eq!(
457+
receive_events(&world),
458+
vec![StartedSystems(1), StartedSystems(1),]
459+
);
460+
let mut stage = SystemStage::parallel()
461+
.with_system(wants_mut)
462+
.with_system(wants_world);
463+
stage.run(&mut world);
464+
assert_eq!(
465+
receive_events(&world),
466+
vec![StartedSystems(1), StartedSystems(1),]
467+
);
468+
let mut stage = SystemStage::parallel()
469+
.with_system(wants_world)
470+
.with_system(wants_world);
471+
stage.run(&mut world);
472+
assert_eq!(receive_events(&world), vec![StartedSystems(2),]);
473+
}
474+
446475
#[test]
447476
fn non_send_resource() {
448477
use std::thread;

crates/bevy_ecs/src/system/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
//! - [`EventWriter`](crate::event::EventWriter)
5757
//! - [`NonSend`] and `Option<NonSend>`
5858
//! - [`NonSendMut`] and `Option<NonSendMut>`
59+
//! - [`&World`](crate::world::World)
5960
//! - [`RemovedComponents`]
6061
//! - [`SystemChangeTick`]
6162
//! - [`Archetypes`](crate::archetype::Archetypes) (Provides Archetype metadata)

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use crate::{
66
component::{Component, ComponentId, ComponentTicks, Components},
77
entity::{Entities, Entity},
88
query::{
9-
FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery,
9+
Access, FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch,
10+
WorldQuery,
1011
},
1112
system::{CommandQueue, Commands, Query, SystemMeta},
1213
world::{FromWorld, World},
@@ -532,6 +533,60 @@ impl<'w, 's> SystemParamFetch<'w, 's> for CommandQueue {
532533
}
533534
}
534535

536+
/// SAFE: only reads world
537+
unsafe impl ReadOnlySystemParamFetch for WorldState {}
538+
539+
/// The [`SystemParamState`] of [`&World`](crate::world::World).
540+
pub struct WorldState;
541+
542+
impl<'w, 's> SystemParam for &'w World {
543+
type Fetch = WorldState;
544+
}
545+
546+
unsafe impl<'w, 's> SystemParamState for WorldState {
547+
type Config = ();
548+
549+
fn init(_world: &mut World, system_meta: &mut SystemMeta, _config: Self::Config) -> Self {
550+
let mut access = Access::default();
551+
access.read_all();
552+
if !system_meta
553+
.archetype_component_access
554+
.is_compatible(&access)
555+
{
556+
panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
557+
}
558+
system_meta.archetype_component_access.extend(&access);
559+
560+
let mut filtered_access = FilteredAccess::default();
561+
562+
filtered_access.read_all();
563+
if !system_meta
564+
.component_access_set
565+
.get_conflicts(&filtered_access)
566+
.is_empty()
567+
{
568+
panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
569+
}
570+
system_meta.component_access_set.add(filtered_access);
571+
572+
WorldState
573+
}
574+
575+
fn default_config() -> Self::Config {}
576+
}
577+
578+
impl<'w, 's> SystemParamFetch<'w, 's> for WorldState {
579+
type Item = &'w World;
580+
unsafe fn get_param(
581+
_state: &'s mut Self,
582+
_system_meta: &SystemMeta,
583+
world: &'w World,
584+
_change_tick: u32,
585+
) -> Self::Item {
586+
world
587+
}
588+
}
589+
535590
/// A system local [`SystemParam`].
536591
///
537592
/// A local may only be accessed by the system itself and is therefore not visible to other systems.

0 commit comments

Comments
 (0)