bevy_ecs/change_detection/
traits.rs

1use crate::{change_detection::MaybeLocation, change_detection::Tick};
2use alloc::borrow::ToOwned;
3use core::mem;
4
5/// Types that can read change detection information.
6/// This change detection is controlled by [`DetectChangesMut`] types such as [`ResMut`].
7///
8/// ## Example
9/// Using types that implement [`DetectChanges`], such as [`Res`], provide
10/// a way to query if a value has been mutated in another system.
11///
12/// ```
13/// use bevy_ecs::prelude::*;
14///
15/// #[derive(Resource)]
16/// struct MyResource(u32);
17///
18/// fn my_system(mut resource: Res<MyResource>) {
19///     if resource.is_changed() {
20///         println!("My component was mutated!");
21///     }
22/// }
23/// ```
24///
25/// [`Res`]: crate::change_detection::params::Res
26/// [`ResMut`]: crate::change_detection::params::ResMut
27pub trait DetectChanges {
28    /// Returns `true` if this value was added after the system last ran.
29    fn is_added(&self) -> bool;
30
31    /// Returns `true` if this value was added or mutably dereferenced
32    /// either since the last time the system ran or, if the system never ran,
33    /// since the beginning of the program.
34    ///
35    /// To check if the value was mutably dereferenced only,
36    /// use `this.is_changed() && !this.is_added()`.
37    fn is_changed(&self) -> bool;
38
39    /// Returns the change tick recording the time this data was most recently changed.
40    ///
41    /// Note that components and resources are also marked as changed upon insertion.
42    ///
43    /// For comparison, the previous change tick of a system can be read using the
44    /// [`SystemChangeTick`](crate::system::SystemChangeTick)
45    /// [`SystemParam`](crate::system::SystemParam).
46    fn last_changed(&self) -> Tick;
47
48    /// Returns the change tick recording the time this data was added.
49    fn added(&self) -> Tick;
50
51    /// The location that last caused this to change.
52    fn changed_by(&self) -> MaybeLocation;
53}
54
55/// Types that implement reliable change detection.
56///
57/// ## Example
58/// Using types that implement [`DetectChangesMut`], such as [`ResMut`], provide
59/// a way to query if a value has been mutated in another system.
60/// Normally change detection is triggered by either [`DerefMut`] or [`AsMut`], however
61/// it can be manually triggered via [`set_changed`](DetectChangesMut::set_changed).
62///
63/// To ensure that changes are only triggered when the value actually differs,
64/// check if the value would change before assignment, such as by checking that `new != old`.
65/// You must be *sure* that you are not mutably dereferencing in this process.
66///
67/// [`set_if_neq`](DetectChangesMut::set_if_neq) is a helper
68/// method for this common functionality.
69///
70/// ```
71/// use bevy_ecs::prelude::*;
72///
73/// #[derive(Resource)]
74/// struct MyResource(u32);
75///
76/// fn my_system(mut resource: ResMut<MyResource>) {
77///     if resource.is_changed() {
78///         println!("My resource was mutated!");
79///     }
80///
81///    resource.0 = 42; // triggers change detection via [`DerefMut`]
82/// }
83/// ```
84///
85/// [`ResMut`]: crate::change_detection::params::ResMut
86/// [`DerefMut`]: core::ops::DerefMut
87pub trait DetectChangesMut: DetectChanges {
88    /// The type contained within this smart pointer
89    ///
90    /// For example, for `ResMut<T>` this would be `T`.
91    type Inner: ?Sized;
92
93    /// Flags this value as having been changed.
94    ///
95    /// Mutably accessing this smart pointer will automatically flag this value as having been changed.
96    /// However, mutation through interior mutability requires manual reporting.
97    ///
98    /// **Note**: This operation cannot be undone.
99    fn set_changed(&mut self);
100
101    /// Flags this value as having been added.
102    ///
103    /// It is not normally necessary to call this method.
104    /// The 'added' tick is set when the value is first added,
105    /// and is not normally changed afterwards.
106    ///
107    /// **Note**: This operation cannot be undone.
108    fn set_added(&mut self);
109
110    /// Manually sets the change tick recording the time when this data was last mutated.
111    ///
112    /// # Warning
113    /// This is a complex and error-prone operation, primarily intended for use with rollback networking strategies.
114    /// If you merely want to flag this data as changed, use [`set_changed`](DetectChangesMut::set_changed) instead.
115    /// If you want to avoid triggering change detection, use [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) instead.
116    fn set_last_changed(&mut self, last_changed: Tick);
117
118    /// Manually sets the added tick recording the time when this data was last added.
119    ///
120    /// # Warning
121    /// The caveats of [`set_last_changed`](DetectChangesMut::set_last_changed) apply. This modifies both the added and changed ticks together.
122    fn set_last_added(&mut self, last_added: Tick);
123
124    /// Manually bypasses change detection, allowing you to mutate the underlying value without updating the change tick.
125    ///
126    /// # Warning
127    /// This is a risky operation, that can have unexpected consequences on any system relying on this code.
128    /// However, it can be an essential escape hatch when, for example,
129    /// you are trying to synchronize representations using change detection and need to avoid infinite recursion.
130    fn bypass_change_detection(&mut self) -> &mut Self::Inner;
131
132    /// Overwrites this smart pointer with the given value, if and only if `*self != value`.
133    /// Returns `true` if the value was overwritten, and returns `false` if it was not.
134    ///
135    /// This is useful to ensure change detection is only triggered when the underlying value
136    /// changes, instead of every time it is mutably accessed.
137    ///
138    /// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
139    /// then consider applying a `map_unchanged` beforehand to allow changing only the relevant
140    /// field and prevent unnecessary copying and cloning.
141    /// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
142    /// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
143    ///
144    /// If you need the previous value, use [`replace_if_neq`](DetectChangesMut::replace_if_neq).
145    ///
146    /// # Examples
147    ///
148    /// ```
149    /// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};
150    /// #[derive(Resource, PartialEq, Eq)]
151    /// pub struct Score(u32);
152    ///
153    /// fn reset_score(mut score: ResMut<Score>) {
154    ///     // Set the score to zero, unless it is already zero.
155    ///     score.set_if_neq(Score(0));
156    /// }
157    /// # let mut world = World::new();
158    /// # world.insert_resource(Score(1));
159    /// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
160    /// # score_changed.initialize(&mut world);
161    /// # score_changed.run((), &mut world);
162    /// #
163    /// # let mut schedule = Schedule::default();
164    /// # schedule.add_systems(reset_score);
165    /// #
166    /// # // first time `reset_score` runs, the score is changed.
167    /// # schedule.run(&mut world);
168    /// # assert!(score_changed.run((), &mut world).unwrap());
169    /// # // second time `reset_score` runs, the score is not changed.
170    /// # schedule.run(&mut world);
171    /// # assert!(!score_changed.run((), &mut world).unwrap());
172    /// ```
173    ///
174    /// [`Mut::map_unchanged`]: crate::change_detection::params::Mut::map_unchanged
175    /// [`MutUntyped::map_unchanged`]: crate::change_detection::params::MutUntyped::map_unchanged
176    /// [`ResMut::map_unchanged`]: crate::change_detection::params::ResMut::map_unchanged
177    /// [`NonSendMut::map_unchanged`]: crate::change_detection::params::NonSendMut::map_unchanged
178    #[inline]
179    #[track_caller]
180    fn set_if_neq(&mut self, value: Self::Inner) -> bool
181    where
182        Self::Inner: Sized + PartialEq,
183    {
184        let old = self.bypass_change_detection();
185        if *old != value {
186            *old = value;
187            self.set_changed();
188            true
189        } else {
190            false
191        }
192    }
193
194    /// Overwrites this smart pointer with the given value, if and only if `*self != value`,
195    /// returning the previous value if this occurs.
196    ///
197    /// This is useful to ensure change detection is only triggered when the underlying value
198    /// changes, instead of every time it is mutably accessed.
199    ///
200    /// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
201    /// then consider applying a `map_unchanged` beforehand to allow
202    /// changing only the relevant field and prevent unnecessary copying and cloning.
203    /// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
204    /// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
205    ///
206    /// If you don't need the previous value, use [`set_if_neq`](DetectChangesMut::set_if_neq).
207    ///
208    /// # Examples
209    ///
210    /// ```
211    /// # use bevy_ecs::{prelude::*, schedule::common_conditions::{resource_changed, on_message}};
212    /// #[derive(Resource, PartialEq, Eq)]
213    /// pub struct Score(u32);
214    ///
215    /// #[derive(Message, PartialEq, Eq)]
216    /// pub struct ScoreChanged {
217    ///     current: u32,
218    ///     previous: u32,
219    /// }
220    ///
221    /// fn reset_score(mut score: ResMut<Score>, mut score_changed: MessageWriter<ScoreChanged>) {
222    ///     // Set the score to zero, unless it is already zero.
223    ///     let new_score = 0;
224    ///     if let Some(Score(previous_score)) = score.replace_if_neq(Score(new_score)) {
225    ///         // If `score` change, emit a `ScoreChanged` event.
226    ///         score_changed.write(ScoreChanged {
227    ///             current: new_score,
228    ///             previous: previous_score,
229    ///         });
230    ///     }
231    /// }
232    /// # let mut world = World::new();
233    /// # world.insert_resource(Messages::<ScoreChanged>::default());
234    /// # world.insert_resource(Score(1));
235    /// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
236    /// # score_changed.initialize(&mut world);
237    /// # score_changed.run((), &mut world);
238    /// #
239    /// # let mut score_changed_event = IntoSystem::into_system(on_message::<ScoreChanged>);
240    /// # score_changed_event.initialize(&mut world);
241    /// # score_changed_event.run((), &mut world);
242    /// #
243    /// # let mut schedule = Schedule::default();
244    /// # schedule.add_systems(reset_score);
245    /// #
246    /// # // first time `reset_score` runs, the score is changed.
247    /// # schedule.run(&mut world);
248    /// # assert!(score_changed.run((), &mut world).unwrap());
249    /// # assert!(score_changed_event.run((), &mut world).unwrap());
250    /// # // second time `reset_score` runs, the score is not changed.
251    /// # schedule.run(&mut world);
252    /// # assert!(!score_changed.run((), &mut world).unwrap());
253    /// # assert!(!score_changed_event.run((), &mut world).unwrap());
254    /// ```
255    ///
256    /// [`Mut::map_unchanged`]: crate::change_detection::params::Mut::map_unchanged
257    /// [`MutUntyped::map_unchanged`]: crate::change_detection::params::MutUntyped::map_unchanged
258    /// [`ResMut::map_unchanged`]: crate::change_detection::params::ResMut::map_unchanged
259    /// [`NonSendMut::map_unchanged`]: crate::change_detection::params::NonSendMut::map_unchanged
260    #[inline]
261    #[must_use = "If you don't need to handle the previous value, use `set_if_neq` instead."]
262    fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>
263    where
264        Self::Inner: Sized + PartialEq,
265    {
266        let old = self.bypass_change_detection();
267        if *old != value {
268            let previous = mem::replace(old, value);
269            self.set_changed();
270            Some(previous)
271        } else {
272            None
273        }
274    }
275
276    /// Overwrites this smart pointer with a clone of the given value, if and only if `*self != value`.
277    /// Returns `true` if the value was overwritten, and returns `false` if it was not.
278    ///
279    /// This method is useful when the caller only has a borrowed form of `Inner`,
280    /// e.g. when writing a `&str` into a `Mut<String>`.
281    ///
282    /// # Examples
283    /// ```
284    /// # extern crate alloc;
285    /// # use alloc::borrow::ToOwned;
286    /// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};
287    /// #[derive(Resource)]
288    /// pub struct Message(String);
289    ///
290    /// fn update_message(mut message: ResMut<Message>) {
291    ///     // Set the score to zero, unless it is already zero.
292    ///     ResMut::map_unchanged(message, |Message(msg)| msg).clone_from_if_neq("another string");
293    /// }
294    /// # let mut world = World::new();
295    /// # world.insert_resource(Message("initial string".into()));
296    /// # let mut message_changed = IntoSystem::into_system(resource_changed::<Message>);
297    /// # message_changed.initialize(&mut world);
298    /// # message_changed.run((), &mut world);
299    /// #
300    /// # let mut schedule = Schedule::default();
301    /// # schedule.add_systems(update_message);
302    /// #
303    /// # // first time `reset_score` runs, the score is changed.
304    /// # schedule.run(&mut world);
305    /// # assert!(message_changed.run((), &mut world).unwrap());
306    /// # // second time `reset_score` runs, the score is not changed.
307    /// # schedule.run(&mut world);
308    /// # assert!(!message_changed.run((), &mut world).unwrap());
309    /// ```
310    fn clone_from_if_neq<T>(&mut self, value: &T) -> bool
311    where
312        T: ToOwned<Owned = Self::Inner> + ?Sized,
313        Self::Inner: PartialEq<T>,
314    {
315        let old = self.bypass_change_detection();
316        if old != value {
317            value.clone_into(old);
318            self.set_changed();
319            true
320        } else {
321            false
322        }
323    }
324}
325
326macro_rules! change_detection_impl {
327    ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
328        impl<$($generics),* : ?Sized $(+ $traits)?> DetectChanges for $name<$($generics),*> {
329            #[inline]
330            fn is_added(&self) -> bool {
331                self.ticks
332                    .added
333                    .is_newer_than(self.ticks.last_run, self.ticks.this_run)
334            }
335
336            #[inline]
337            fn is_changed(&self) -> bool {
338                self.ticks
339                    .changed
340                    .is_newer_than(self.ticks.last_run, self.ticks.this_run)
341            }
342
343            #[inline]
344            fn last_changed(&self) -> Tick {
345                *self.ticks.changed
346            }
347
348            #[inline]
349            fn added(&self) -> Tick {
350                *self.ticks.added
351            }
352
353            #[inline]
354            fn changed_by(&self) -> MaybeLocation {
355                self.ticks.changed_by.copied()
356            }
357        }
358
359        impl<$($generics),*: ?Sized $(+ $traits)?> Deref for $name<$($generics),*> {
360            type Target = $target;
361
362            #[inline]
363            fn deref(&self) -> &Self::Target {
364                self.value
365            }
366        }
367
368        impl<$($generics),* $(: $traits)?> AsRef<$target> for $name<$($generics),*> {
369            #[inline]
370            fn as_ref(&self) -> &$target {
371                self.deref()
372            }
373        }
374    }
375}
376
377pub(crate) use change_detection_impl;
378
379macro_rules! change_detection_mut_impl {
380    ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
381        impl<$($generics),* : ?Sized $(+ $traits)?> DetectChangesMut for $name<$($generics),*> {
382            type Inner = $target;
383
384            #[inline]
385            #[track_caller]
386            fn set_changed(&mut self) {
387                *self.ticks.changed = self.ticks.this_run;
388                self.ticks.changed_by.assign(MaybeLocation::caller());
389            }
390
391            #[inline]
392            #[track_caller]
393            fn set_added(&mut self) {
394                *self.ticks.changed = self.ticks.this_run;
395                *self.ticks.added = self.ticks.this_run;
396                self.ticks.changed_by.assign(MaybeLocation::caller());
397            }
398
399            #[inline]
400            #[track_caller]
401            fn set_last_changed(&mut self, last_changed: Tick) {
402                *self.ticks.changed = last_changed;
403                self.ticks.changed_by.assign(MaybeLocation::caller());
404            }
405
406            #[inline]
407            #[track_caller]
408            fn set_last_added(&mut self, last_added: Tick) {
409                *self.ticks.added = last_added;
410                *self.ticks.changed = last_added;
411                self.ticks.changed_by.assign(MaybeLocation::caller());
412            }
413
414            #[inline]
415            fn bypass_change_detection(&mut self) -> &mut Self::Inner {
416                self.value
417            }
418        }
419
420        impl<$($generics),* : ?Sized $(+ $traits)?> DerefMut for $name<$($generics),*> {
421            #[inline]
422            #[track_caller]
423            fn deref_mut(&mut self) -> &mut Self::Target {
424                self.set_changed();
425                self.ticks.changed_by.assign(MaybeLocation::caller());
426                self.value
427            }
428        }
429
430        impl<$($generics),* $(: $traits)?> AsMut<$target> for $name<$($generics),*> {
431            #[inline]
432            fn as_mut(&mut self) -> &mut $target {
433                self.deref_mut()
434            }
435        }
436    };
437}
438
439pub(crate) use change_detection_mut_impl;
440
441macro_rules! impl_methods {
442    ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
443        impl<$($generics),* : ?Sized $(+ $traits)?> $name<$($generics),*> {
444            /// Consume `self` and return a mutable reference to the
445            /// contained value while marking `self` as "changed".
446            #[inline]
447            pub fn into_inner(mut self) -> &'w mut $target {
448                self.set_changed();
449                self.value
450            }
451
452            /// Returns a `Mut<>` with a smaller lifetime.
453            /// This is useful if you have `&mut
454            #[doc = stringify!($name)]
455            /// <T>`, but you need a `Mut<T>`.
456            pub fn reborrow(&mut self) -> Mut<'_, $target> {
457                Mut {
458                    value: self.value,
459                    ticks: ComponentTicksMut {
460                        added: self.ticks.added,
461                        changed: self.ticks.changed,
462                        changed_by: self.ticks.changed_by.as_deref_mut(),
463                        last_run: self.ticks.last_run,
464                        this_run: self.ticks.this_run,
465                    },
466                }
467            }
468
469            /// Maps to an inner value by applying a function to the contained reference, without flagging a change.
470            ///
471            /// You should never modify the argument passed to the closure -- if you want to modify the data
472            /// without flagging a change, consider using [`DetectChangesMut::bypass_change_detection`] to make your intent explicit.
473            ///
474            /// ```
475            /// # use bevy_ecs::prelude::*;
476            /// # #[derive(PartialEq)] pub struct Vec2;
477            /// # impl Vec2 { pub const ZERO: Self = Self; }
478            /// # #[derive(Component)] pub struct Transform { translation: Vec2 }
479            /// // When run, zeroes the translation of every entity.
480            /// fn reset_positions(mut transforms: Query<&mut Transform>) {
481            ///     for transform in &mut transforms {
482            ///         // We pinky promise not to modify `t` within the closure.
483            ///         // Breaking this promise will result in logic errors, but will never cause undefined behavior.
484            ///         let mut translation = transform.map_unchanged(|t| &mut t.translation);
485            ///         // Only reset the translation if it isn't already zero;
486            ///         translation.set_if_neq(Vec2::ZERO);
487            ///     }
488            /// }
489            /// # bevy_ecs::system::assert_is_system(reset_positions);
490            /// ```
491            pub fn map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> &mut U) -> Mut<'w, U> {
492                Mut {
493                    value: f(self.value),
494                    ticks: self.ticks,
495                }
496            }
497
498            /// Optionally maps to an inner value by applying a function to the contained reference.
499            /// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.
500            ///
501            /// As with `map_unchanged`, you should never modify the argument passed to the closure.
502            pub fn filter_map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> Option<&mut U>) -> Option<Mut<'w, U>> {
503                let value = f(self.value);
504                value.map(|value| Mut {
505                    value,
506                    ticks: self.ticks,
507                })
508            }
509
510            /// Optionally maps to an inner value by applying a function to the contained reference, returns an error on failure.
511            /// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.
512            ///
513            /// As with `map_unchanged`, you should never modify the argument passed to the closure.
514            pub fn try_map_unchanged<U: ?Sized, E>(self, f: impl FnOnce(&mut $target) -> Result<&mut U, E>) -> Result<Mut<'w, U>, E> {
515                let value = f(self.value);
516                value.map(|value| Mut {
517                    value,
518                    ticks: self.ticks,
519                })
520            }
521
522            /// Allows you access to the dereferenced value of this pointer without immediately
523            /// triggering change detection.
524            pub fn as_deref_mut(&mut self) -> Mut<'_, <$target as Deref>::Target>
525                where $target: DerefMut
526            {
527                self.reborrow().map_unchanged(|v| v.deref_mut())
528            }
529
530        }
531    };
532}
533
534pub(crate) use impl_methods;
535
536macro_rules! impl_debug {
537    ($name:ident < $( $generics:tt ),+ >, $($traits:ident)?) => {
538        impl<$($generics),* : ?Sized $(+ $traits)?> core::fmt::Debug for $name<$($generics),*>
539            where T: core::fmt::Debug
540        {
541            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
542                f.debug_tuple(stringify!($name))
543                    .field(&self.value)
544                    .finish()
545            }
546        }
547
548    };
549}
550
551pub(crate) use impl_debug;