Add replace_if_neq to DetectChangesMut (#9418)
# Objective Just like [`set_if_neq`](https://docs.rs/bevy_ecs/latest/bevy_ecs/change_detection/trait.DetectChangesMut.html#method.set_if_neq), being able to express the "I don't want to unnecessarily trigger the change detection" but with the ability to handle the previous value if change occurs. ## Solution Add `replace_if_neq` to `DetectChangesMut`. --- ## Changelog - Added `DetectChangesMut::replace_if_neq`: like `set_if_neq` change the value only if the new value if different from the current one, but return the previous value if the change occurs.
This commit is contained in:
parent
1abb6b0758
commit
cfb65c1eaf
@ -6,6 +6,7 @@ use crate::{
|
||||
system::Resource,
|
||||
};
|
||||
use bevy_ptr::{Ptr, UnsafeCellDeref};
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
|
||||
@ -129,6 +130,8 @@ pub trait DetectChangesMut: DetectChanges {
|
||||
/// This is useful to ensure change detection is only triggered when the underlying value
|
||||
/// changes, instead of every time it is mutably accessed.
|
||||
///
|
||||
/// If you need to handle the previous value, use [`replace_if_neq`](DetectChangesMut::replace_if_neq).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -167,6 +170,77 @@ pub trait DetectChangesMut: DetectChanges {
|
||||
self.set_changed();
|
||||
}
|
||||
}
|
||||
|
||||
/// Overwrites this smart pointer with the given value, if and only if `*self != value`
|
||||
/// returning the previous value if this occurs.
|
||||
///
|
||||
/// This is useful to ensure change detection is only triggered when the underlying value
|
||||
/// changes, instead of every time it is mutably accessed.
|
||||
///
|
||||
/// If you don't need to handle the previous value, use [`set_if_neq`](DetectChangesMut::set_if_neq).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::{prelude::*, schedule::common_conditions::{resource_changed, on_event}};
|
||||
/// #[derive(Resource, PartialEq, Eq)]
|
||||
/// pub struct Score(u32);
|
||||
///
|
||||
/// #[derive(Event, PartialEq, Eq)]
|
||||
/// pub struct ScoreChanged {
|
||||
/// current: u32,
|
||||
/// previous: u32,
|
||||
/// }
|
||||
///
|
||||
/// fn reset_score(mut score: ResMut<Score>, mut score_changed: EventWriter<ScoreChanged>) {
|
||||
/// // Set the score to zero, unless it is already zero.
|
||||
/// let new_score = 0;
|
||||
/// if let Some(Score(previous_score)) = score.replace_if_neq(Score(new_score)) {
|
||||
/// // If `score` change, emit a `ScoreChanged` event.
|
||||
/// score_changed.send(ScoreChanged {
|
||||
/// current: new_score,
|
||||
/// previous: previous_score,
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
/// # let mut world = World::new();
|
||||
/// # world.insert_resource(Events::<ScoreChanged>::default());
|
||||
/// # world.insert_resource(Score(1));
|
||||
/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>());
|
||||
/// # score_changed.initialize(&mut world);
|
||||
/// # score_changed.run((), &mut world);
|
||||
/// #
|
||||
/// # let mut score_changed_event = IntoSystem::into_system(on_event::<ScoreChanged>());
|
||||
/// # score_changed_event.initialize(&mut world);
|
||||
/// # score_changed_event.run((), &mut world);
|
||||
/// #
|
||||
/// # let mut schedule = Schedule::new();
|
||||
/// # schedule.add_systems(reset_score);
|
||||
/// #
|
||||
/// # // first time `reset_score` runs, the score is changed.
|
||||
/// # schedule.run(&mut world);
|
||||
/// # assert!(score_changed.run((), &mut world));
|
||||
/// # assert!(score_changed_event.run((), &mut world));
|
||||
/// # // second time `reset_score` runs, the score is not changed.
|
||||
/// # schedule.run(&mut world);
|
||||
/// # assert!(!score_changed.run((), &mut world));
|
||||
/// # assert!(!score_changed_event.run((), &mut world));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use = "If you don't need to handle the previous value, use `set_if_neq` instead."]
|
||||
fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>
|
||||
where
|
||||
Self::Inner: Sized + PartialEq,
|
||||
{
|
||||
let old = self.bypass_change_detection();
|
||||
if *old != value {
|
||||
let previous = mem::replace(old, value);
|
||||
self.set_changed();
|
||||
Some(previous)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! change_detection_impl {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user