Skip to content

Commit aee2ccd

Browse files
Pietrek14james7132
authored andcommitted
Allow access to non-send resource through World::resource_scope (bevyengine#6113)
# Objective Relaxes the trait bound for `World::resource_scope` to allow non-send resources. Fixes bevyengine#6037. ## Solution No big changes in code had to be made. Added a check so that the non-send resources won't be accessed from a different thread. --- ## Changelog - `World::resource_scope` accepts non-send resources now - `World::resource_scope` verifies non-send access if the resource is non-send - Two new tests are added, one for valid use of `World::resource_scope` with a non-send resource, and one for invalid use (calling it from a different thread, resulting in panic) Co-authored-by: Dawid Piotrowski <41804418+Pietrek14@users.noreply.github.com>
1 parent d6d07a6 commit aee2ccd

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

crates/bevy_ecs/src/lib.rs

+36
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ mod tests {
6565
use bevy_tasks::{ComputeTaskPool, TaskPool};
6666
use std::{
6767
any::TypeId,
68+
marker::PhantomData,
6869
sync::{
6970
atomic::{AtomicUsize, Ordering},
7071
Arc, Mutex,
@@ -78,6 +79,9 @@ mod tests {
7879
#[derive(Component, Debug, PartialEq, Eq, Clone, Copy)]
7980
struct C;
8081

82+
#[derive(Default)]
83+
struct NonSendA(usize, PhantomData<*mut ()>);
84+
8185
#[derive(Component, Clone, Debug)]
8286
struct DropCk(Arc<AtomicUsize>);
8387
impl DropCk {
@@ -1262,6 +1266,38 @@ mod tests {
12621266
assert_eq!(world.resource::<A>().0, 1);
12631267
}
12641268

1269+
#[test]
1270+
fn non_send_resource_scope() {
1271+
let mut world = World::default();
1272+
world.insert_non_send_resource(NonSendA::default());
1273+
world.resource_scope(|world: &mut World, mut value: Mut<NonSendA>| {
1274+
value.0 += 1;
1275+
assert!(!world.contains_resource::<NonSendA>());
1276+
});
1277+
assert_eq!(world.non_send_resource::<NonSendA>().0, 1);
1278+
}
1279+
1280+
#[test]
1281+
#[should_panic(
1282+
expected = "attempted to access NonSend resource bevy_ecs::tests::NonSendA off of the main thread"
1283+
)]
1284+
fn non_send_resource_scope_from_different_thread() {
1285+
let mut world = World::default();
1286+
world.insert_non_send_resource(NonSendA::default());
1287+
1288+
let thread = std::thread::spawn(move || {
1289+
// Accessing the non-send resource on a different thread
1290+
// Should result in a panic
1291+
world.resource_scope(|_: &mut World, mut value: Mut<NonSendA>| {
1292+
value.0 += 1;
1293+
});
1294+
});
1295+
1296+
if let Err(err) = thread.join() {
1297+
std::panic::resume_unwind(err);
1298+
}
1299+
}
1300+
12651301
#[test]
12661302
fn insert_overwrite_drop() {
12671303
let (dropck1, dropped1) = DropCk::new_pair();

crates/bevy_ecs/src/world/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1149,14 +1149,27 @@ impl World {
11491149
/// });
11501150
/// assert_eq!(world.get_resource::<A>().unwrap().0, 2);
11511151
/// ```
1152-
pub fn resource_scope<R: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<R>) -> U) -> U {
1152+
pub fn resource_scope<
1153+
R: 'static, /* The resource doesn't need to be Send nor Sync. */
1154+
U,
1155+
>(
1156+
&mut self,
1157+
f: impl FnOnce(&mut World, Mut<R>) -> U,
1158+
) -> U {
11531159
let last_change_tick = self.last_change_tick();
11541160
let change_tick = self.change_tick();
11551161

11561162
let component_id = self
11571163
.components
11581164
.get_resource_id(TypeId::of::<R>())
11591165
.unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::<R>()));
1166+
1167+
// If the resource isn't send and sync, validate that we are on the main thread, so that we can access it.
1168+
let component_info = self.components().get_info(component_id).unwrap();
1169+
if !component_info.is_send_and_sync() {
1170+
self.validate_non_send_access::<R>();
1171+
}
1172+
11601173
let (ptr, mut ticks) = {
11611174
let resource_archetype = self.archetypes.resource_mut();
11621175
let unique_components = resource_archetype.unique_components_mut();

0 commit comments

Comments
 (0)