Add World::get_resource_or_init
as an alternative to World::get_resource_or_insert_with
(#15758)
# Objective If a `Resource` implements `FromWorld` or `Default`, it's nicer to be able to write: ```rust let foo = world.get_resource_or_init::<Foo>(); ``` Rather than: ```rust let foo = world.get_resource_or_insert_with(Foo::default); ``` The latter is also not possible if a type implements `FromWorld` only, and not `Default`. ## Solution Added: ```rust impl World { pub fn get_resource_or_init<R: Resource + FromWorld>(&mut self) -> Mut<'_, R>; } ``` Turns out all current in-engine uses of `get_resource_or_insert_with` are exactly the above, so they've also been replaced. ## Testing - Added a doc-test. - Also added a doc-test for `World::get_resource_or_insert_with`.
This commit is contained in:
parent
88d9ead7f8
commit
b4071ca370
@ -314,7 +314,7 @@ impl Plugin for AssetPlugin {
|
|||||||
{
|
{
|
||||||
let mut sources = app
|
let mut sources = app
|
||||||
.world_mut()
|
.world_mut()
|
||||||
.get_resource_or_insert_with::<AssetSourceBuilders>(Default::default);
|
.get_resource_or_init::<AssetSourceBuilders>();
|
||||||
sources.init_default_source(
|
sources.init_default_source(
|
||||||
&self.file_path,
|
&self.file_path,
|
||||||
(!matches!(self.mode, AssetMode::Unprocessed))
|
(!matches!(self.mode, AssetMode::Unprocessed))
|
||||||
@ -519,7 +519,7 @@ impl AssetApp for App {
|
|||||||
{
|
{
|
||||||
let mut sources = self
|
let mut sources = self
|
||||||
.world_mut()
|
.world_mut()
|
||||||
.get_resource_or_insert_with(AssetSourceBuilders::default);
|
.get_resource_or_init::<AssetSourceBuilders>();
|
||||||
sources.insert(id, source);
|
sources.insert(id, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ impl EventRegistry {
|
|||||||
// By initializing the resource here, we can be sure that it is present,
|
// By initializing the resource here, we can be sure that it is present,
|
||||||
// and receive the correct, up-to-date `ComponentId` even if it was previously removed.
|
// and receive the correct, up-to-date `ComponentId` even if it was previously removed.
|
||||||
let component_id = world.init_resource::<Events<T>>();
|
let component_id = world.init_resource::<Events<T>>();
|
||||||
let mut registry = world.get_resource_or_insert_with(Self::default);
|
let mut registry = world.get_resource_or_init::<Self>();
|
||||||
registry.event_updates.push(RegisteredEvent {
|
registry.event_updates.push(RegisteredEvent {
|
||||||
component_id,
|
component_id,
|
||||||
previously_updated: false,
|
previously_updated: false,
|
||||||
@ -84,7 +84,7 @@ impl EventRegistry {
|
|||||||
/// Removes an event from the world and it's associated [`EventRegistry`].
|
/// Removes an event from the world and it's associated [`EventRegistry`].
|
||||||
pub fn deregister_events<T: Event>(world: &mut World) {
|
pub fn deregister_events<T: Event>(world: &mut World) {
|
||||||
let component_id = world.init_resource::<Events<T>>();
|
let component_id = world.init_resource::<Events<T>>();
|
||||||
let mut registry = world.get_resource_or_insert_with(Self::default);
|
let mut registry = world.get_resource_or_init::<Self>();
|
||||||
registry
|
registry
|
||||||
.event_updates
|
.event_updates
|
||||||
.retain(|e| e.component_id != component_id);
|
.retain(|e| e.component_id != component_id);
|
||||||
|
@ -405,7 +405,7 @@ impl Schedule {
|
|||||||
if self.graph.changed {
|
if self.graph.changed {
|
||||||
self.graph.initialize(world);
|
self.graph.initialize(world);
|
||||||
let ignored_ambiguities = world
|
let ignored_ambiguities = world
|
||||||
.get_resource_or_insert_with::<Schedules>(Schedules::default)
|
.get_resource_or_init::<Schedules>()
|
||||||
.ignored_scheduling_ambiguities
|
.ignored_scheduling_ambiguities
|
||||||
.clone();
|
.clone();
|
||||||
self.graph.update_schedule(
|
self.graph.update_schedule(
|
||||||
|
@ -2101,6 +2101,19 @@ impl World {
|
|||||||
|
|
||||||
/// Gets a mutable reference to the resource of type `T` if it exists,
|
/// Gets a mutable reference to the resource of type `T` if it exists,
|
||||||
/// otherwise inserts the resource using the result of calling `func`.
|
/// otherwise inserts the resource using the result of calling `func`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
/// #
|
||||||
|
/// #[derive(Resource)]
|
||||||
|
/// struct MyResource(i32);
|
||||||
|
///
|
||||||
|
/// # let mut world = World::new();
|
||||||
|
/// let my_res = world.get_resource_or_insert_with(|| MyResource(10));
|
||||||
|
/// assert_eq!(my_res.0, 10);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn get_resource_or_insert_with<R: Resource>(
|
pub fn get_resource_or_insert_with<R: Resource>(
|
||||||
@ -2137,6 +2150,82 @@ impl World {
|
|||||||
unsafe { data.with_type::<R>() }
|
unsafe { data.with_type::<R>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable reference to the resource of type `T` if it exists,
|
||||||
|
/// otherwise initializes the resource by calling its [`FromWorld`]
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
/// #
|
||||||
|
/// #[derive(Resource)]
|
||||||
|
/// struct Foo(i32);
|
||||||
|
///
|
||||||
|
/// impl Default for Foo {
|
||||||
|
/// fn default() -> Self {
|
||||||
|
/// Self(15)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Resource)]
|
||||||
|
/// struct MyResource(i32);
|
||||||
|
///
|
||||||
|
/// impl FromWorld for MyResource {
|
||||||
|
/// fn from_world(world: &mut World) -> Self {
|
||||||
|
/// let foo = world.get_resource_or_init::<Foo>();
|
||||||
|
/// Self(foo.0 * 2)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # let mut world = World::new();
|
||||||
|
/// let my_res = world.get_resource_or_init::<MyResource>();
|
||||||
|
/// assert_eq!(my_res.0, 30);
|
||||||
|
/// ```
|
||||||
|
#[track_caller]
|
||||||
|
pub fn get_resource_or_init<R: Resource + FromWorld>(&mut self) -> Mut<'_, R> {
|
||||||
|
#[cfg(feature = "track_change_detection")]
|
||||||
|
let caller = Location::caller();
|
||||||
|
let change_tick = self.change_tick();
|
||||||
|
let last_change_tick = self.last_change_tick();
|
||||||
|
|
||||||
|
let component_id = self.components.register_resource::<R>();
|
||||||
|
if self
|
||||||
|
.storages
|
||||||
|
.resources
|
||||||
|
.get(component_id)
|
||||||
|
.map_or(true, |data| !data.is_present())
|
||||||
|
{
|
||||||
|
let value = R::from_world(self);
|
||||||
|
OwningPtr::make(value, |ptr| {
|
||||||
|
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
||||||
|
unsafe {
|
||||||
|
self.insert_resource_by_id(
|
||||||
|
component_id,
|
||||||
|
ptr,
|
||||||
|
#[cfg(feature = "track_change_detection")]
|
||||||
|
caller,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: The resource was just initialized if it was empty.
|
||||||
|
let data = unsafe {
|
||||||
|
self.storages
|
||||||
|
.resources
|
||||||
|
.get_mut(component_id)
|
||||||
|
.debug_checked_unwrap()
|
||||||
|
};
|
||||||
|
// SAFETY: The resource must be present, as we would have inserted it if it was empty.
|
||||||
|
let data = unsafe {
|
||||||
|
data.get_mut(last_change_tick, change_tick)
|
||||||
|
.debug_checked_unwrap()
|
||||||
|
};
|
||||||
|
// SAFETY: The underlying type of the resource is `R`.
|
||||||
|
unsafe { data.with_type::<R>() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
|
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
@ -3230,7 +3319,7 @@ impl World {
|
|||||||
///
|
///
|
||||||
/// The `Schedules` resource will be initialized if it does not already exist.
|
/// The `Schedules` resource will be initialized if it does not already exist.
|
||||||
pub fn add_schedule(&mut self, schedule: Schedule) {
|
pub fn add_schedule(&mut self, schedule: Schedule) {
|
||||||
let mut schedules = self.get_resource_or_insert_with(Schedules::default);
|
let mut schedules = self.get_resource_or_init::<Schedules>();
|
||||||
schedules.insert(schedule);
|
schedules.insert(schedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,12 +241,10 @@ impl AppGizmoBuilder for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.world_mut()
|
self.world_mut()
|
||||||
.get_resource_or_insert_with::<GizmoConfigStore>(Default::default)
|
.get_resource_or_init::<GizmoConfigStore>()
|
||||||
.register::<Config>();
|
.register::<Config>();
|
||||||
|
|
||||||
let mut handles = self
|
let mut handles = self.world_mut().get_resource_or_init::<LineGizmoHandles>();
|
||||||
.world_mut()
|
|
||||||
.get_resource_or_insert_with::<LineGizmoHandles>(Default::default);
|
|
||||||
|
|
||||||
handles.list.insert(TypeId::of::<Config>(), None);
|
handles.list.insert(TypeId::of::<Config>(), None);
|
||||||
handles.strip.insert(TypeId::of::<Config>(), None);
|
handles.strip.insert(TypeId::of::<Config>(), None);
|
||||||
@ -288,7 +286,7 @@ impl AppGizmoBuilder for App {
|
|||||||
self.init_gizmo_group::<Config>();
|
self.init_gizmo_group::<Config>();
|
||||||
|
|
||||||
self.world_mut()
|
self.world_mut()
|
||||||
.get_resource_or_insert_with::<GizmoConfigStore>(Default::default)
|
.get_resource_or_init::<GizmoConfigStore>()
|
||||||
.insert(config, group);
|
.insert(config, group);
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -181,7 +181,7 @@ pub(crate) fn internal_apply_state_transition<S: States>(
|
|||||||
/// Runs automatically when using `App` to insert states, but needs to
|
/// Runs automatically when using `App` to insert states, but needs to
|
||||||
/// be added manually in other situations.
|
/// be added manually in other situations.
|
||||||
pub fn setup_state_transitions_in_world(world: &mut World) {
|
pub fn setup_state_transitions_in_world(world: &mut World) {
|
||||||
let mut schedules = world.get_resource_or_insert_with(Schedules::default);
|
let mut schedules = world.get_resource_or_init::<Schedules>();
|
||||||
if schedules.contains(StateTransition) {
|
if schedules.contains(StateTransition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user