Skip to content

Commit 9e85c1c

Browse files
committed
bevy_ecs changes
1 parent 1b3e0b5 commit 9e85c1c

20 files changed

+656
-1024
lines changed

crates/bevy_ecs/macros/src/component.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ pub fn derive_resource(input: TokenStream) -> TokenStream {
3939
})
4040
}
4141

42+
pub fn derive_thread_local_resource(input: TokenStream) -> TokenStream {
43+
let mut ast = parse_macro_input!(input as DeriveInput);
44+
let bevy_ecs_path: Path = crate::bevy_ecs_path();
45+
46+
ast.generics
47+
.make_where_clause()
48+
.predicates
49+
.push(parse_quote! { Self: 'static });
50+
51+
let struct_name = &ast.ident;
52+
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
53+
54+
TokenStream::from(quote! {
55+
impl #impl_generics #bevy_ecs_path::storage::ThreadLocalResource for #struct_name #type_generics #where_clause {
56+
}
57+
})
58+
}
59+
4260
pub fn derive_component(input: TokenStream) -> TokenStream {
4361
let mut ast = parse_macro_input!(input as DeriveInput);
4462
let bevy_ecs_path: Path = crate::bevy_ecs_path();

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,21 +460,31 @@ pub(crate) fn bevy_ecs_path() -> syn::Path {
460460
}
461461

462462
#[proc_macro_derive(Event)]
463+
/// Derive macro generating an impl of the trait `Event`.
463464
pub fn derive_event(input: TokenStream) -> TokenStream {
464465
component::derive_event(input)
465466
}
466467

467468
#[proc_macro_derive(Resource)]
469+
/// Derive macro generating an impl of the trait `Resource`.
468470
pub fn derive_resource(input: TokenStream) -> TokenStream {
469471
component::derive_resource(input)
470472
}
471473

474+
#[proc_macro_derive(ThreadLocalResource)]
475+
/// Derive macro generating an impl of the trait `ThreadLocalResource`.
476+
pub fn derive_thread_local_resource(input: TokenStream) -> TokenStream {
477+
component::derive_thread_local_resource(input)
478+
}
479+
472480
#[proc_macro_derive(Component, attributes(component))]
481+
/// Derive macro generating an impl of the trait `Component`.
473482
pub fn derive_component(input: TokenStream) -> TokenStream {
474483
component::derive_component(input)
475484
}
476485

477486
#[proc_macro_derive(States)]
487+
/// Derive macro generating an impl of the trait `States`.
478488
pub fn derive_states(input: TokenStream) -> TokenStream {
479489
states::derive_states(input)
480490
}

crates/bevy_ecs/src/change_detection.rs

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -579,39 +579,6 @@ impl<'a, T: Resource> From<ResMut<'a, T>> for Mut<'a, T> {
579579
}
580580
}
581581

582-
/// Unique borrow of a non-[`Send`] resource.
583-
///
584-
/// Only [`Send`] resources may be accessed with the [`ResMut`] [`SystemParam`](crate::system::SystemParam). In case that the
585-
/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct
586-
/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
587-
/// over to another thread.
588-
///
589-
/// # Panics
590-
///
591-
/// Panics when used as a `SystemParameter` if the resource does not exist.
592-
///
593-
/// Use `Option<NonSendMut<T>>` instead if the resource might not always exist.
594-
pub struct NonSendMut<'a, T: ?Sized + 'static> {
595-
pub(crate) value: &'a mut T,
596-
pub(crate) ticks: TicksMut<'a>,
597-
}
598-
599-
change_detection_impl!(NonSendMut<'a, T>, T,);
600-
change_detection_mut_impl!(NonSendMut<'a, T>, T,);
601-
impl_methods!(NonSendMut<'a, T>, T,);
602-
impl_debug!(NonSendMut<'a, T>,);
603-
604-
impl<'a, T: 'static> From<NonSendMut<'a, T>> for Mut<'a, T> {
605-
/// Convert this `NonSendMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
606-
/// while losing the specificity of `NonSendMut`.
607-
fn from(other: NonSendMut<'a, T>) -> Mut<'a, T> {
608-
Mut {
609-
value: other.value,
610-
ticks: other.ticks,
611-
}
612-
}
613-
}
614-
615582
/// Shared borrow of an entity's component with access to change detection.
616583
/// Similar to [`Mut`] but is immutable and so doesn't require unique access.
617584
pub struct Ref<'a, T: ?Sized> {
@@ -910,9 +877,7 @@ mod tests {
910877

911878
use crate::{
912879
self as bevy_ecs,
913-
change_detection::{
914-
Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE,
915-
},
880+
change_detection::{Mut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE},
916881
component::{Component, ComponentTicks, Tick},
917882
system::{IntoSystem, Query, System},
918883
world::World,
@@ -1056,31 +1021,6 @@ mod tests {
10561021
assert!(val.is_changed());
10571022
}
10581023

1059-
#[test]
1060-
fn mut_from_non_send_mut() {
1061-
let mut component_ticks = ComponentTicks {
1062-
added: Tick::new(1),
1063-
changed: Tick::new(2),
1064-
};
1065-
let ticks = TicksMut {
1066-
added: &mut component_ticks.added,
1067-
changed: &mut component_ticks.changed,
1068-
last_run: Tick::new(3),
1069-
this_run: Tick::new(4),
1070-
};
1071-
let mut res = R {};
1072-
let non_send_mut = NonSendMut {
1073-
value: &mut res,
1074-
ticks,
1075-
};
1076-
1077-
let into_mut: Mut<R> = non_send_mut.into();
1078-
assert_eq!(1, into_mut.ticks.added.get());
1079-
assert_eq!(2, into_mut.ticks.changed.get());
1080-
assert_eq!(3, into_mut.ticks.last_run.get());
1081-
assert_eq!(4, into_mut.ticks.this_run.get());
1082-
}
1083-
10841024
#[test]
10851025
fn map_mut() {
10861026
use super::*;

crates/bevy_ecs/src/component.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Types for declaring and storing [`Component`]s.
22
3+
use crate::storage::ThreadLocalResource;
34
use crate::{
45
self as bevy_ecs,
56
change_detection::MAX_CHANGE_AGE,
@@ -634,11 +635,11 @@ impl Components {
634635
}
635636
}
636637

637-
/// Initializes a [non-send resource](crate::system::NonSend) of type `T` with this instance.
638+
/// Initializes a [`ThreadLocalResource`] of type `T` with this instance.
638639
/// If a resource of this type has already been initialized, this will return
639640
/// the ID of the pre-existing resource.
640641
#[inline]
641-
pub fn init_non_send<T: Any>(&mut self) -> ComponentId {
642+
pub fn init_non_send<T: ThreadLocalResource>(&mut self) -> ComponentId {
642643
// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]
643644
unsafe {
644645
self.get_or_insert_resource_with(TypeId::of::<T>(), || {
@@ -759,6 +760,7 @@ impl<'a> TickCells<'a> {
759760
/// # Safety
760761
/// All cells contained within must uphold the safety invariants of [`UnsafeCellDeref::read`].
761762
#[inline]
763+
#[allow(dead_code)]
762764
pub(crate) unsafe fn read(&self) -> ComponentTicks {
763765
ComponentTicks {
764766
added: self.added.read(),

crates/bevy_ecs/src/lib.rs

Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ pub mod prelude {
4848
IntoSystemConfigs, IntoSystemSet, IntoSystemSetConfigs, NextState, OnEnter, OnExit,
4949
OnTransition, Schedule, Schedules, State, States, SystemSet,
5050
},
51+
storage::{ThreadLocal, ThreadLocalResource, ThreadLocals},
5152
system::{
52-
Commands, Deferred, In, IntoSystem, Local, NonSend, NonSendMut, ParallelCommands,
53-
ParamSet, Query, ReadOnlySystem, Res, ResMut, Resource, System, SystemParamFunction,
53+
Commands, Deferred, In, IntoSystem, Local, ParallelCommands, ParamSet, Query,
54+
ReadOnlySystem, Res, ResMut, Resource, System, SystemParamFunction,
5455
},
5556
world::{EntityMut, EntityRef, EntityWorldMut, FromWorld, World},
5657
};
@@ -77,7 +78,6 @@ mod tests {
7778
use bevy_tasks::{ComputeTaskPool, TaskPool};
7879
use std::{
7980
any::TypeId,
80-
marker::PhantomData,
8181
sync::{
8282
atomic::{AtomicUsize, Ordering},
8383
Arc, Mutex,
@@ -91,9 +91,6 @@ mod tests {
9191
#[derive(Component, Debug, PartialEq, Eq, Clone, Copy)]
9292
struct C;
9393

94-
#[derive(Default)]
95-
struct NonSendA(usize, PhantomData<*mut ()>);
96-
9794
#[derive(Component, Clone, Debug)]
9895
struct DropCk(Arc<AtomicUsize>);
9996
impl DropCk {
@@ -1269,36 +1266,6 @@ mod tests {
12691266
);
12701267
}
12711268

1272-
#[test]
1273-
fn non_send_resource() {
1274-
let mut world = World::default();
1275-
world.insert_non_send_resource(123i32);
1276-
world.insert_non_send_resource(456i64);
1277-
assert_eq!(*world.non_send_resource::<i32>(), 123);
1278-
assert_eq!(*world.non_send_resource_mut::<i64>(), 456);
1279-
}
1280-
1281-
#[test]
1282-
fn non_send_resource_points_to_distinct_data() {
1283-
let mut world = World::default();
1284-
world.insert_resource(A(123));
1285-
world.insert_non_send_resource(A(456));
1286-
assert_eq!(*world.resource::<A>(), A(123));
1287-
assert_eq!(*world.non_send_resource::<A>(), A(456));
1288-
}
1289-
1290-
#[test]
1291-
#[should_panic]
1292-
fn non_send_resource_panic() {
1293-
let mut world = World::default();
1294-
world.insert_non_send_resource(0i32);
1295-
std::thread::spawn(move || {
1296-
let _ = world.non_send_resource_mut::<i32>();
1297-
})
1298-
.join()
1299-
.unwrap();
1300-
}
1301-
13021269
#[test]
13031270
fn exact_size_query() {
13041271
let mut world = World::default();
@@ -1416,32 +1383,6 @@ mod tests {
14161383
assert_eq!(world.resource::<A>().0, 1);
14171384
}
14181385

1419-
#[test]
1420-
#[should_panic(
1421-
expected = "Attempted to access or drop non-send resource bevy_ecs::tests::NonSendA from thread"
1422-
)]
1423-
fn non_send_resource_drop_from_different_thread() {
1424-
let mut world = World::default();
1425-
world.insert_non_send_resource(NonSendA::default());
1426-
1427-
let thread = std::thread::spawn(move || {
1428-
// Dropping the non-send resource on a different thread
1429-
// Should result in a panic
1430-
drop(world);
1431-
});
1432-
1433-
if let Err(err) = thread.join() {
1434-
std::panic::resume_unwind(err);
1435-
}
1436-
}
1437-
1438-
#[test]
1439-
fn non_send_resource_drop_from_same_thread() {
1440-
let mut world = World::default();
1441-
world.insert_non_send_resource(NonSendA::default());
1442-
drop(world);
1443-
}
1444-
14451386
#[test]
14461387
fn insert_overwrite_drop() {
14471388
let (dropck1, dropped1) = DropCk::new_pair();

crates/bevy_ecs/src/schedule/config.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,11 @@ use crate::{
66
graph_utils::{Ambiguity, Dependency, DependencyKind, GraphInfo},
77
set::{BoxedSystemSet, IntoSystemSet, SystemSet},
88
},
9-
system::{BoxedSystem, IntoSystem, System},
9+
system::{BoxedSystem, IntoSystem},
1010
};
1111

1212
fn new_condition<M>(condition: impl Condition<M>) -> BoxedCondition {
1313
let condition_system = IntoSystem::into_system(condition);
14-
assert!(
15-
condition_system.is_send(),
16-
"Condition `{}` accesses `NonSend` resources. This is not currently supported.",
17-
condition_system.name()
18-
);
19-
2014
Box::new(condition_system)
2115
}
2216

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

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{
22
any::Any,
3+
panic::AssertUnwindSafe,
34
sync::{Arc, Mutex},
45
};
56

@@ -8,7 +9,6 @@ use bevy_utils::default;
89
use bevy_utils::syncunsafecell::SyncUnsafeCell;
910
#[cfg(feature = "trace")]
1011
use bevy_utils::tracing::{info_span, Instrument, Span};
11-
use std::panic::AssertUnwindSafe;
1212

1313
use async_channel::{Receiver, Sender};
1414
use fixedbitset::FixedBitSet;
@@ -58,8 +58,6 @@ struct SystemTaskMetadata {
5858
archetype_component_access: Access<ArchetypeComponentId>,
5959
/// Indices of the systems that directly depend on the system.
6060
dependents: Vec<usize>,
61-
/// Is `true` if the system does not access `!Send` data.
62-
is_send: bool,
6361
/// Is `true` if the system is exclusive.
6462
is_exclusive: bool,
6563
/// Cached tracing span for system task
@@ -83,8 +81,6 @@ pub struct MultiThreadedExecutor {
8381
system_task_metadata: Vec<SystemTaskMetadata>,
8482
/// Union of the accesses of all currently running systems.
8583
active_access: Access<ArchetypeComponentId>,
86-
/// Returns `true` if a system with non-`Send` access is running.
87-
local_thread_running: bool,
8884
/// Returns `true` if an exclusive system is running.
8985
exclusive_running: bool,
9086
/// The number of systems expected to run.
@@ -154,7 +150,6 @@ impl SystemExecutor for MultiThreadedExecutor {
154150
self.system_task_metadata.push(SystemTaskMetadata {
155151
archetype_component_access: default(),
156152
dependents: schedule.system_dependents[index].clone(),
157-
is_send: schedule.systems[index].is_send(),
158153
is_exclusive: schedule.systems[index].is_exclusive(),
159154
#[cfg(feature = "trace")]
160155
system_task_span: info_span!(
@@ -278,7 +273,6 @@ impl MultiThreadedExecutor {
278273
num_completed_systems: 0,
279274
num_dependencies_remaining: Vec::new(),
280275
active_access: default(),
281-
local_thread_running: false,
282276
exclusive_running: false,
283277
evaluated_sets: FixedBitSet::new(),
284278
ready_systems: FixedBitSet::new(),
@@ -378,10 +372,6 @@ impl MultiThreadedExecutor {
378372
return false;
379373
}
380374

381-
if !system_meta.is_send && self.local_thread_running {
382-
return false;
383-
}
384-
385375
// TODO: an earlier out if world's archetypes did not change
386376
for set_idx in conditions.sets_with_conditions_of_systems[system_index]
387377
.difference(&self.evaluated_sets)
@@ -532,12 +522,7 @@ impl MultiThreadedExecutor {
532522
self.active_access
533523
.extend(&system_meta.archetype_component_access);
534524

535-
if system_meta.is_send {
536-
scope.spawn(task);
537-
} else {
538-
self.local_thread_running = true;
539-
scope.spawn_on_external(task);
540-
}
525+
scope.spawn(task);
541526
}
542527

543528
/// # Safety
@@ -580,7 +565,7 @@ impl MultiThreadedExecutor {
580565
.system_task_span
581566
.clone(),
582567
);
583-
scope.spawn_on_scope(task);
568+
scope.spawn(task);
584569
} else {
585570
let task = async move {
586571
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
@@ -610,11 +595,10 @@ impl MultiThreadedExecutor {
610595
.system_task_span
611596
.clone(),
612597
);
613-
scope.spawn_on_scope(task);
598+
scope.spawn(task);
614599
}
615600

616601
self.exclusive_running = true;
617-
self.local_thread_running = true;
618602
}
619603

620604
fn finish_system_and_handle_dependents(&mut self, result: SystemResult) {
@@ -627,10 +611,6 @@ impl MultiThreadedExecutor {
627611
self.exclusive_running = false;
628612
}
629613

630-
if !self.system_task_metadata[system_index].is_send {
631-
self.local_thread_running = false;
632-
}
633-
634614
debug_assert!(self.num_running_systems >= 1);
635615
self.num_running_systems -= 1;
636616
self.num_completed_systems += 1;

0 commit comments

Comments
 (0)