Skip to content

Commit d50be4e

Browse files
use UnsafeWorldCell for System and ParamState
1 parent 3281aea commit d50be4e

File tree

13 files changed

+129
-69
lines changed

13 files changed

+129
-69
lines changed

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream {
294294
unsafe fn get_param<'w, 's>(
295295
state: &'s mut Self::State,
296296
system_meta: &SystemMeta,
297-
world: &'w World,
297+
world: UnsafeWorldCell<'w>,
298298
change_tick: u32,
299299
) -> Self::Item<'w, 's> {
300300
ParamSet {
@@ -498,7 +498,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
498498
unsafe fn get_param<'w2, 's2>(
499499
state: &'s2 mut Self::State,
500500
system_meta: &#path::system::SystemMeta,
501-
world: &'w2 #path::world::World,
501+
world: #path::world::unsafe_world_cell::UnsafeWorldCell<'w2>,
502502
change_tick: u32,
503503
) -> Self::Item<'w2, 's2> {
504504
let (#(#tuple_patterns,)*) = <

crates/bevy_ecs/src/schedule/executor_parallel.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::sync::Arc;
22

33
use crate as bevy_ecs;
4+
use crate::world::unsafe_world_cell::UnsafeWorldCell;
45
use crate::{
56
archetype::ArchetypeComponentId,
67
query::Access,
@@ -138,7 +139,12 @@ impl ParallelSystemExecutor for ParallelExecutor {
138139
}
139140
}
140141

141-
let thread_executor = world.get_resource::<MainThreadExecutor>().map(|e| &*e.0);
142+
let thread_executor = world
143+
.get_resource::<MainThreadExecutor>()
144+
.map(|e| Arc::clone(&e.0));
145+
let thread_executor = thread_executor.as_deref();
146+
147+
let world = world.as_unsafe_world_cell();
142148

143149
ComputeTaskPool::init(TaskPool::default).scope_with_executor(
144150
false,
@@ -188,7 +194,7 @@ impl ParallelExecutor {
188194
&mut self,
189195
scope: &Scope<'_, 'scope, ()>,
190196
systems: &'scope mut [SystemContainer],
191-
world: &'scope World,
197+
world: UnsafeWorldCell<'scope>,
192198
) {
193199
// These are used as a part of a unit test.
194200
#[cfg(test)]

crates/bevy_ecs/src/schedule_v3/executor/multi_threaded.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
is_apply_system_buffers, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule,
1515
},
1616
system::BoxedSystem,
17-
world::World,
17+
world::{unsafe_world_cell::UnsafeWorldCell, World},
1818
};
1919

2020
/// A funky borrow split of [`SystemSchedule`] required by the [`MultiThreadedExecutor`].
@@ -252,6 +252,7 @@ impl MultiThreadedExecutor {
252252
// SAFETY: No exclusive system is running.
253253
// Therefore, there is no existing mutable reference to the world.
254254
let world = unsafe { &*cell.get() };
255+
255256
if !self.can_run(system_index, system, conditions, world) {
256257
// NOTE: exclusive systems with ambiguities are susceptible to
257258
// being significantly displaced here (compared to single-threaded order)
@@ -280,6 +281,9 @@ impl MultiThreadedExecutor {
280281
break;
281282
}
282283

284+
// TODO: do this earlier?
285+
let world = world.as_unsafe_world_cell_migration_internal();
286+
283287
// SAFETY: No other reference to this system exists.
284288
unsafe {
285289
self.spawn_system_task(scope, system_index, systems, world);
@@ -400,7 +404,7 @@ impl MultiThreadedExecutor {
400404
scope: &Scope<'_, 'scope, ()>,
401405
system_index: usize,
402406
systems: &'scope [SyncUnsafeCell<BoxedSystem>],
403-
world: &'scope World,
407+
world: UnsafeWorldCell<'scope>,
404408
) {
405409
// SAFETY: this system is not running, no other reference exists
406410
let system = unsafe { &mut *systems[system_index].get() };
@@ -560,6 +564,7 @@ fn apply_system_buffers(
560564
unapplied_systems.clear();
561565
}
562566

567+
// TODO: this is unsafe
563568
fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &World) -> bool {
564569
// not short-circuiting is intentional
565570
#[allow(clippy::unnecessary_fold)]
@@ -569,7 +574,7 @@ fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &World
569574
#[cfg(feature = "trace")]
570575
let _condition_span = info_span!("condition", name = &*condition.name()).entered();
571576
// SAFETY: caller ensures system access is compatible
572-
unsafe { condition.run_unsafe((), world) }
577+
unsafe { condition.run_unsafe((), world.as_unsafe_world_cell_readonly()) }
573578
})
574579
.fold(true, |acc, res| acc && res)
575580
}

crates/bevy_ecs/src/system/commands/parallel_scope.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
entity::Entities,
77
prelude::World,
88
system::{SystemMeta, SystemParam},
9+
world::unsafe_world_cell::UnsafeWorldCell,
910
};
1011

1112
use super::{CommandQueue, Commands};
@@ -70,7 +71,7 @@ unsafe impl SystemParam for ParallelCommands<'_, '_> {
7071
unsafe fn get_param<'w, 's>(
7172
state: &'s mut Self::State,
7273
_: &crate::system::SystemMeta,
73-
world: &'w World,
74+
world: UnsafeWorldCell<'w>,
7475
_: u32,
7576
) -> Self::Item<'w, 's> {
7677
ParallelCommands {

crates/bevy_ecs/src/system/exclusive_function_system.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
check_system_change_tick, AsSystemLabel, ExclusiveSystemParam, ExclusiveSystemParamItem,
99
In, InputMarker, IntoSystem, System, SystemMeta, SystemTypeIdLabel,
1010
},
11-
world::{World, WorldId},
11+
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
1212
};
1313
use bevy_ecs_macros::all_tuples;
1414
use std::{any::TypeId, borrow::Cow, marker::PhantomData};
@@ -96,7 +96,7 @@ where
9696
}
9797

9898
#[inline]
99-
unsafe fn run_unsafe(&mut self, _input: Self::In, _world: &World) -> Self::Out {
99+
unsafe fn run_unsafe(&mut self, _input: Self::In, _world: UnsafeWorldCell<'_>) -> Self::Out {
100100
panic!("Cannot run exclusive systems with a shared World reference");
101101
}
102102

crates/bevy_ecs/src/system/function_system.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
query::{Access, FilteredAccessSet},
77
schedule::{SystemLabel, SystemLabelId},
88
system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem},
9-
world::{World, WorldId},
9+
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
1010
};
1111
use bevy_ecs_macros::all_tuples;
1212
use std::{any::TypeId, borrow::Cow, fmt::Debug, marker::PhantomData};
@@ -173,7 +173,7 @@ impl<Param: SystemParam> SystemState<Param> {
173173
self.validate_world(world);
174174
self.update_archetypes(world);
175175
// SAFETY: Param is read-only and doesn't allow mutable access to World. It also matches the World this SystemState was created with.
176-
unsafe { self.get_unchecked_manual(world) }
176+
unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell_readonly()) }
177177
}
178178

179179
/// Retrieve the mutable [`SystemParam`] values.
@@ -182,7 +182,7 @@ impl<Param: SystemParam> SystemState<Param> {
182182
self.validate_world(world);
183183
self.update_archetypes(world);
184184
// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
185-
unsafe { self.get_unchecked_manual(world) }
185+
unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell()) }
186186
}
187187

188188
/// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
@@ -242,7 +242,7 @@ impl<Param: SystemParam> SystemState<Param> {
242242
self.validate_world(world);
243243
let change_tick = world.read_change_tick();
244244
// SAFETY: Param is read-only and doesn't allow mutable access to World. It also matches the World this SystemState was created with.
245-
unsafe { self.fetch(world, change_tick) }
245+
unsafe { self.fetch(world.as_unsafe_world_cell_readonly(), change_tick) }
246246
}
247247

248248
/// Retrieve the mutable [`SystemParam`] values. This will not update the state's view of the world's archetypes
@@ -260,7 +260,7 @@ impl<Param: SystemParam> SystemState<Param> {
260260
self.validate_world(world);
261261
let change_tick = world.change_tick();
262262
// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
263-
unsafe { self.fetch(world, change_tick) }
263+
unsafe { self.fetch(world.as_unsafe_world_cell(), change_tick) }
264264
}
265265

266266
/// Retrieve the [`SystemParam`] values. This will not update archetypes automatically.
@@ -272,7 +272,7 @@ impl<Param: SystemParam> SystemState<Param> {
272272
#[inline]
273273
pub unsafe fn get_unchecked_manual<'w, 's>(
274274
&'s mut self,
275-
world: &'w World,
275+
world: UnsafeWorldCell<'w>,
276276
) -> SystemParamItem<'w, 's, Param> {
277277
let change_tick = world.increment_change_tick();
278278
self.fetch(world, change_tick)
@@ -285,7 +285,7 @@ impl<Param: SystemParam> SystemState<Param> {
285285
#[inline]
286286
unsafe fn fetch<'w, 's>(
287287
&'s mut self,
288-
world: &'w World,
288+
world: UnsafeWorldCell<'w>,
289289
change_tick: u32,
290290
) -> SystemParamItem<'w, 's, Param> {
291291
let param = Param::get_param(&mut self.param_state, &self.meta, world, change_tick);
@@ -458,7 +458,7 @@ where
458458
}
459459

460460
#[inline]
461-
unsafe fn run_unsafe(&mut self, input: Self::In, world: &World) -> Self::Out {
461+
unsafe fn run_unsafe(&mut self, input: Self::In, world: UnsafeWorldCell<'_>) -> Self::Out {
462462
let change_tick = world.increment_change_tick();
463463

464464
// Safety:

crates/bevy_ecs/src/system/system.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ use bevy_utils::tracing::warn;
22
use core::fmt::Debug;
33

44
use crate::{
5-
archetype::ArchetypeComponentId, change_detection::MAX_CHANGE_AGE, component::ComponentId,
6-
query::Access, schedule::SystemLabelId, world::World,
5+
archetype::ArchetypeComponentId,
6+
change_detection::MAX_CHANGE_AGE,
7+
component::ComponentId,
8+
query::Access,
9+
schedule::SystemLabelId,
10+
world::{unsafe_world_cell::UnsafeWorldCell, World},
711
};
812

913
use std::any::TypeId;
@@ -46,17 +50,14 @@ pub trait System: Send + Sync + 'static {
4650
///
4751
/// # Safety
4852
///
49-
/// This might access world and resources in an unsafe manner. This should only be called in one
50-
/// of the following contexts:
51-
/// 1. This system is the only system running on the given world across all threads.
52-
/// 2. This system only runs in parallel with other systems that do not conflict with the
53-
/// [`System::archetype_component_access()`].
54-
unsafe fn run_unsafe(&mut self, input: Self::In, world: &World) -> Self::Out;
53+
/// This function may only be called with a [`UnsafeWorldCell`] that can be used for
54+
/// everything listed in [`System::archetype_component_access`].
55+
unsafe fn run_unsafe(&mut self, input: Self::In, world: UnsafeWorldCell<'_>) -> Self::Out;
5556
/// Runs the system with the given input in the world.
5657
fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out {
5758
self.update_archetype_component_access(world);
5859
// SAFETY: world and resources are exclusively borrowed
59-
unsafe { self.run_unsafe(input, world) }
60+
unsafe { self.run_unsafe(input, world.as_unsafe_world_cell()) }
6061
}
6162
fn apply_buffers(&mut self, world: &mut World);
6263
/// Initialize the system.

0 commit comments

Comments
 (0)