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;