Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add World::get_resource_or_init as an alternative to World::get_resource_or_insert_with #15758

Merged
merged 3 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/bevy_asset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ecs/src/event/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/schedule/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
91 changes: 90 additions & 1 deletion crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

Expand Down
8 changes: 3 additions & 5 deletions crates/bevy_gizmos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_state/src/state/transitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down