From bdbf626341a35582350711f87fa17dea4ec129f6 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Tue, 8 Feb 2022 23:04:19 +0000 Subject: [PATCH] Implement init_resource for `Commands` and `World` (#3079) # Objective - Fixes #3078 - Fixes #1397 ## Solution - Implement Commands::init_resource. - Also implement for World, for consistency and to simplify internal structure. - While we're here, clean up some of the docs for Command and World resource modification. --- crates/bevy_app/src/app.rs | 52 ++--- crates/bevy_ecs/src/lib.rs | 6 +- .../src/schedule/executor_parallel.rs | 2 +- crates/bevy_ecs/src/system/commands/mod.rs | 68 +++++- crates/bevy_ecs/src/system/mod.rs | 6 +- crates/bevy_ecs/src/world/mod.rs | 219 +++++++++++------- crates/bevy_log/src/lib.rs | 2 +- crates/bevy_winit/src/lib.rs | 8 +- 8 files changed, 219 insertions(+), 144 deletions(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index e514e77bcba98..734ef502abd3a 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -647,18 +647,15 @@ impl App { /// App::new() /// .insert_resource(MyCounter { counter: 0 }); /// ``` - pub fn insert_resource(&mut self, resource: T) -> &mut Self - where - T: Resource, - { + pub fn insert_resource(&mut self, resource: R) -> &mut Self { self.world.insert_resource(resource); self } /// Inserts a non-send resource to the app /// - /// You usually want to use `insert_resource`, but there are some special cases when a resource must - /// be non-send. + /// You usually want to use `insert_resource`, + /// but there are some special cases when a resource cannot be sent across threads. /// /// ## Example /// ``` @@ -671,19 +668,18 @@ impl App { /// App::new() /// .insert_non_send_resource(MyCounter { counter: 0 }); /// ``` - pub fn insert_non_send_resource(&mut self, resource: T) -> &mut Self - where - T: 'static, - { - self.world.insert_non_send(resource); + pub fn insert_non_send_resource(&mut self, resource: R) -> &mut Self { + self.world.insert_non_send_resource(resource); self } - /// Initialize a resource in the current [`App`], if it does not exist yet + /// Initialize a resource with standard starting values by adding it to the [`World`] /// /// If the resource already exists, nothing happens. /// - /// Adds a resource that implements `Default` or [`FromWorld`] trait. + /// The resource must implement the [`FromWorld`] trait. + /// If the `Default` trait is implemented, the `FromWorld` trait will use + /// the `Default::default` method to initialize the resource. /// /// ## Example /// ``` @@ -704,32 +700,18 @@ impl App { /// App::new() /// .init_resource::(); /// ``` - pub fn init_resource(&mut self) -> &mut Self - where - R: FromWorld + Send + Sync + 'static, - { - // PERF: We could avoid double hashing here, since the `from_resources` call is guaranteed - // not to modify the map. However, we would need to be borrowing resources both - // mutably and immutably, so we would need to be extremely certain this is correct - if !self.world.contains_resource::() { - let resource = R::from_world(&mut self.world); - self.insert_resource(resource); - } + pub fn init_resource(&mut self) -> &mut Self { + self.world.init_resource::(); self } - /// Initialize a non-send resource in the current [`App`], if it does not exist yet. + /// Initialize a non-send resource with standard starting values by adding it to the [`World`] /// - /// Adds a resource that implements `Default` or [`FromWorld`] trait. - pub fn init_non_send_resource(&mut self) -> &mut Self - where - R: FromWorld + 'static, - { - // See perf comment in init_resource - if self.world.get_non_send_resource::().is_none() { - let resource = R::from_world(&mut self.world); - self.world.insert_non_send(resource); - } + /// The resource must implement the [`FromWorld`] trait. + /// If the `Default` trait is implemented, the `FromWorld` trait will use + /// the `Default::default` method to initialize the resource. + pub fn init_non_send_resource(&mut self) -> &mut Self { + self.world.init_non_send_resource::(); self } diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 813935de1cec9..d48ea55929773 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -1181,8 +1181,8 @@ mod tests { #[test] fn non_send_resource() { let mut world = World::default(); - world.insert_non_send(123i32); - world.insert_non_send(456i64); + world.insert_non_send_resource(123i32); + world.insert_non_send_resource(456i64); assert_eq!(*world.get_non_send_resource::().unwrap(), 123); assert_eq!(*world.get_non_send_resource_mut::().unwrap(), 456); } @@ -1191,7 +1191,7 @@ mod tests { #[should_panic] fn non_send_resource_panic() { let mut world = World::default(); - world.insert_non_send(0i32); + world.insert_non_send_resource(0i32); std::thread::spawn(move || { let _ = world.get_non_send_resource_mut::(); }) diff --git a/crates/bevy_ecs/src/schedule/executor_parallel.rs b/crates/bevy_ecs/src/schedule/executor_parallel.rs index 99515de252bb0..c0acb5cbcfc14 100644 --- a/crates/bevy_ecs/src/schedule/executor_parallel.rs +++ b/crates/bevy_ecs/src/schedule/executor_parallel.rs @@ -476,7 +476,7 @@ mod tests { fn non_send_resource() { use std::thread; let mut world = World::new(); - world.insert_non_send(thread::current().id()); + world.insert_non_send_resource(thread::current().id()); fn non_send(thread_id: NonSend) { assert_eq!(thread::current().id(), *thread_id); } diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 608f8eeb551d3..ad237367b0fe5 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -4,7 +4,7 @@ use crate::{ bundle::Bundle, component::Component, entity::{Entities, Entity}, - world::World, + world::{FromWorld, World}, }; use bevy_utils::tracing::{error, warn}; pub use command_queue::CommandQueue; @@ -261,9 +261,45 @@ impl<'w, 's> Commands<'w, 's> { self.queue.push(InsertOrSpawnBatch { bundles_iter }); } + /// Inserts a resource with standard starting values to the [`World`]. + /// + /// If the resource already exists, nothing happens. + /// + /// The value given by the [`FromWorld::from_world`] method will be used. + /// Note that any resource with the `Default` trait automatically implements `FromWorld`, + /// and those default values will be here instead. + /// + /// See [`World::init_resource`] for more details. + /// Note that commands do not take effect immediately. + /// When possible, prefer the equivalent methods on `App` or `World`. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// # #[derive(Default)] + /// # struct Scoreboard { + /// # current_score: u32, + /// # high_score: u32, + /// # } + /// # + /// # fn system(mut commands: Commands) { + /// commands.init_resource::(); + /// # } + /// # system.system(); + /// ``` + pub fn init_resource(&mut self) { + self.queue.push(InitResource:: { + _phantom: PhantomData::::default(), + }) + } + /// Inserts a resource to the [`World`], overwriting any previous value of the same type. /// /// See [`World::insert_resource`] for more details. + /// Note that commands do not take effect immediately. + /// When possible, prefer the equivalent methods on `App` or `World`. /// /// # Example /// @@ -283,7 +319,7 @@ impl<'w, 's> Commands<'w, 's> { /// # } /// # bevy_ecs::system::assert_is_system(system); /// ``` - pub fn insert_resource(&mut self, resource: T) { + pub fn insert_resource(&mut self, resource: R) { self.queue.push(InsertResource { resource }) } @@ -306,8 +342,8 @@ impl<'w, 's> Commands<'w, 's> { /// # } /// # bevy_ecs::system::assert_is_system(system); /// ``` - pub fn remove_resource(&mut self) { - self.queue.push(RemoveResource:: { + pub fn remove_resource(&mut self) { + self.queue.push(RemoveResource:: { phantom: PhantomData, }); } @@ -713,23 +749,33 @@ where } } -pub struct InsertResource { - pub resource: T, +pub struct InitResource { + _phantom: PhantomData, } -impl Command for InsertResource { +impl Command for InitResource { + fn write(self, world: &mut World) { + world.init_resource::(); + } +} + +pub struct InsertResource { + pub resource: R, +} + +impl Command for InsertResource { fn write(self, world: &mut World) { world.insert_resource(self.resource); } } -pub struct RemoveResource { - pub phantom: PhantomData, +pub struct RemoveResource { + pub phantom: PhantomData, } -impl Command for RemoveResource { +impl Command for RemoveResource { fn write(self, world: &mut World) { - world.remove_resource::(); + world.remove_resource::(); } } diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 27b585e70f8e9..738c312c40d88 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -422,7 +422,7 @@ mod tests { world.insert_resource(false); struct NotSend1(std::rc::Rc); struct NotSend2(std::rc::Rc); - world.insert_non_send(NotSend1(std::rc::Rc::new(0))); + world.insert_non_send_resource(NotSend1(std::rc::Rc::new(0))); fn sys( op: Option>, @@ -446,8 +446,8 @@ mod tests { struct NotSend1(std::rc::Rc); struct NotSend2(std::rc::Rc); - world.insert_non_send(NotSend1(std::rc::Rc::new(1))); - world.insert_non_send(NotSend2(std::rc::Rc::new(2))); + world.insert_non_send_resource(NotSend1(std::rc::Rc::new(1))); + world.insert_non_send_resource(NotSend2(std::rc::Rc::new(2))); fn sys(_op: NonSend, mut _op2: NonSendMut, mut run: ResMut) { *run = true; diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index c39528285ebd5..d1404c9df2072 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -592,46 +592,88 @@ impl World { } } + /// Inserts a new resource with standard starting values. + /// + /// If the resource already exists, nothing happens. + /// + /// The value given by the [`FromWorld::from_world`] method will be used. + /// Note that any resource with the `Default` trait automatically implements `FromWorld`, + /// and those default values will be here instead. + #[inline] + pub fn init_resource(&mut self) { + // PERF: We could avoid double hashing here, since the `from_world` call is guaranteed + // not to modify the map. However, we would need to be borrowing resources both + // mutably and immutably, so we would need to be extremely certain this is correct + if !self.contains_resource::() { + let resource = R::from_world(self); + self.insert_resource(resource); + } + } + /// Inserts a new resource with the given `value`. + /// /// Resources are "unique" data of a given type. + /// If you insert a resource of a type that already exists, + /// you will overwrite any existing data. #[inline] - pub fn insert_resource(&mut self, value: T) { - let component_id = self.components.init_resource::(); + pub fn insert_resource(&mut self, value: R) { + let component_id = self.components.init_resource::(); // SAFE: component_id just initialized and corresponds to resource of type T unsafe { self.insert_resource_with_id(component_id, value) }; } + /// Inserts a new non-send resource with standard starting values. + /// + /// If the resource already exists, nothing happens. + /// + /// The value given by the [`FromWorld::from_world`] method will be used. + /// Note that any resource with the `Default` trait automatically implements `FromWorld`, + /// and those default values will be here instead. + #[inline] + pub fn init_non_send_resource(&mut self) { + // PERF: We could avoid double hashing here, since the `from_world` call is guaranteed + // not to modify the map. However, we would need to be borrowing resources both + // mutably and immutably, so we would need to be extremely certain this is correct + if !self.contains_resource::() { + let resource = R::from_world(self); + self.insert_non_send_resource(resource); + } + } + /// Inserts a new non-send resource with the given `value`. - /// Resources are "unique" data of a given type. + /// + /// `NonSend` resources cannot be sent across threads, + /// and do not need the `Send + Sync` bounds. + /// Systems with `NonSend` resources are always scheduled on the main thread. #[inline] - pub fn insert_non_send(&mut self, value: T) { - self.validate_non_send_access::(); - let component_id = self.components.init_non_send::(); - // SAFE: component_id just initialized and corresponds to resource of type T + pub fn insert_non_send_resource(&mut self, value: R) { + self.validate_non_send_access::(); + let component_id = self.components.init_non_send::(); + // SAFE: component_id just initialized and corresponds to resource of type R unsafe { self.insert_resource_with_id(component_id, value) }; } /// Removes the resource of a given type and returns it, if it exists. Otherwise returns [None]. - /// Resources are "unique" data of a given type. #[inline] - pub fn remove_resource(&mut self) -> Option { - // SAFE: T is Send + Sync + pub fn remove_resource(&mut self) -> Option { + // SAFE: R is Send + Sync unsafe { self.remove_resource_unchecked() } } #[inline] - pub fn remove_non_send(&mut self) -> Option { - self.validate_non_send_access::(); + pub fn remove_non_send_resource(&mut self) -> Option { + self.validate_non_send_access::(); // SAFE: we are on main thread unsafe { self.remove_resource_unchecked() } } #[inline] /// # Safety - /// make sure you're on main thread if T isn't Send + Sync + /// Only remove `NonSend` resources from the main thread + /// as they cannot be sent across theads #[allow(unused_unsafe)] - pub unsafe fn remove_resource_unchecked(&mut self) -> Option { - let component_id = self.components.get_resource_id(TypeId::of::())?; + pub unsafe fn remove_resource_unchecked(&mut self) -> Option { + let component_id = self.components.get_resource_id(TypeId::of::())?; let resource_archetype = self.archetypes.resource_mut(); let unique_components = resource_archetype.unique_components_mut(); let column = unique_components.get_mut(component_id)?; @@ -639,17 +681,17 @@ impl World { return None; } // SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of the - // ptr value / drop is called when T is dropped + // ptr value / drop is called when R is dropped let (ptr, _) = unsafe { column.swap_remove_and_forget_unchecked(0) }; - // SAFE: column is of type T - Some(unsafe { ptr.cast::().read() }) + // SAFE: column is of type R + Some(unsafe { ptr.cast::().read() }) } - /// Returns `true` if a resource of type `T` exists. Otherwise returns `false`. + /// Returns `true` if a resource of type `R` exists. Otherwise returns `false`. #[inline] - pub fn contains_resource(&self) -> bool { + pub fn contains_resource(&self) -> bool { let component_id = - if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { + if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { component_id } else { return false; @@ -658,16 +700,15 @@ impl World { } /// Gets a reference to the resource of the given type, if it exists. Otherwise returns [None] - /// Resources are "unique" data of a given type. #[inline] - pub fn get_resource(&self) -> Option<&T> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + pub fn get_resource(&self) -> Option<&R> { + let component_id = self.components.get_resource_id(TypeId::of::())?; unsafe { self.get_resource_with_id(component_id) } } - pub fn is_resource_added(&self) -> bool { + pub fn is_resource_added(&self) -> bool { let component_id = - if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { + if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { component_id } else { return false; @@ -682,9 +723,9 @@ impl World { ticks.is_added(self.last_change_tick(), self.read_change_tick()) } - pub fn is_resource_changed(&self) -> bool { + pub fn is_resource_changed(&self) -> bool { let component_id = - if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { + if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { component_id } else { return false; @@ -700,65 +741,64 @@ impl World { } /// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns - /// [None] Resources are "unique" data of a given type. #[inline] - pub fn get_resource_mut(&mut self) -> Option> { + pub fn get_resource_mut(&mut self) -> Option> { // SAFE: unique world access unsafe { self.get_resource_unchecked_mut() } } // PERF: optimize this to avoid redundant lookups - /// Gets a resource of type `T` if it exists, otherwise inserts the resource using the result of - /// calling `func`. + /// Gets a resource of type `T` if it exists, + /// otherwise inserts the resource using the result of calling `func`. #[inline] - pub fn get_resource_or_insert_with( + pub fn get_resource_or_insert_with( &mut self, - func: impl FnOnce() -> T, - ) -> Mut<'_, T> { - if !self.contains_resource::() { + func: impl FnOnce() -> R, + ) -> Mut<'_, R> { + if !self.contains_resource::() { self.insert_resource(func()); } self.get_resource_mut().unwrap() } - /// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns - /// [None] Resources are "unique" data of a given type. + /// Gets a mutable reference to the resource of the given type, if it exists + /// Otherwise returns [None] /// /// # Safety /// This will allow aliased mutable access to the given resource type. The caller must ensure /// that only one mutable access exists at a time. #[inline] - pub unsafe fn get_resource_unchecked_mut(&self) -> Option> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + pub unsafe fn get_resource_unchecked_mut(&self) -> Option> { + let component_id = self.components.get_resource_id(TypeId::of::())?; self.get_resource_unchecked_mut_with_id(component_id) } - /// Gets a reference to the non-send resource of the given type, if it exists. Otherwise returns - /// [None] Resources are "unique" data of a given type. + /// Gets a reference to the non-send resource of the given type, if it exists. + /// Otherwise returns [None] #[inline] - pub fn get_non_send_resource(&self) -> Option<&T> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + pub fn get_non_send_resource(&self) -> Option<&R> { + let component_id = self.components.get_resource_id(TypeId::of::())?; // SAFE: component id matches type T unsafe { self.get_non_send_with_id(component_id) } } - /// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise - /// returns [None] Resources are "unique" data of a given type. + /// Gets a mutable reference to the non-send resource of the given type, if it exists. + /// Otherwise returns [None] #[inline] - pub fn get_non_send_resource_mut(&mut self) -> Option> { + pub fn get_non_send_resource_mut(&mut self) -> Option> { // SAFE: unique world access unsafe { self.get_non_send_resource_unchecked_mut() } } - /// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise - /// returns [None] Resources are "unique" data of a given type. + /// Gets a mutable reference to the non-send resource of the given type, if it exists. + /// Otherwise returns [None] /// /// # Safety /// This will allow aliased mutable access to the given non-send resource type. The caller must /// ensure that only one mutable access exists at a time. #[inline] - pub unsafe fn get_non_send_resource_unchecked_mut(&self) -> Option> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + pub unsafe fn get_non_send_resource_unchecked_mut(&self) -> Option> { + let component_id = self.components.get_resource_id(TypeId::of::())?; self.get_non_send_unchecked_mut_with_id(component_id) } @@ -908,27 +948,27 @@ impl World { /// }); /// assert_eq!(world.get_resource::().unwrap().0, 2); /// ``` - pub fn resource_scope(&mut self, f: impl FnOnce(&mut World, Mut) -> U) -> U { + pub fn resource_scope(&mut self, f: impl FnOnce(&mut World, Mut) -> U) -> U { let component_id = self .components - .get_resource_id(TypeId::of::()) - .unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::())); + .get_resource_id(TypeId::of::()) + .unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::())); let (ptr, mut ticks) = { let resource_archetype = self.archetypes.resource_mut(); let unique_components = resource_archetype.unique_components_mut(); let column = unique_components.get_mut(component_id).unwrap_or_else(|| { - panic!("resource does not exist: {}", std::any::type_name::()) + panic!("resource does not exist: {}", std::any::type_name::()) }); if column.is_empty() { - panic!("resource does not exist: {}", std::any::type_name::()); + panic!("resource does not exist: {}", std::any::type_name::()); } // SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of - // the ptr value / drop is called when T is dropped + // the ptr value / drop is called when R is dropped unsafe { column.swap_remove_and_forget_unchecked(0) } }; // SAFE: pointer is of type T and valid to move out of // Read the value onto the stack to avoid potential mut aliasing. - let mut value = unsafe { std::ptr::read(ptr.cast::()) }; + let mut value = unsafe { std::ptr::read(ptr.cast::()) }; let value_mut = Mut { value: &mut value, ticks: Ticks { @@ -938,12 +978,12 @@ impl World { }, }; let result = f(self, value_mut); - assert!(!self.contains_resource::()); + assert!(!self.contains_resource::()); let resource_archetype = self.archetypes.resource_mut(); let unique_components = resource_archetype.unique_components_mut(); let column = unique_components .get_mut(component_id) - .unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::())); + .unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::())); // Wrap the value in MaybeUninit to prepare for passing the value back into the ECS let mut nodrop_wrapped_value = std::mem::MaybeUninit::new(value); @@ -955,27 +995,27 @@ impl World { } /// # Safety - /// `component_id` must be assigned to a component of type T + /// `component_id` must be assigned to a component of type `R` #[inline] - pub(crate) unsafe fn get_resource_with_id( + pub(crate) unsafe fn get_resource_with_id( &self, component_id: ComponentId, - ) -> Option<&T> { + ) -> Option<&R> { let column = self.get_populated_resource_column(component_id)?; - Some(&*column.get_data_ptr().as_ptr().cast::()) + Some(&*column.get_data_ptr().as_ptr().cast::()) } /// # Safety - /// `component_id` must be assigned to a component of type T. + /// `component_id` must be assigned to a component of type `R` /// Caller must ensure this doesn't violate Rust mutability rules for the given resource. #[inline] - pub(crate) unsafe fn get_resource_unchecked_mut_with_id( + pub(crate) unsafe fn get_resource_unchecked_mut_with_id( &self, component_id: ComponentId, - ) -> Option> { + ) -> Option> { let column = self.get_populated_resource_column(component_id)?; Some(Mut { - value: &mut *column.get_data_ptr().cast::().as_ptr(), + value: &mut *column.get_data_ptr().cast::().as_ptr(), ticks: Ticks { component_ticks: &mut *column.get_ticks_mut_ptr_unchecked(0), last_change_tick: self.last_change_tick(), @@ -985,48 +1025,48 @@ impl World { } /// # Safety - /// `component_id` must be assigned to a component of type T + /// `component_id` must be assigned to a component of type `R` #[inline] - pub(crate) unsafe fn get_non_send_with_id( + pub(crate) unsafe fn get_non_send_with_id( &self, component_id: ComponentId, - ) -> Option<&T> { - self.validate_non_send_access::(); + ) -> Option<&R> { + self.validate_non_send_access::(); self.get_resource_with_id(component_id) } /// # Safety - /// `component_id` must be assigned to a component of type T. + /// `component_id` must be assigned to a component of type `R`. /// Caller must ensure this doesn't violate Rust mutability rules for the given resource. #[inline] - pub(crate) unsafe fn get_non_send_unchecked_mut_with_id( + pub(crate) unsafe fn get_non_send_unchecked_mut_with_id( &self, component_id: ComponentId, - ) -> Option> { - self.validate_non_send_access::(); + ) -> Option> { + self.validate_non_send_access::(); self.get_resource_unchecked_mut_with_id(component_id) } /// # Safety - /// `component_id` must be valid and correspond to a resource component of type T + /// `component_id` must be valid and correspond to a resource component of type `R` #[inline] - unsafe fn insert_resource_with_id(&mut self, component_id: ComponentId, value: T) { + unsafe fn insert_resource_with_id(&mut self, component_id: ComponentId, value: R) { let change_tick = self.change_tick(); let column = self.initialize_resource_internal(component_id); if column.is_empty() { let mut value = ManuallyDrop::new(value); - // SAFE: column is of type T and has been allocated above - let data = (&mut *value as *mut T).cast::(); + // SAFE: column is of type R and has been allocated above + let data = (&mut *value as *mut R).cast::(); column.push(data, ComponentTicks::new(change_tick)); } else { - // SAFE: column is of type T and has already been allocated - *column.get_data_unchecked(0).cast::() = value; + // SAFE: column is of type R and has already been allocated + *column.get_data_unchecked(0).cast::() = value; column.get_ticks_unchecked_mut(0).set_changed(change_tick); } } /// # Safety - /// `component_id` must be valid and correspond to a resource component of type T + /// `component_id` must be valid and correspond to a resource component of type `R` #[inline] unsafe fn initialize_resource_internal(&mut self, component_id: ComponentId) -> &mut Column { // SAFE: resource archetype always exists @@ -1055,15 +1095,15 @@ impl World { }) } - pub(crate) fn initialize_resource(&mut self) -> ComponentId { - let component_id = self.components.init_resource::(); + pub(crate) fn initialize_resource(&mut self) -> ComponentId { + let component_id = self.components.init_resource::(); // SAFE: resource initialized above unsafe { self.initialize_resource_internal(component_id) }; component_id } - pub(crate) fn initialize_non_send_resource(&mut self) -> ComponentId { - let component_id = self.components.init_non_send::(); + pub(crate) fn initialize_non_send_resource(&mut self) -> ComponentId { + let component_id = self.components.init_non_send::(); // SAFE: resource initialized above unsafe { self.initialize_resource_internal(component_id) }; component_id @@ -1171,7 +1211,10 @@ impl fmt::Debug for World { unsafe impl Send for World {} unsafe impl Sync for World {} -/// Creates `Self` using data from the given [World] +/// Creates an instance of the type this trait is implemented for +/// using data from the supplied [World]. +/// +/// This can be helpful for complex initialization or context-aware defaults. pub trait FromWorld { /// Creates `Self` using data from the given [World] fn from_world(world: &mut World) -> Self; diff --git a/crates/bevy_log/src/lib.rs b/crates/bevy_log/src/lib.rs index c9e04cafde31f..8318880970788 100644 --- a/crates/bevy_log/src/lib.rs +++ b/crates/bevy_log/src/lib.rs @@ -133,7 +133,7 @@ impl Plugin for LogPlugin { } })) .build(); - app.world.insert_non_send(guard); + app.world.insert_non_send_resource(guard); chrome_layer }; diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index f11caebfd9495..9ff666d37639b 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -223,10 +223,14 @@ pub fn winit_runner(app: App) { // } pub fn winit_runner_with(mut app: App) { - let mut event_loop = app.world.remove_non_send::>().unwrap(); + let mut event_loop = app + .world + .remove_non_send_resource::>() + .unwrap(); let mut create_window_event_reader = ManualEventReader::::default(); let mut app_exit_event_reader = ManualEventReader::::default(); - app.world.insert_non_send(event_loop.create_proxy()); + app.world + .insert_non_send_resource(event_loop.create_proxy()); trace!("Entering winit event loop");