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