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