mirror of
https://github.com/bevyengine/bevy
synced 2024-11-14 00:47:32 +00:00
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
6 changed files with 99 additions and 12 deletions
|
@ -314,7 +314,7 @@ impl Plugin for AssetPlugin {
|
|||
{
|
||||
let mut sources = app
|
||||
.world_mut()
|
||||
.get_resource_or_insert_with::<AssetSourceBuilders>(Default::default);
|
||||
.get_resource_or_init::<AssetSourceBuilders>();
|
||||
sources.init_default_source(
|
||||
&self.file_path,
|
||||
(!matches!(self.mode, AssetMode::Unprocessed))
|
||||
|
@ -519,7 +519,7 @@ impl AssetApp for App {
|
|||
{
|
||||
let mut sources = self
|
||||
.world_mut()
|
||||
.get_resource_or_insert_with(AssetSourceBuilders::default);
|
||||
.get_resource_or_init::<AssetSourceBuilders>();
|
||||
sources.insert(id, source);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ impl EventRegistry {
|
|||
// 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.
|
||||
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 {
|
||||
component_id,
|
||||
previously_updated: false,
|
||||
|
@ -84,7 +84,7 @@ impl EventRegistry {
|
|||
/// Removes an event from the world and it's associated [`EventRegistry`].
|
||||
pub fn deregister_events<T: Event>(world: &mut World) {
|
||||
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
|
||||
.retain(|e| e.component_id != component_id);
|
||||
|
|
|
@ -405,7 +405,7 @@ impl Schedule {
|
|||
if self.graph.changed {
|
||||
self.graph.initialize(world);
|
||||
let ignored_ambiguities = world
|
||||
.get_resource_or_insert_with::<Schedules>(Schedules::default)
|
||||
.get_resource_or_init::<Schedules>()
|
||||
.ignored_scheduling_ambiguities
|
||||
.clone();
|
||||
self.graph.update_schedule(
|
||||
|
|
|
@ -2101,6 +2101,19 @@ impl World {
|
|||
|
||||
/// Gets a mutable reference to the resource of type `T` if it exists,
|
||||
/// 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]
|
||||
#[track_caller]
|
||||
pub fn get_resource_or_insert_with<R: Resource>(
|
||||
|
@ -2137,6 +2150,82 @@ impl World {
|
|||
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.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -3230,7 +3319,7 @@ impl World {
|
|||
///
|
||||
/// The `Schedules` resource will be initialized if it does not already exist.
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -241,12 +241,10 @@ impl AppGizmoBuilder for App {
|
|||
}
|
||||
|
||||
self.world_mut()
|
||||
.get_resource_or_insert_with::<GizmoConfigStore>(Default::default)
|
||||
.get_resource_or_init::<GizmoConfigStore>()
|
||||
.register::<Config>();
|
||||
|
||||
let mut handles = self
|
||||
.world_mut()
|
||||
.get_resource_or_insert_with::<LineGizmoHandles>(Default::default);
|
||||
let mut handles = self.world_mut().get_resource_or_init::<LineGizmoHandles>();
|
||||
|
||||
handles.list.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.world_mut()
|
||||
.get_resource_or_insert_with::<GizmoConfigStore>(Default::default)
|
||||
.get_resource_or_init::<GizmoConfigStore>()
|
||||
.insert(config, group);
|
||||
|
||||
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
|
||||
/// be added manually in other situations.
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue