bevy_ecs/change_detection.rs
1//! Types that detect when their internal data mutate.
2
3use crate::{
4 component::{Tick, TickCells},
5 ptr::PtrMut,
6 system::Resource,
7};
8use bevy_ptr::{Ptr, UnsafeCellDeref};
9use core::{
10 mem,
11 ops::{Deref, DerefMut},
12};
13#[cfg(feature = "track_change_detection")]
14use {
15 bevy_ptr::ThinSlicePtr,
16 core::{cell::UnsafeCell, panic::Location},
17};
18
19/// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
20///
21/// Change ticks can only be scanned when systems aren't running. Thus, if the threshold is `N`,
22/// the maximum is `2 * N - 1` (i.e. the world ticks `N - 1` times, then `N` times).
23///
24/// If no change is older than `u32::MAX - (2 * N - 1)` following a scan, none of their ages can
25/// overflow and cause false positives.
26// (518,400,000 = 1000 ticks per frame * 144 frames per second * 3600 seconds per hour)
27pub const CHECK_TICK_THRESHOLD: u32 = 518_400_000;
28
29/// The maximum change tick difference that won't overflow before the next `check_tick` scan.
30///
31/// Changes stop being detected once they become this old.
32pub const MAX_CHANGE_AGE: u32 = u32::MAX - (2 * CHECK_TICK_THRESHOLD - 1);
33
34/// Types that can read change detection information.
35/// This change detection is controlled by [`DetectChangesMut`] types such as [`ResMut`].
36///
37/// ## Example
38/// Using types that implement [`DetectChanges`], such as [`Res`], provide
39/// a way to query if a value has been mutated in another system.
40///
41/// ```
42/// use bevy_ecs::prelude::*;
43///
44/// #[derive(Resource)]
45/// struct MyResource(u32);
46///
47/// fn my_system(mut resource: Res<MyResource>) {
48/// if resource.is_changed() {
49/// println!("My component was mutated!");
50/// }
51/// }
52/// ```
53pub trait DetectChanges {
54 /// Returns `true` if this value was added after the system last ran.
55 fn is_added(&self) -> bool;
56
57 /// Returns `true` if this value was added or mutably dereferenced
58 /// either since the last time the system ran or, if the system never ran,
59 /// since the beginning of the program.
60 ///
61 /// To check if the value was mutably dereferenced only,
62 /// use `this.is_changed() && !this.is_added()`.
63 fn is_changed(&self) -> bool;
64
65 /// Returns the change tick recording the time this data was most recently changed.
66 ///
67 /// Note that components and resources are also marked as changed upon insertion.
68 ///
69 /// For comparison, the previous change tick of a system can be read using the
70 /// [`SystemChangeTick`](crate::system::SystemChangeTick)
71 /// [`SystemParam`](crate::system::SystemParam).
72 fn last_changed(&self) -> Tick;
73
74 /// The location that last caused this to change.
75 #[cfg(feature = "track_change_detection")]
76 fn changed_by(&self) -> &'static Location<'static>;
77}
78
79/// Types that implement reliable change detection.
80///
81/// ## Example
82/// Using types that implement [`DetectChangesMut`], such as [`ResMut`], provide
83/// a way to query if a value has been mutated in another system.
84/// Normally change detection is triggered by either [`DerefMut`] or [`AsMut`], however
85/// it can be manually triggered via [`set_changed`](DetectChangesMut::set_changed).
86///
87/// To ensure that changes are only triggered when the value actually differs,
88/// check if the value would change before assignment, such as by checking that `new != old`.
89/// You must be *sure* that you are not mutably dereferencing in this process.
90///
91/// [`set_if_neq`](DetectChangesMut::set_if_neq) is a helper
92/// method for this common functionality.
93///
94/// ```
95/// use bevy_ecs::prelude::*;
96///
97/// #[derive(Resource)]
98/// struct MyResource(u32);
99///
100/// fn my_system(mut resource: ResMut<MyResource>) {
101/// if resource.is_changed() {
102/// println!("My resource was mutated!");
103/// }
104///
105/// resource.0 = 42; // triggers change detection via [`DerefMut`]
106/// }
107/// ```
108pub trait DetectChangesMut: DetectChanges {
109 /// The type contained within this smart pointer
110 ///
111 /// For example, for `ResMut<T>` this would be `T`.
112 type Inner: ?Sized;
113
114 /// Flags this value as having been changed.
115 ///
116 /// Mutably accessing this smart pointer will automatically flag this value as having been changed.
117 /// However, mutation through interior mutability requires manual reporting.
118 ///
119 /// **Note**: This operation cannot be undone.
120 fn set_changed(&mut self);
121
122 /// Manually sets the change tick recording the time when this data was last mutated.
123 ///
124 /// # Warning
125 /// This is a complex and error-prone operation, primarily intended for use with rollback networking strategies.
126 /// If you merely want to flag this data as changed, use [`set_changed`](DetectChangesMut::set_changed) instead.
127 /// If you want to avoid triggering change detection, use [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) instead.
128 fn set_last_changed(&mut self, last_changed: Tick);
129
130 /// Manually bypasses change detection, allowing you to mutate the underlying value without updating the change tick.
131 ///
132 /// # Warning
133 /// This is a risky operation, that can have unexpected consequences on any system relying on this code.
134 /// However, it can be an essential escape hatch when, for example,
135 /// you are trying to synchronize representations using change detection and need to avoid infinite recursion.
136 fn bypass_change_detection(&mut self) -> &mut Self::Inner;
137
138 /// Overwrites this smart pointer with the given value, if and only if `*self != value`.
139 /// Returns `true` if the value was overwritten, and returns `false` if it was not.
140 ///
141 /// This is useful to ensure change detection is only triggered when the underlying value
142 /// changes, instead of every time it is mutably accessed.
143 ///
144 /// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
145 /// then consider applying a `map_unchanged` beforehand to allow changing only the relevant
146 /// field and prevent unnecessary copying and cloning.
147 /// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
148 /// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
149 ///
150 /// If you need the previous value, use [`replace_if_neq`](DetectChangesMut::replace_if_neq).
151 ///
152 /// # Examples
153 ///
154 /// ```
155 /// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};
156 /// #[derive(Resource, PartialEq, Eq)]
157 /// pub struct Score(u32);
158 ///
159 /// fn reset_score(mut score: ResMut<Score>) {
160 /// // Set the score to zero, unless it is already zero.
161 /// score.set_if_neq(Score(0));
162 /// }
163 /// # let mut world = World::new();
164 /// # world.insert_resource(Score(1));
165 /// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
166 /// # score_changed.initialize(&mut world);
167 /// # score_changed.run((), &mut world);
168 /// #
169 /// # let mut schedule = Schedule::default();
170 /// # schedule.add_systems(reset_score);
171 /// #
172 /// # // first time `reset_score` runs, the score is changed.
173 /// # schedule.run(&mut world);
174 /// # assert!(score_changed.run((), &mut world));
175 /// # // second time `reset_score` runs, the score is not changed.
176 /// # schedule.run(&mut world);
177 /// # assert!(!score_changed.run((), &mut world));
178 /// ```
179 #[inline]
180 #[track_caller]
181 fn set_if_neq(&mut self, value: Self::Inner) -> bool
182 where
183 Self::Inner: Sized + PartialEq,
184 {
185 let old = self.bypass_change_detection();
186 if *old != value {
187 *old = value;
188 self.set_changed();
189 true
190 } else {
191 false
192 }
193 }
194
195 /// Overwrites this smart pointer with the given value, if and only if `*self != value`,
196 /// returning the previous value if this occurs.
197 ///
198 /// This is useful to ensure change detection is only triggered when the underlying value
199 /// changes, instead of every time it is mutably accessed.
200 ///
201 /// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
202 /// then consider applying a [`map_unchanged`](Mut::map_unchanged) beforehand to allow
203 /// changing only the relevant field and prevent unnecessary copying and cloning.
204 /// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
205 /// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
206 ///
207 /// If you don't need the previous value, use [`set_if_neq`](DetectChangesMut::set_if_neq).
208 ///
209 /// # Examples
210 ///
211 /// ```
212 /// # use bevy_ecs::{prelude::*, schedule::common_conditions::{resource_changed, on_event}};
213 /// #[derive(Resource, PartialEq, Eq)]
214 /// pub struct Score(u32);
215 ///
216 /// #[derive(Event, PartialEq, Eq)]
217 /// pub struct ScoreChanged {
218 /// current: u32,
219 /// previous: u32,
220 /// }
221 ///
222 /// fn reset_score(mut score: ResMut<Score>, mut score_changed: EventWriter<ScoreChanged>) {
223 /// // Set the score to zero, unless it is already zero.
224 /// let new_score = 0;
225 /// if let Some(Score(previous_score)) = score.replace_if_neq(Score(new_score)) {
226 /// // If `score` change, emit a `ScoreChanged` event.
227 /// score_changed.send(ScoreChanged {
228 /// current: new_score,
229 /// previous: previous_score,
230 /// });
231 /// }
232 /// }
233 /// # let mut world = World::new();
234 /// # world.insert_resource(Events::<ScoreChanged>::default());
235 /// # world.insert_resource(Score(1));
236 /// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
237 /// # score_changed.initialize(&mut world);
238 /// # score_changed.run((), &mut world);
239 /// #
240 /// # let mut score_changed_event = IntoSystem::into_system(on_event::<ScoreChanged>);
241 /// # score_changed_event.initialize(&mut world);
242 /// # score_changed_event.run((), &mut world);
243 /// #
244 /// # let mut schedule = Schedule::default();
245 /// # schedule.add_systems(reset_score);
246 /// #
247 /// # // first time `reset_score` runs, the score is changed.
248 /// # schedule.run(&mut world);
249 /// # assert!(score_changed.run((), &mut world));
250 /// # assert!(score_changed_event.run((), &mut world));
251 /// # // second time `reset_score` runs, the score is not changed.
252 /// # schedule.run(&mut world);
253 /// # assert!(!score_changed.run((), &mut world));
254 /// # assert!(!score_changed_event.run((), &mut world));
255 /// ```
256 #[inline]
257 #[must_use = "If you don't need to handle the previous value, use `set_if_neq` instead."]
258 fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>
259 where
260 Self::Inner: Sized + PartialEq,
261 {
262 let old = self.bypass_change_detection();
263 if *old != value {
264 let previous = mem::replace(old, value);
265 self.set_changed();
266 Some(previous)
267 } else {
268 None
269 }
270 }
271}
272
273macro_rules! change_detection_impl {
274 ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
275 impl<$($generics),* : ?Sized $(+ $traits)?> DetectChanges for $name<$($generics),*> {
276 #[inline]
277 fn is_added(&self) -> bool {
278 self.ticks
279 .added
280 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
281 }
282
283 #[inline]
284 fn is_changed(&self) -> bool {
285 self.ticks
286 .changed
287 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
288 }
289
290 #[inline]
291 fn last_changed(&self) -> Tick {
292 *self.ticks.changed
293 }
294
295 #[inline]
296 #[cfg(feature = "track_change_detection")]
297 fn changed_by(&self) -> &'static Location<'static> {
298 self.changed_by
299 }
300 }
301
302 impl<$($generics),*: ?Sized $(+ $traits)?> Deref for $name<$($generics),*> {
303 type Target = $target;
304
305 #[inline]
306 fn deref(&self) -> &Self::Target {
307 self.value
308 }
309 }
310
311 impl<$($generics),* $(: $traits)?> AsRef<$target> for $name<$($generics),*> {
312 #[inline]
313 fn as_ref(&self) -> &$target {
314 self.deref()
315 }
316 }
317 }
318}
319
320macro_rules! change_detection_mut_impl {
321 ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
322 impl<$($generics),* : ?Sized $(+ $traits)?> DetectChangesMut for $name<$($generics),*> {
323 type Inner = $target;
324
325 #[inline]
326 #[track_caller]
327 fn set_changed(&mut self) {
328 *self.ticks.changed = self.ticks.this_run;
329 #[cfg(feature = "track_change_detection")]
330 {
331 *self.changed_by = Location::caller();
332 }
333 }
334
335 #[inline]
336 #[track_caller]
337 fn set_last_changed(&mut self, last_changed: Tick) {
338 *self.ticks.changed = last_changed;
339 #[cfg(feature = "track_change_detection")]
340 {
341 *self.changed_by = Location::caller();
342 }
343 }
344
345 #[inline]
346 fn bypass_change_detection(&mut self) -> &mut Self::Inner {
347 self.value
348 }
349 }
350
351 impl<$($generics),* : ?Sized $(+ $traits)?> DerefMut for $name<$($generics),*> {
352 #[inline]
353 #[track_caller]
354 fn deref_mut(&mut self) -> &mut Self::Target {
355 self.set_changed();
356 #[cfg(feature = "track_change_detection")]
357 {
358 *self.changed_by = Location::caller();
359 }
360 self.value
361 }
362 }
363
364 impl<$($generics),* $(: $traits)?> AsMut<$target> for $name<$($generics),*> {
365 #[inline]
366 fn as_mut(&mut self) -> &mut $target {
367 self.deref_mut()
368 }
369 }
370 };
371}
372
373macro_rules! impl_methods {
374 ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
375 impl<$($generics),* : ?Sized $(+ $traits)?> $name<$($generics),*> {
376 /// Consume `self` and return a mutable reference to the
377 /// contained value while marking `self` as "changed".
378 #[inline]
379 pub fn into_inner(mut self) -> &'w mut $target {
380 self.set_changed();
381 self.value
382 }
383
384 /// Returns a `Mut<>` with a smaller lifetime.
385 /// This is useful if you have `&mut
386 #[doc = stringify!($name)]
387 /// <T>`, but you need a `Mut<T>`.
388 pub fn reborrow(&mut self) -> Mut<'_, $target> {
389 Mut {
390 value: self.value,
391 ticks: TicksMut {
392 added: self.ticks.added,
393 changed: self.ticks.changed,
394 last_run: self.ticks.last_run,
395 this_run: self.ticks.this_run,
396 },
397 #[cfg(feature = "track_change_detection")]
398 changed_by: self.changed_by,
399 }
400 }
401
402 /// Maps to an inner value by applying a function to the contained reference, without flagging a change.
403 ///
404 /// You should never modify the argument passed to the closure -- if you want to modify the data
405 /// without flagging a change, consider using [`DetectChangesMut::bypass_change_detection`] to make your intent explicit.
406 ///
407 /// ```
408 /// # use bevy_ecs::prelude::*;
409 /// # #[derive(PartialEq)] pub struct Vec2;
410 /// # impl Vec2 { pub const ZERO: Self = Self; }
411 /// # #[derive(Component)] pub struct Transform { translation: Vec2 }
412 /// // When run, zeroes the translation of every entity.
413 /// fn reset_positions(mut transforms: Query<&mut Transform>) {
414 /// for transform in &mut transforms {
415 /// // We pinky promise not to modify `t` within the closure.
416 /// // Breaking this promise will result in logic errors, but will never cause undefined behavior.
417 /// let mut translation = transform.map_unchanged(|t| &mut t.translation);
418 /// // Only reset the translation if it isn't already zero;
419 /// translation.set_if_neq(Vec2::ZERO);
420 /// }
421 /// }
422 /// # bevy_ecs::system::assert_is_system(reset_positions);
423 /// ```
424 pub fn map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> &mut U) -> Mut<'w, U> {
425 Mut {
426 value: f(self.value),
427 ticks: self.ticks,
428 #[cfg(feature = "track_change_detection")]
429 changed_by: self.changed_by,
430 }
431 }
432
433 /// Optionally maps to an inner value by applying a function to the contained reference.
434 /// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.
435 ///
436 /// As with `map_unchanged`, you should never modify the argument passed to the closure.
437 pub fn filter_map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> Option<&mut U>) -> Option<Mut<'w, U>> {
438 let value = f(self.value);
439 value.map(|value| Mut {
440 value,
441 ticks: self.ticks,
442 #[cfg(feature = "track_change_detection")]
443 changed_by: self.changed_by,
444 })
445 }
446
447 /// Allows you access to the dereferenced value of this pointer without immediately
448 /// triggering change detection.
449 pub fn as_deref_mut(&mut self) -> Mut<'_, <$target as Deref>::Target>
450 where $target: DerefMut
451 {
452 self.reborrow().map_unchanged(|v| v.deref_mut())
453 }
454
455 }
456 };
457}
458
459macro_rules! impl_debug {
460 ($name:ident < $( $generics:tt ),+ >, $($traits:ident)?) => {
461 impl<$($generics),* : ?Sized $(+ $traits)?> core::fmt::Debug for $name<$($generics),*>
462 where T: core::fmt::Debug
463 {
464 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
465 f.debug_tuple(stringify!($name))
466 .field(&self.value)
467 .finish()
468 }
469 }
470
471 };
472}
473
474#[derive(Clone)]
475pub(crate) struct Ticks<'w> {
476 pub(crate) added: &'w Tick,
477 pub(crate) changed: &'w Tick,
478 pub(crate) last_run: Tick,
479 pub(crate) this_run: Tick,
480}
481
482impl<'w> Ticks<'w> {
483 /// # Safety
484 /// This should never alias the underlying ticks with a mutable one such as `TicksMut`.
485 #[inline]
486 pub(crate) unsafe fn from_tick_cells(
487 cells: TickCells<'w>,
488 last_run: Tick,
489 this_run: Tick,
490 ) -> Self {
491 Self {
492 // SAFETY: Caller ensures there is no mutable access to the cell.
493 added: unsafe { cells.added.deref() },
494 // SAFETY: Caller ensures there is no mutable access to the cell.
495 changed: unsafe { cells.changed.deref() },
496 last_run,
497 this_run,
498 }
499 }
500}
501
502pub(crate) struct TicksMut<'w> {
503 pub(crate) added: &'w mut Tick,
504 pub(crate) changed: &'w mut Tick,
505 pub(crate) last_run: Tick,
506 pub(crate) this_run: Tick,
507}
508
509impl<'w> TicksMut<'w> {
510 /// # Safety
511 /// This should never alias the underlying ticks. All access must be unique.
512 #[inline]
513 pub(crate) unsafe fn from_tick_cells(
514 cells: TickCells<'w>,
515 last_run: Tick,
516 this_run: Tick,
517 ) -> Self {
518 Self {
519 // SAFETY: Caller ensures there is no alias to the cell.
520 added: unsafe { cells.added.deref_mut() },
521 // SAFETY: Caller ensures there is no alias to the cell.
522 changed: unsafe { cells.changed.deref_mut() },
523 last_run,
524 this_run,
525 }
526 }
527}
528
529impl<'w> From<TicksMut<'w>> for Ticks<'w> {
530 fn from(ticks: TicksMut<'w>) -> Self {
531 Ticks {
532 added: ticks.added,
533 changed: ticks.changed,
534 last_run: ticks.last_run,
535 this_run: ticks.this_run,
536 }
537 }
538}
539
540/// Shared borrow of a [`Resource`].
541///
542/// See the [`Resource`] documentation for usage.
543///
544/// If you need a unique mutable borrow, use [`ResMut`] instead.
545///
546/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.
547/// This will cause a panic, but can be configured to do nothing or warn once.
548///
549/// Use [`Option<Res<T>>`] instead if the resource might not always exist.
550pub struct Res<'w, T: ?Sized + Resource> {
551 pub(crate) value: &'w T,
552 pub(crate) ticks: Ticks<'w>,
553 #[cfg(feature = "track_change_detection")]
554 pub(crate) changed_by: &'static Location<'static>,
555}
556
557impl<'w, T: Resource> Res<'w, T> {
558 /// Copies a reference to a resource.
559 ///
560 /// Note that unless you actually need an instance of `Res<T>`, you should
561 /// prefer to just convert it to `&T` which can be freely copied.
562 #[allow(clippy::should_implement_trait)]
563 pub fn clone(this: &Self) -> Self {
564 Self {
565 value: this.value,
566 ticks: this.ticks.clone(),
567 #[cfg(feature = "track_change_detection")]
568 changed_by: this.changed_by,
569 }
570 }
571
572 /// Due to lifetime limitations of the `Deref` trait, this method can be used to obtain a
573 /// reference of the [`Resource`] with a lifetime bound to `'w` instead of the lifetime of the
574 /// struct itself.
575 pub fn into_inner(self) -> &'w T {
576 self.value
577 }
578}
579
580impl<'w, T: Resource> From<ResMut<'w, T>> for Res<'w, T> {
581 fn from(res: ResMut<'w, T>) -> Self {
582 Self {
583 value: res.value,
584 ticks: res.ticks.into(),
585 #[cfg(feature = "track_change_detection")]
586 changed_by: res.changed_by,
587 }
588 }
589}
590
591impl<'w, T: Resource> From<Res<'w, T>> for Ref<'w, T> {
592 /// Convert a `Res` into a `Ref`. This allows keeping the change-detection feature of `Ref`
593 /// while losing the specificity of `Res` for resources.
594 fn from(res: Res<'w, T>) -> Self {
595 Self {
596 value: res.value,
597 ticks: res.ticks,
598 #[cfg(feature = "track_change_detection")]
599 changed_by: res.changed_by,
600 }
601 }
602}
603
604impl<'w, 'a, T: Resource> IntoIterator for &'a Res<'w, T>
605where
606 &'a T: IntoIterator,
607{
608 type Item = <&'a T as IntoIterator>::Item;
609 type IntoIter = <&'a T as IntoIterator>::IntoIter;
610
611 fn into_iter(self) -> Self::IntoIter {
612 self.value.into_iter()
613 }
614}
615change_detection_impl!(Res<'w, T>, T, Resource);
616impl_debug!(Res<'w, T>, Resource);
617
618/// Unique mutable borrow of a [`Resource`].
619///
620/// See the [`Resource`] documentation for usage.
621///
622/// If you need a shared borrow, use [`Res`] instead.
623///
624/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.
625/// /// This will cause a panic, but can be configured to do nothing or warn once.
626///
627/// Use [`Option<ResMut<T>>`] instead if the resource might not always exist.
628pub struct ResMut<'w, T: ?Sized + Resource> {
629 pub(crate) value: &'w mut T,
630 pub(crate) ticks: TicksMut<'w>,
631 #[cfg(feature = "track_change_detection")]
632 pub(crate) changed_by: &'w mut &'static Location<'static>,
633}
634
635impl<'w, 'a, T: Resource> IntoIterator for &'a ResMut<'w, T>
636where
637 &'a T: IntoIterator,
638{
639 type Item = <&'a T as IntoIterator>::Item;
640 type IntoIter = <&'a T as IntoIterator>::IntoIter;
641
642 fn into_iter(self) -> Self::IntoIter {
643 self.value.into_iter()
644 }
645}
646
647impl<'w, 'a, T: Resource> IntoIterator for &'a mut ResMut<'w, T>
648where
649 &'a mut T: IntoIterator,
650{
651 type Item = <&'a mut T as IntoIterator>::Item;
652 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
653
654 fn into_iter(self) -> Self::IntoIter {
655 self.set_changed();
656 self.value.into_iter()
657 }
658}
659
660change_detection_impl!(ResMut<'w, T>, T, Resource);
661change_detection_mut_impl!(ResMut<'w, T>, T, Resource);
662impl_methods!(ResMut<'w, T>, T, Resource);
663impl_debug!(ResMut<'w, T>, Resource);
664
665impl<'w, T: Resource> From<ResMut<'w, T>> for Mut<'w, T> {
666 /// Convert this `ResMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
667 /// while losing the specificity of `ResMut` for resources.
668 fn from(other: ResMut<'w, T>) -> Mut<'w, T> {
669 Mut {
670 value: other.value,
671 ticks: other.ticks,
672 #[cfg(feature = "track_change_detection")]
673 changed_by: other.changed_by,
674 }
675 }
676}
677
678/// Unique borrow of a non-[`Send`] resource.
679///
680/// Only [`Send`] resources may be accessed with the [`ResMut`] [`SystemParam`](crate::system::SystemParam). In case that the
681/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct
682/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
683/// over to another thread.
684///
685/// This [`SystemParam`](crate::system::SystemParam) fails validation if non-send resource doesn't exist.
686/// /// This will cause a panic, but can be configured to do nothing or warn once.
687///
688/// Use [`Option<NonSendMut<T>>`] instead if the resource might not always exist.
689pub struct NonSendMut<'w, T: ?Sized + 'static> {
690 pub(crate) value: &'w mut T,
691 pub(crate) ticks: TicksMut<'w>,
692 #[cfg(feature = "track_change_detection")]
693 pub(crate) changed_by: &'w mut &'static Location<'static>,
694}
695
696change_detection_impl!(NonSendMut<'w, T>, T,);
697change_detection_mut_impl!(NonSendMut<'w, T>, T,);
698impl_methods!(NonSendMut<'w, T>, T,);
699impl_debug!(NonSendMut<'w, T>,);
700
701impl<'w, T: 'static> From<NonSendMut<'w, T>> for Mut<'w, T> {
702 /// Convert this `NonSendMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
703 /// while losing the specificity of `NonSendMut`.
704 fn from(other: NonSendMut<'w, T>) -> Mut<'w, T> {
705 Mut {
706 value: other.value,
707 ticks: other.ticks,
708 #[cfg(feature = "track_change_detection")]
709 changed_by: other.changed_by,
710 }
711 }
712}
713
714/// Shared borrow of an entity's component with access to change detection.
715/// Similar to [`Mut`] but is immutable and so doesn't require unique access.
716///
717/// # Examples
718///
719/// These two systems produce the same output.
720///
721/// ```
722/// # use bevy_ecs::change_detection::DetectChanges;
723/// # use bevy_ecs::query::{Changed, With};
724/// # use bevy_ecs::system::Query;
725/// # use bevy_ecs::world::Ref;
726/// # use bevy_ecs_macros::Component;
727/// # #[derive(Component)]
728/// # struct MyComponent;
729///
730/// fn how_many_changed_1(query: Query<(), Changed<MyComponent>>) {
731/// println!("{} changed", query.iter().count());
732/// }
733///
734/// fn how_many_changed_2(query: Query<Ref<MyComponent>>) {
735/// println!("{} changed", query.iter().filter(|c| c.is_changed()).count());
736/// }
737/// ```
738pub struct Ref<'w, T: ?Sized> {
739 pub(crate) value: &'w T,
740 pub(crate) ticks: Ticks<'w>,
741 #[cfg(feature = "track_change_detection")]
742 pub(crate) changed_by: &'static Location<'static>,
743}
744
745impl<'w, T: ?Sized> Ref<'w, T> {
746 /// Returns the reference wrapped by this type. The reference is allowed to outlive `self`, which makes this method more flexible than simply borrowing `self`.
747 pub fn into_inner(self) -> &'w T {
748 self.value
749 }
750
751 /// Map `Ref` to a different type using `f`.
752 ///
753 /// This doesn't do anything else than call `f` on the wrapped value.
754 /// This is equivalent to [`Mut::map_unchanged`].
755 pub fn map<U: ?Sized>(self, f: impl FnOnce(&T) -> &U) -> Ref<'w, U> {
756 Ref {
757 value: f(self.value),
758 ticks: self.ticks,
759 #[cfg(feature = "track_change_detection")]
760 changed_by: self.changed_by,
761 }
762 }
763
764 /// Create a new `Ref` using provided values.
765 ///
766 /// This is an advanced feature, `Ref`s are designed to be _created_ by
767 /// engine-internal code and _consumed_ by end-user code.
768 ///
769 /// - `value` - The value wrapped by `Ref`.
770 /// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.
771 /// - `changed` - A [`Tick`] that stores the last time the wrapped value was changed.
772 /// - `last_run` - A [`Tick`], occurring before `this_run`, which is used
773 /// as a reference to determine whether the wrapped value is newly added or changed.
774 /// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".
775 pub fn new(
776 value: &'w T,
777 added: &'w Tick,
778 changed: &'w Tick,
779 last_run: Tick,
780 this_run: Tick,
781 #[cfg(feature = "track_change_detection")] caller: &'static Location<'static>,
782 ) -> Ref<'w, T> {
783 Ref {
784 value,
785 ticks: Ticks {
786 added,
787 changed,
788 last_run,
789 this_run,
790 },
791 #[cfg(feature = "track_change_detection")]
792 changed_by: caller,
793 }
794 }
795}
796
797impl<'w, 'a, T> IntoIterator for &'a Ref<'w, T>
798where
799 &'a T: IntoIterator,
800{
801 type Item = <&'a T as IntoIterator>::Item;
802 type IntoIter = <&'a T as IntoIterator>::IntoIter;
803
804 fn into_iter(self) -> Self::IntoIter {
805 self.value.into_iter()
806 }
807}
808change_detection_impl!(Ref<'w, T>, T,);
809impl_debug!(Ref<'w, T>,);
810
811/// Unique mutable borrow of an entity's component or of a resource.
812///
813/// This can be used in queries to opt into change detection on both their mutable and immutable forms, as opposed to
814/// `&mut T`, which only provides access to change detection while in its mutable form:
815///
816/// ```rust
817/// # use bevy_ecs::prelude::*;
818/// # use bevy_ecs::query::QueryData;
819/// #
820/// #[derive(Component, Clone)]
821/// struct Name(String);
822///
823/// #[derive(Component, Clone, Copy)]
824/// struct Health(f32);
825///
826/// #[derive(Component, Clone, Copy)]
827/// struct Position {
828/// x: f32,
829/// y: f32,
830/// };
831///
832/// #[derive(Component, Clone, Copy)]
833/// struct Player {
834/// id: usize,
835/// };
836///
837/// #[derive(QueryData)]
838/// #[query_data(mutable)]
839/// struct PlayerQuery {
840/// id: &'static Player,
841///
842/// // Reacting to `PlayerName` changes is expensive, so we need to enable change detection when reading it.
843/// name: Mut<'static, Name>,
844///
845/// health: &'static mut Health,
846/// position: &'static mut Position,
847/// }
848///
849/// fn update_player_avatars(players_query: Query<PlayerQuery>) {
850/// // The item returned by the iterator is of type `PlayerQueryReadOnlyItem`.
851/// for player in players_query.iter() {
852/// if player.name.is_changed() {
853/// // Update the player's name. This clones a String, and so is more expensive.
854/// update_player_name(player.id, player.name.clone());
855/// }
856///
857/// // Update the health bar.
858/// update_player_health(player.id, *player.health);
859///
860/// // Update the player's position.
861/// update_player_position(player.id, *player.position);
862/// }
863/// }
864///
865/// # bevy_ecs::system::assert_is_system(update_player_avatars);
866///
867/// # fn update_player_name(player: &Player, new_name: Name) {}
868/// # fn update_player_health(player: &Player, new_health: Health) {}
869/// # fn update_player_position(player: &Player, new_position: Position) {}
870/// ```
871pub struct Mut<'w, T: ?Sized> {
872 pub(crate) value: &'w mut T,
873 pub(crate) ticks: TicksMut<'w>,
874 #[cfg(feature = "track_change_detection")]
875 pub(crate) changed_by: &'w mut &'static Location<'static>,
876}
877
878impl<'w, T: ?Sized> Mut<'w, T> {
879 /// Creates a new change-detection enabled smart pointer.
880 /// In almost all cases you do not need to call this method manually,
881 /// as instances of `Mut` will be created by engine-internal code.
882 ///
883 /// Many use-cases of this method would be better served by [`Mut::map_unchanged`]
884 /// or [`Mut::reborrow`].
885 ///
886 /// - `value` - The value wrapped by this smart pointer.
887 /// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.
888 /// - `last_changed` - A [`Tick`] that stores the last time the wrapped value was changed.
889 /// This will be updated to the value of `change_tick` if the returned smart pointer
890 /// is modified.
891 /// - `last_run` - A [`Tick`], occurring before `this_run`, which is used
892 /// as a reference to determine whether the wrapped value is newly added or changed.
893 /// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".
894 pub fn new(
895 value: &'w mut T,
896 added: &'w mut Tick,
897 last_changed: &'w mut Tick,
898 last_run: Tick,
899 this_run: Tick,
900 #[cfg(feature = "track_change_detection")] caller: &'w mut &'static Location<'static>,
901 ) -> Self {
902 Self {
903 value,
904 ticks: TicksMut {
905 added,
906 changed: last_changed,
907 last_run,
908 this_run,
909 },
910 #[cfg(feature = "track_change_detection")]
911 changed_by: caller,
912 }
913 }
914}
915
916impl<'w, T: ?Sized> From<Mut<'w, T>> for Ref<'w, T> {
917 fn from(mut_ref: Mut<'w, T>) -> Self {
918 Self {
919 value: mut_ref.value,
920 ticks: mut_ref.ticks.into(),
921 #[cfg(feature = "track_change_detection")]
922 changed_by: mut_ref.changed_by,
923 }
924 }
925}
926
927impl<'w, 'a, T> IntoIterator for &'a Mut<'w, T>
928where
929 &'a T: IntoIterator,
930{
931 type Item = <&'a T as IntoIterator>::Item;
932 type IntoIter = <&'a T as IntoIterator>::IntoIter;
933
934 fn into_iter(self) -> Self::IntoIter {
935 self.value.into_iter()
936 }
937}
938
939impl<'w, 'a, T> IntoIterator for &'a mut Mut<'w, T>
940where
941 &'a mut T: IntoIterator,
942{
943 type Item = <&'a mut T as IntoIterator>::Item;
944 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
945
946 fn into_iter(self) -> Self::IntoIter {
947 self.set_changed();
948 self.value.into_iter()
949 }
950}
951
952change_detection_impl!(Mut<'w, T>, T,);
953change_detection_mut_impl!(Mut<'w, T>, T,);
954impl_methods!(Mut<'w, T>, T,);
955impl_debug!(Mut<'w, T>,);
956
957/// Unique mutable borrow of resources or an entity's component.
958///
959/// Similar to [`Mut`], but not generic over the component type, instead
960/// exposing the raw pointer as a `*mut ()`.
961///
962/// Usually you don't need to use this and can instead use the APIs returning a
963/// [`Mut`], but in situations where the types are not known at compile time
964/// or are defined outside of rust this can be used.
965pub struct MutUntyped<'w> {
966 pub(crate) value: PtrMut<'w>,
967 pub(crate) ticks: TicksMut<'w>,
968 #[cfg(feature = "track_change_detection")]
969 pub(crate) changed_by: &'w mut &'static Location<'static>,
970}
971
972impl<'w> MutUntyped<'w> {
973 /// Returns the pointer to the value, marking it as changed.
974 ///
975 /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).
976 #[inline]
977 pub fn into_inner(mut self) -> PtrMut<'w> {
978 self.set_changed();
979 self.value
980 }
981
982 /// Returns a [`MutUntyped`] with a smaller lifetime.
983 /// This is useful if you have `&mut MutUntyped`, but you need a `MutUntyped`.
984 #[inline]
985 pub fn reborrow(&mut self) -> MutUntyped {
986 MutUntyped {
987 value: self.value.reborrow(),
988 ticks: TicksMut {
989 added: self.ticks.added,
990 changed: self.ticks.changed,
991 last_run: self.ticks.last_run,
992 this_run: self.ticks.this_run,
993 },
994 #[cfg(feature = "track_change_detection")]
995 changed_by: self.changed_by,
996 }
997 }
998
999 /// Returns `true` if this value was changed or mutably dereferenced
1000 /// either since a specific change tick.
1001 pub fn has_changed_since(&self, tick: Tick) -> bool {
1002 self.ticks.changed.is_newer_than(tick, self.ticks.this_run)
1003 }
1004
1005 /// Returns a pointer to the value without taking ownership of this smart pointer, marking it as changed.
1006 ///
1007 /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).
1008 #[inline]
1009 pub fn as_mut(&mut self) -> PtrMut<'_> {
1010 self.set_changed();
1011 self.value.reborrow()
1012 }
1013
1014 /// Returns an immutable pointer to the value without taking ownership.
1015 #[inline]
1016 pub fn as_ref(&self) -> Ptr<'_> {
1017 self.value.as_ref()
1018 }
1019
1020 /// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value,
1021 /// without flagging a change.
1022 /// This function is the untyped equivalent of [`Mut::map_unchanged`].
1023 ///
1024 /// You should never modify the argument passed to the closure – if you want to modify the data without flagging a change, consider using [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) to make your intent explicit.
1025 ///
1026 /// If you know the type of the value you can do
1027 /// ```no_run
1028 /// # use bevy_ecs::change_detection::{Mut, MutUntyped};
1029 /// # let mut_untyped: MutUntyped = unimplemented!();
1030 /// // SAFETY: ptr is of type `u8`
1031 /// mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::<u8>() });
1032 /// ```
1033 /// If you have a [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) that you know belongs to this [`MutUntyped`],
1034 /// you can do
1035 /// ```no_run
1036 /// # use bevy_ecs::change_detection::{Mut, MutUntyped};
1037 /// # let mut_untyped: MutUntyped = unimplemented!();
1038 /// # let reflect_from_ptr: bevy_reflect::ReflectFromPtr = unimplemented!();
1039 /// // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped`
1040 /// mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_mut(ptr) });
1041 /// ```
1042 pub fn map_unchanged<T: ?Sized>(self, f: impl FnOnce(PtrMut<'w>) -> &'w mut T) -> Mut<'w, T> {
1043 Mut {
1044 value: f(self.value),
1045 ticks: self.ticks,
1046 #[cfg(feature = "track_change_detection")]
1047 changed_by: self.changed_by,
1048 }
1049 }
1050
1051 /// Transforms this [`MutUntyped`] into a [`Mut<T>`] with the same lifetime.
1052 ///
1053 /// # Safety
1054 /// - `T` must be the erased pointee type for this [`MutUntyped`].
1055 pub unsafe fn with_type<T>(self) -> Mut<'w, T> {
1056 Mut {
1057 // SAFETY: `value` is `Aligned` and caller ensures the pointee type is `T`.
1058 value: unsafe { self.value.deref_mut() },
1059 ticks: self.ticks,
1060 // SAFETY: `caller` is `Aligned`.
1061 #[cfg(feature = "track_change_detection")]
1062 changed_by: self.changed_by,
1063 }
1064 }
1065}
1066
1067impl<'w> DetectChanges for MutUntyped<'w> {
1068 #[inline]
1069 fn is_added(&self) -> bool {
1070 self.ticks
1071 .added
1072 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
1073 }
1074
1075 #[inline]
1076 fn is_changed(&self) -> bool {
1077 self.ticks
1078 .changed
1079 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
1080 }
1081
1082 #[inline]
1083 fn last_changed(&self) -> Tick {
1084 *self.ticks.changed
1085 }
1086
1087 #[inline]
1088 #[cfg(feature = "track_change_detection")]
1089 fn changed_by(&self) -> &'static Location<'static> {
1090 self.changed_by
1091 }
1092}
1093
1094impl<'w> DetectChangesMut for MutUntyped<'w> {
1095 type Inner = PtrMut<'w>;
1096
1097 #[inline]
1098 #[track_caller]
1099 fn set_changed(&mut self) {
1100 *self.ticks.changed = self.ticks.this_run;
1101 #[cfg(feature = "track_change_detection")]
1102 {
1103 *self.changed_by = Location::caller();
1104 }
1105 }
1106
1107 #[inline]
1108 #[track_caller]
1109 fn set_last_changed(&mut self, last_changed: Tick) {
1110 *self.ticks.changed = last_changed;
1111 #[cfg(feature = "track_change_detection")]
1112 {
1113 *self.changed_by = Location::caller();
1114 }
1115 }
1116
1117 #[inline]
1118 #[track_caller]
1119 fn bypass_change_detection(&mut self) -> &mut Self::Inner {
1120 &mut self.value
1121 }
1122}
1123
1124impl core::fmt::Debug for MutUntyped<'_> {
1125 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1126 f.debug_tuple("MutUntyped")
1127 .field(&self.value.as_ptr())
1128 .finish()
1129 }
1130}
1131
1132impl<'w, T> From<Mut<'w, T>> for MutUntyped<'w> {
1133 fn from(value: Mut<'w, T>) -> Self {
1134 MutUntyped {
1135 value: value.value.into(),
1136 ticks: value.ticks,
1137 #[cfg(feature = "track_change_detection")]
1138 changed_by: value.changed_by,
1139 }
1140 }
1141}
1142
1143/// A type alias to [`&'static Location<'static>`](std::panic::Location) when the `track_change_detection` feature is
1144/// enabled, and the unit type `()` when it is not.
1145///
1146/// This is primarily used in places where `#[cfg(...)]` attributes are not allowed, such as
1147/// function return types. Because unit is a zero-sized type, it is the equivalent of not using a
1148/// `Location` at all.
1149///
1150/// Please use this type sparingly: prefer normal `#[cfg(...)]` attributes when possible.
1151#[cfg(feature = "track_change_detection")]
1152pub(crate) type MaybeLocation = &'static Location<'static>;
1153
1154/// A type alias to [`&'static Location<'static>`](std::panic::Location) when the `track_change_detection` feature is
1155/// enabled, and the unit type `()` when it is not.
1156///
1157/// This is primarily used in places where `#[cfg(...)]` attributes are not allowed, such as
1158/// function return types. Because unit is a zero-sized type, it is the equivalent of not using a
1159/// `Location` at all.
1160///
1161/// Please use this type sparingly: prefer normal `#[cfg(...)]` attributes when possible.
1162#[cfg(not(feature = "track_change_detection"))]
1163pub(crate) type MaybeLocation = ();
1164
1165/// A type alias to `&UnsafeCell<&'static Location<'static>>` when the `track_change_detection`
1166/// feature is enabled, and the unit type `()` when it is not.
1167///
1168/// See [`MaybeLocation`] for further information.
1169#[cfg(feature = "track_change_detection")]
1170pub(crate) type MaybeUnsafeCellLocation<'a> = &'a UnsafeCell<&'static Location<'static>>;
1171
1172/// A type alias to `&UnsafeCell<&'static Location<'static>>` when the `track_change_detection`
1173/// feature is enabled, and the unit type `()` when it is not.
1174///
1175/// See [`MaybeLocation`] for further information.
1176#[cfg(not(feature = "track_change_detection"))]
1177pub(crate) type MaybeUnsafeCellLocation<'a> = ();
1178
1179/// A type alias to `ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>` when the
1180/// `track_change_detection` feature is enabled, and the unit type `()` when it is not.
1181///
1182/// See [`MaybeLocation`] for further information.
1183#[cfg(feature = "track_change_detection")]
1184pub(crate) type MaybeThinSlicePtrLocation<'w> =
1185 ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>;
1186
1187/// A type alias to `ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>` when the
1188/// `track_change_detection` feature is enabled, and the unit type `()` when it is not.
1189///
1190/// See [`MaybeLocation`] for further information.
1191#[cfg(not(feature = "track_change_detection"))]
1192pub(crate) type MaybeThinSlicePtrLocation<'w> = ();
1193
1194#[cfg(test)]
1195mod tests {
1196 use bevy_ecs_macros::Resource;
1197 use bevy_ptr::PtrMut;
1198 use bevy_reflect::{FromType, ReflectFromPtr};
1199 use core::ops::{Deref, DerefMut};
1200 #[cfg(feature = "track_change_detection")]
1201 use core::panic::Location;
1202
1203 use crate::{
1204 self as bevy_ecs,
1205 change_detection::{
1206 Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE,
1207 },
1208 component::{Component, ComponentTicks, Tick},
1209 system::{IntoSystem, Single, System},
1210 world::World,
1211 };
1212
1213 use super::{DetectChanges, DetectChangesMut, MutUntyped};
1214
1215 #[derive(Component, PartialEq)]
1216 struct C;
1217
1218 #[derive(Resource)]
1219 struct R;
1220
1221 #[derive(Resource, PartialEq)]
1222 struct R2(u8);
1223
1224 impl Deref for R2 {
1225 type Target = u8;
1226 fn deref(&self) -> &u8 {
1227 &self.0
1228 }
1229 }
1230
1231 impl DerefMut for R2 {
1232 fn deref_mut(&mut self) -> &mut u8 {
1233 &mut self.0
1234 }
1235 }
1236
1237 #[test]
1238 fn change_expiration() {
1239 fn change_detected(query: Option<Single<Ref<C>>>) -> bool {
1240 query.unwrap().is_changed()
1241 }
1242
1243 fn change_expired(query: Option<Single<Ref<C>>>) -> bool {
1244 query.unwrap().is_changed()
1245 }
1246
1247 let mut world = World::new();
1248
1249 // component added: 1, changed: 1
1250 world.spawn(C);
1251
1252 let mut change_detected_system = IntoSystem::into_system(change_detected);
1253 let mut change_expired_system = IntoSystem::into_system(change_expired);
1254 change_detected_system.initialize(&mut world);
1255 change_expired_system.initialize(&mut world);
1256
1257 // world: 1, system last ran: 0, component changed: 1
1258 // The spawn will be detected since it happened after the system "last ran".
1259 assert!(change_detected_system.run((), &mut world));
1260
1261 // world: 1 + MAX_CHANGE_AGE
1262 let change_tick = world.change_tick.get_mut();
1263 *change_tick = change_tick.wrapping_add(MAX_CHANGE_AGE);
1264
1265 // Both the system and component appeared `MAX_CHANGE_AGE` ticks ago.
1266 // Since we clamp things to `MAX_CHANGE_AGE` for determinism,
1267 // `ComponentTicks::is_changed` will now see `MAX_CHANGE_AGE > MAX_CHANGE_AGE`
1268 // and return `false`.
1269 assert!(!change_expired_system.run((), &mut world));
1270 }
1271
1272 #[test]
1273 fn change_tick_wraparound() {
1274 let mut world = World::new();
1275 world.last_change_tick = Tick::new(u32::MAX);
1276 *world.change_tick.get_mut() = 0;
1277
1278 // component added: 0, changed: 0
1279 world.spawn(C);
1280
1281 world.increment_change_tick();
1282
1283 // Since the world is always ahead, as long as changes can't get older than `u32::MAX` (which we ensure),
1284 // the wrapping difference will always be positive, so wraparound doesn't matter.
1285 let mut query = world.query::<Ref<C>>();
1286 assert!(query.single(&world).is_changed());
1287 }
1288
1289 #[test]
1290 fn change_tick_scan() {
1291 let mut world = World::new();
1292
1293 // component added: 1, changed: 1
1294 world.spawn(C);
1295
1296 // a bunch of stuff happens, the component is now older than `MAX_CHANGE_AGE`
1297 *world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD;
1298 let change_tick = world.change_tick();
1299
1300 let mut query = world.query::<Ref<C>>();
1301 for tracker in query.iter(&world) {
1302 let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();
1303 let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();
1304 assert!(ticks_since_insert > MAX_CHANGE_AGE);
1305 assert!(ticks_since_change > MAX_CHANGE_AGE);
1306 }
1307
1308 // scan change ticks and clamp those at risk of overflow
1309 world.check_change_ticks();
1310
1311 for tracker in query.iter(&world) {
1312 let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();
1313 let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();
1314 assert_eq!(ticks_since_insert, MAX_CHANGE_AGE);
1315 assert_eq!(ticks_since_change, MAX_CHANGE_AGE);
1316 }
1317 }
1318
1319 #[test]
1320 fn mut_from_res_mut() {
1321 let mut component_ticks = ComponentTicks {
1322 added: Tick::new(1),
1323 changed: Tick::new(2),
1324 };
1325 let ticks = TicksMut {
1326 added: &mut component_ticks.added,
1327 changed: &mut component_ticks.changed,
1328 last_run: Tick::new(3),
1329 this_run: Tick::new(4),
1330 };
1331 let mut res = R {};
1332 #[cfg(feature = "track_change_detection")]
1333 let mut caller = Location::caller();
1334
1335 let res_mut = ResMut {
1336 value: &mut res,
1337 ticks,
1338 #[cfg(feature = "track_change_detection")]
1339 changed_by: &mut caller,
1340 };
1341
1342 let into_mut: Mut<R> = res_mut.into();
1343 assert_eq!(1, into_mut.ticks.added.get());
1344 assert_eq!(2, into_mut.ticks.changed.get());
1345 assert_eq!(3, into_mut.ticks.last_run.get());
1346 assert_eq!(4, into_mut.ticks.this_run.get());
1347 }
1348
1349 #[test]
1350 fn mut_new() {
1351 let mut component_ticks = ComponentTicks {
1352 added: Tick::new(1),
1353 changed: Tick::new(3),
1354 };
1355 let mut res = R {};
1356 #[cfg(feature = "track_change_detection")]
1357 let mut caller = Location::caller();
1358
1359 let val = Mut::new(
1360 &mut res,
1361 &mut component_ticks.added,
1362 &mut component_ticks.changed,
1363 Tick::new(2), // last_run
1364 Tick::new(4), // this_run
1365 #[cfg(feature = "track_change_detection")]
1366 &mut caller,
1367 );
1368
1369 assert!(!val.is_added());
1370 assert!(val.is_changed());
1371 }
1372
1373 #[test]
1374 fn mut_from_non_send_mut() {
1375 let mut component_ticks = ComponentTicks {
1376 added: Tick::new(1),
1377 changed: Tick::new(2),
1378 };
1379 let ticks = TicksMut {
1380 added: &mut component_ticks.added,
1381 changed: &mut component_ticks.changed,
1382 last_run: Tick::new(3),
1383 this_run: Tick::new(4),
1384 };
1385 let mut res = R {};
1386 #[cfg(feature = "track_change_detection")]
1387 let mut caller = Location::caller();
1388
1389 let non_send_mut = NonSendMut {
1390 value: &mut res,
1391 ticks,
1392 #[cfg(feature = "track_change_detection")]
1393 changed_by: &mut caller,
1394 };
1395
1396 let into_mut: Mut<R> = non_send_mut.into();
1397 assert_eq!(1, into_mut.ticks.added.get());
1398 assert_eq!(2, into_mut.ticks.changed.get());
1399 assert_eq!(3, into_mut.ticks.last_run.get());
1400 assert_eq!(4, into_mut.ticks.this_run.get());
1401 }
1402
1403 #[test]
1404 fn map_mut() {
1405 use super::*;
1406 struct Outer(i64);
1407
1408 let last_run = Tick::new(2);
1409 let this_run = Tick::new(3);
1410 let mut component_ticks = ComponentTicks {
1411 added: Tick::new(1),
1412 changed: Tick::new(2),
1413 };
1414 let ticks = TicksMut {
1415 added: &mut component_ticks.added,
1416 changed: &mut component_ticks.changed,
1417 last_run,
1418 this_run,
1419 };
1420
1421 let mut outer = Outer(0);
1422 #[cfg(feature = "track_change_detection")]
1423 let mut caller = Location::caller();
1424
1425 let ptr = Mut {
1426 value: &mut outer,
1427 ticks,
1428 #[cfg(feature = "track_change_detection")]
1429 changed_by: &mut caller,
1430 };
1431 assert!(!ptr.is_changed());
1432
1433 // Perform a mapping operation.
1434 let mut inner = ptr.map_unchanged(|x| &mut x.0);
1435 assert!(!inner.is_changed());
1436
1437 // Mutate the inner value.
1438 *inner = 64;
1439 assert!(inner.is_changed());
1440 // Modifying one field of a component should flag a change for the entire component.
1441 assert!(component_ticks.is_changed(last_run, this_run));
1442 }
1443
1444 #[test]
1445 fn set_if_neq() {
1446 let mut world = World::new();
1447
1448 world.insert_resource(R2(0));
1449 // Resources are Changed when first added
1450 world.increment_change_tick();
1451 // This is required to update world::last_change_tick
1452 world.clear_trackers();
1453
1454 let mut r = world.resource_mut::<R2>();
1455 assert!(!r.is_changed(), "Resource must begin unchanged.");
1456
1457 r.set_if_neq(R2(0));
1458 assert!(
1459 !r.is_changed(),
1460 "Resource must not be changed after setting to the same value."
1461 );
1462
1463 r.set_if_neq(R2(3));
1464 assert!(
1465 r.is_changed(),
1466 "Resource must be changed after setting to a different value."
1467 );
1468 }
1469
1470 #[test]
1471 fn as_deref_mut() {
1472 let mut world = World::new();
1473
1474 world.insert_resource(R2(0));
1475 // Resources are Changed when first added
1476 world.increment_change_tick();
1477 // This is required to update world::last_change_tick
1478 world.clear_trackers();
1479
1480 let mut r = world.resource_mut::<R2>();
1481 assert!(!r.is_changed(), "Resource must begin unchanged.");
1482
1483 let mut r = r.as_deref_mut();
1484 assert!(
1485 !r.is_changed(),
1486 "Dereferencing should not mark the item as changed yet"
1487 );
1488
1489 r.set_if_neq(3);
1490 assert!(
1491 r.is_changed(),
1492 "Resource must be changed after setting to a different value."
1493 );
1494 }
1495
1496 #[test]
1497 fn mut_untyped_to_reflect() {
1498 let last_run = Tick::new(2);
1499 let this_run = Tick::new(3);
1500 let mut component_ticks = ComponentTicks {
1501 added: Tick::new(1),
1502 changed: Tick::new(2),
1503 };
1504 let ticks = TicksMut {
1505 added: &mut component_ticks.added,
1506 changed: &mut component_ticks.changed,
1507 last_run,
1508 this_run,
1509 };
1510
1511 let mut value: i32 = 5;
1512 #[cfg(feature = "track_change_detection")]
1513 let mut caller = Location::caller();
1514
1515 let value = MutUntyped {
1516 value: PtrMut::from(&mut value),
1517 ticks,
1518 #[cfg(feature = "track_change_detection")]
1519 changed_by: &mut caller,
1520 };
1521
1522 let reflect_from_ptr = <ReflectFromPtr as FromType<i32>>::from_type();
1523
1524 let mut new = value.map_unchanged(|ptr| {
1525 // SAFETY: The underlying type of `ptr` matches `reflect_from_ptr`.
1526 let value = unsafe { reflect_from_ptr.as_reflect_mut(ptr) };
1527 value
1528 });
1529
1530 assert!(!new.is_changed());
1531
1532 new.reflect_mut();
1533
1534 assert!(new.is_changed());
1535 }
1536
1537 #[test]
1538 fn mut_untyped_from_mut() {
1539 let mut component_ticks = ComponentTicks {
1540 added: Tick::new(1),
1541 changed: Tick::new(2),
1542 };
1543 let ticks = TicksMut {
1544 added: &mut component_ticks.added,
1545 changed: &mut component_ticks.changed,
1546 last_run: Tick::new(3),
1547 this_run: Tick::new(4),
1548 };
1549 let mut c = C {};
1550 #[cfg(feature = "track_change_detection")]
1551 let mut caller = Location::caller();
1552
1553 let mut_typed = Mut {
1554 value: &mut c,
1555 ticks,
1556 #[cfg(feature = "track_change_detection")]
1557 changed_by: &mut caller,
1558 };
1559
1560 let into_mut: MutUntyped = mut_typed.into();
1561 assert_eq!(1, into_mut.ticks.added.get());
1562 assert_eq!(2, into_mut.ticks.changed.get());
1563 assert_eq!(3, into_mut.ticks.last_run.get());
1564 assert_eq!(4, into_mut.ticks.this_run.get());
1565 }
1566}