diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 442fc60ae03a7..39f89b95ffaaf 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -110,6 +110,38 @@ use std::{ /// /// [orphan rule]: https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type /// [newtype pattern]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types +/// +/// # `!Sync` Components +/// A `!Sync` type cannot implement `Component`. However, it is possible to wrap a `Send` but not `Sync` +/// type in [`SyncCell`] or the currently unstable [`Exclusive`] to make it `Sync`. This forces only +/// having mutable access (`&mut T` only, never `&T`), but makes it safe to reference across multiple +/// threads. +/// +/// This will fail to compile since `RefCell` is `!Sync`. +/// ```compile_fail +/// # use std::cell::RefCell; +/// # use bevy_ecs::component::Component; +/// #[derive(Component)] +/// struct NotSync { +/// counter: RefCell, +/// } +/// ``` +/// +/// This will compile since the `RefCell` is wrapped with `SyncCell`. +/// ``` +/// # use std::cell::RefCell; +/// # use bevy_ecs::component::Component; +/// use bevy_utils::synccell::SyncCell; +/// +/// // This will compile. +/// #[derive(Component)] +/// struct ActuallySync { +/// counter: SyncCell>, +/// } +/// ``` +/// +/// [`SyncCell`]: bevy_utils::synccell::SyncCell +/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html pub trait Component: Send + Sync + 'static { type Storage: ComponentStorage; } diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index a10737acad773..d52961c4ad86a 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -89,6 +89,38 @@ use std::{ /// /// This will most commonly occur when working with `SystemParam`s generically, as the requirement /// has not been proven to the compiler. +/// +/// # `!Sync` Resources +/// A `!Sync` type cannot implement `Resource`. However, it is possible to wrap a `Send` but not `Sync` +/// type in [`SyncCell`] or the currently unstable [`Exclusive`] to make it `Sync`. This forces only +/// having mutable access (`&mut T` only, never `&T`), but makes it safe to reference across multiple +/// threads. +/// +/// This will fail to compile since `RefCell` is `!Sync`. +/// ```compile_fail +/// # use std::cell::RefCell; +/// # use bevy_ecs::system::Resource; +/// +/// #[derive(Resource)] +/// struct NotSync { +/// counter: RefCell, +/// } +/// ``` +/// +/// This will compile since the `RefCell` is wrapped with `SyncCell`. +/// ``` +/// # use std::cell::RefCell; +/// # use bevy_ecs::system::Resource; +/// use bevy_utils::synccell::SyncCell; +/// +/// #[derive(Resource)] +/// struct ActuallySync { +/// counter: SyncCell>, +/// } +/// ``` +/// +/// [`SyncCell`]: bevy_utils::synccell::SyncCell +/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html pub trait SystemParam: Sized { type Fetch: for<'w, 's> SystemParamFetch<'w, 's>; }