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 resource::Resource,
7};
8use alloc::borrow::ToOwned;
9use bevy_ptr::{Ptr, UnsafeCellDeref};
10#[cfg(feature = "bevy_reflect")]
11use bevy_reflect::Reflect;
12use core::{
13 marker::PhantomData,
14 mem,
15 ops::{Deref, DerefMut},
16 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 /// Returns the change tick recording the time this data was added.
75 fn added(&self) -> Tick;
76
77 /// The location that last caused this to change.
78 fn changed_by(&self) -> MaybeLocation;
79}
80
81/// Types that implement reliable change detection.
82///
83/// ## Example
84/// Using types that implement [`DetectChangesMut`], such as [`ResMut`], provide
85/// a way to query if a value has been mutated in another system.
86/// Normally change detection is triggered by either [`DerefMut`] or [`AsMut`], however
87/// it can be manually triggered via [`set_changed`](DetectChangesMut::set_changed).
88///
89/// To ensure that changes are only triggered when the value actually differs,
90/// check if the value would change before assignment, such as by checking that `new != old`.
91/// You must be *sure* that you are not mutably dereferencing in this process.
92///
93/// [`set_if_neq`](DetectChangesMut::set_if_neq) is a helper
94/// method for this common functionality.
95///
96/// ```
97/// use bevy_ecs::prelude::*;
98///
99/// #[derive(Resource)]
100/// struct MyResource(u32);
101///
102/// fn my_system(mut resource: ResMut<MyResource>) {
103/// if resource.is_changed() {
104/// println!("My resource was mutated!");
105/// }
106///
107/// resource.0 = 42; // triggers change detection via [`DerefMut`]
108/// }
109/// ```
110pub trait DetectChangesMut: DetectChanges {
111 /// The type contained within this smart pointer
112 ///
113 /// For example, for `ResMut<T>` this would be `T`.
114 type Inner: ?Sized;
115
116 /// Flags this value as having been changed.
117 ///
118 /// Mutably accessing this smart pointer will automatically flag this value as having been changed.
119 /// However, mutation through interior mutability requires manual reporting.
120 ///
121 /// **Note**: This operation cannot be undone.
122 fn set_changed(&mut self);
123
124 /// Flags this value as having been added.
125 ///
126 /// It is not normally necessary to call this method.
127 /// The 'added' tick is set when the value is first added,
128 /// and is not normally changed afterwards.
129 ///
130 /// **Note**: This operation cannot be undone.
131 fn set_added(&mut self);
132
133 /// Manually sets the change tick recording the time when this data was last mutated.
134 ///
135 /// # Warning
136 /// This is a complex and error-prone operation, primarily intended for use with rollback networking strategies.
137 /// If you merely want to flag this data as changed, use [`set_changed`](DetectChangesMut::set_changed) instead.
138 /// If you want to avoid triggering change detection, use [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) instead.
139 fn set_last_changed(&mut self, last_changed: Tick);
140
141 /// Manually sets the added tick recording the time when this data was last added.
142 ///
143 /// # Warning
144 /// The caveats of [`set_last_changed`](DetectChangesMut::set_last_changed) apply. This modifies both the added and changed ticks together.
145 fn set_last_added(&mut self, last_added: Tick);
146
147 /// Manually bypasses change detection, allowing you to mutate the underlying value without updating the change tick.
148 ///
149 /// # Warning
150 /// This is a risky operation, that can have unexpected consequences on any system relying on this code.
151 /// However, it can be an essential escape hatch when, for example,
152 /// you are trying to synchronize representations using change detection and need to avoid infinite recursion.
153 fn bypass_change_detection(&mut self) -> &mut Self::Inner;
154
155 /// Overwrites this smart pointer with the given value, if and only if `*self != value`.
156 /// Returns `true` if the value was overwritten, and returns `false` if it was not.
157 ///
158 /// This is useful to ensure change detection is only triggered when the underlying value
159 /// changes, instead of every time it is mutably accessed.
160 ///
161 /// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
162 /// then consider applying a `map_unchanged` beforehand to allow changing only the relevant
163 /// field and prevent unnecessary copying and cloning.
164 /// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
165 /// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
166 ///
167 /// If you need the previous value, use [`replace_if_neq`](DetectChangesMut::replace_if_neq).
168 ///
169 /// # Examples
170 ///
171 /// ```
172 /// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};
173 /// #[derive(Resource, PartialEq, Eq)]
174 /// pub struct Score(u32);
175 ///
176 /// fn reset_score(mut score: ResMut<Score>) {
177 /// // Set the score to zero, unless it is already zero.
178 /// score.set_if_neq(Score(0));
179 /// }
180 /// # let mut world = World::new();
181 /// # world.insert_resource(Score(1));
182 /// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
183 /// # score_changed.initialize(&mut world);
184 /// # score_changed.run((), &mut world);
185 /// #
186 /// # let mut schedule = Schedule::default();
187 /// # schedule.add_systems(reset_score);
188 /// #
189 /// # // first time `reset_score` runs, the score is changed.
190 /// # schedule.run(&mut world);
191 /// # assert!(score_changed.run((), &mut world).unwrap());
192 /// # // second time `reset_score` runs, the score is not changed.
193 /// # schedule.run(&mut world);
194 /// # assert!(!score_changed.run((), &mut world).unwrap());
195 /// ```
196 #[inline]
197 #[track_caller]
198 fn set_if_neq(&mut self, value: Self::Inner) -> bool
199 where
200 Self::Inner: Sized + PartialEq,
201 {
202 let old = self.bypass_change_detection();
203 if *old != value {
204 *old = value;
205 self.set_changed();
206 true
207 } else {
208 false
209 }
210 }
211
212 /// Overwrites this smart pointer with the given value, if and only if `*self != value`,
213 /// returning the previous value if this occurs.
214 ///
215 /// This is useful to ensure change detection is only triggered when the underlying value
216 /// changes, instead of every time it is mutably accessed.
217 ///
218 /// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,
219 /// then consider applying a [`map_unchanged`](Mut::map_unchanged) beforehand to allow
220 /// changing only the relevant field and prevent unnecessary copying and cloning.
221 /// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],
222 /// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example
223 ///
224 /// If you don't need the previous value, use [`set_if_neq`](DetectChangesMut::set_if_neq).
225 ///
226 /// # Examples
227 ///
228 /// ```
229 /// # use bevy_ecs::{prelude::*, schedule::common_conditions::{resource_changed, on_event}};
230 /// #[derive(Resource, PartialEq, Eq)]
231 /// pub struct Score(u32);
232 ///
233 /// #[derive(Message, PartialEq, Eq)]
234 /// pub struct ScoreChanged {
235 /// current: u32,
236 /// previous: u32,
237 /// }
238 ///
239 /// fn reset_score(mut score: ResMut<Score>, mut score_changed: MessageWriter<ScoreChanged>) {
240 /// // Set the score to zero, unless it is already zero.
241 /// let new_score = 0;
242 /// if let Some(Score(previous_score)) = score.replace_if_neq(Score(new_score)) {
243 /// // If `score` change, emit a `ScoreChanged` event.
244 /// score_changed.write(ScoreChanged {
245 /// current: new_score,
246 /// previous: previous_score,
247 /// });
248 /// }
249 /// }
250 /// # let mut world = World::new();
251 /// # world.insert_resource(Events::<ScoreChanged>::default());
252 /// # world.insert_resource(Score(1));
253 /// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
254 /// # score_changed.initialize(&mut world);
255 /// # score_changed.run((), &mut world);
256 /// #
257 /// # let mut score_changed_event = IntoSystem::into_system(on_event::<ScoreChanged>);
258 /// # score_changed_event.initialize(&mut world);
259 /// # score_changed_event.run((), &mut world);
260 /// #
261 /// # let mut schedule = Schedule::default();
262 /// # schedule.add_systems(reset_score);
263 /// #
264 /// # // first time `reset_score` runs, the score is changed.
265 /// # schedule.run(&mut world);
266 /// # assert!(score_changed.run((), &mut world).unwrap());
267 /// # assert!(score_changed_event.run((), &mut world).unwrap());
268 /// # // second time `reset_score` runs, the score is not changed.
269 /// # schedule.run(&mut world);
270 /// # assert!(!score_changed.run((), &mut world).unwrap());
271 /// # assert!(!score_changed_event.run((), &mut world).unwrap());
272 /// ```
273 #[inline]
274 #[must_use = "If you don't need to handle the previous value, use `set_if_neq` instead."]
275 fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>
276 where
277 Self::Inner: Sized + PartialEq,
278 {
279 let old = self.bypass_change_detection();
280 if *old != value {
281 let previous = mem::replace(old, value);
282 self.set_changed();
283 Some(previous)
284 } else {
285 None
286 }
287 }
288
289 /// Overwrites this smart pointer with a clone of the given value, if and only if `*self != value`.
290 /// Returns `true` if the value was overwritten, and returns `false` if it was not.
291 ///
292 /// This method is useful when the caller only has a borrowed form of `Inner`,
293 /// e.g. when writing a `&str` into a `Mut<String>`.
294 ///
295 /// # Examples
296 /// ```
297 /// # extern crate alloc;
298 /// # use alloc::borrow::ToOwned;
299 /// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};
300 /// #[derive(Resource)]
301 /// pub struct Message(String);
302 ///
303 /// fn update_message(mut message: ResMut<Message>) {
304 /// // Set the score to zero, unless it is already zero.
305 /// ResMut::map_unchanged(message, |Message(msg)| msg).clone_from_if_neq("another string");
306 /// }
307 /// # let mut world = World::new();
308 /// # world.insert_resource(Message("initial string".into()));
309 /// # let mut message_changed = IntoSystem::into_system(resource_changed::<Message>);
310 /// # message_changed.initialize(&mut world);
311 /// # message_changed.run((), &mut world);
312 /// #
313 /// # let mut schedule = Schedule::default();
314 /// # schedule.add_systems(update_message);
315 /// #
316 /// # // first time `reset_score` runs, the score is changed.
317 /// # schedule.run(&mut world);
318 /// # assert!(message_changed.run((), &mut world).unwrap());
319 /// # // second time `reset_score` runs, the score is not changed.
320 /// # schedule.run(&mut world);
321 /// # assert!(!message_changed.run((), &mut world).unwrap());
322 /// ```
323 fn clone_from_if_neq<T>(&mut self, value: &T) -> bool
324 where
325 T: ToOwned<Owned = Self::Inner> + ?Sized,
326 Self::Inner: PartialEq<T>,
327 {
328 let old = self.bypass_change_detection();
329 if old != value {
330 value.clone_into(old);
331 self.set_changed();
332 true
333 } else {
334 false
335 }
336 }
337}
338
339macro_rules! change_detection_impl {
340 ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
341 impl<$($generics),* : ?Sized $(+ $traits)?> DetectChanges for $name<$($generics),*> {
342 #[inline]
343 fn is_added(&self) -> bool {
344 self.ticks
345 .added
346 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
347 }
348
349 #[inline]
350 fn is_changed(&self) -> bool {
351 self.ticks
352 .changed
353 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
354 }
355
356 #[inline]
357 fn last_changed(&self) -> Tick {
358 *self.ticks.changed
359 }
360
361 #[inline]
362 fn added(&self) -> Tick {
363 *self.ticks.added
364 }
365
366 #[inline]
367 fn changed_by(&self) -> MaybeLocation {
368 self.changed_by.copied()
369 }
370 }
371
372 impl<$($generics),*: ?Sized $(+ $traits)?> Deref for $name<$($generics),*> {
373 type Target = $target;
374
375 #[inline]
376 fn deref(&self) -> &Self::Target {
377 self.value
378 }
379 }
380
381 impl<$($generics),* $(: $traits)?> AsRef<$target> for $name<$($generics),*> {
382 #[inline]
383 fn as_ref(&self) -> &$target {
384 self.deref()
385 }
386 }
387 }
388}
389
390macro_rules! change_detection_mut_impl {
391 ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
392 impl<$($generics),* : ?Sized $(+ $traits)?> DetectChangesMut for $name<$($generics),*> {
393 type Inner = $target;
394
395 #[inline]
396 #[track_caller]
397 fn set_changed(&mut self) {
398 *self.ticks.changed = self.ticks.this_run;
399 self.changed_by.assign(MaybeLocation::caller());
400 }
401
402 #[inline]
403 #[track_caller]
404 fn set_added(&mut self) {
405 *self.ticks.changed = self.ticks.this_run;
406 *self.ticks.added = self.ticks.this_run;
407 self.changed_by.assign(MaybeLocation::caller());
408 }
409
410 #[inline]
411 #[track_caller]
412 fn set_last_changed(&mut self, last_changed: Tick) {
413 *self.ticks.changed = last_changed;
414 self.changed_by.assign(MaybeLocation::caller());
415 }
416
417 #[inline]
418 #[track_caller]
419 fn set_last_added(&mut self, last_added: Tick) {
420 *self.ticks.added = last_added;
421 *self.ticks.changed = last_added;
422 self.changed_by.assign(MaybeLocation::caller());
423 }
424
425 #[inline]
426 fn bypass_change_detection(&mut self) -> &mut Self::Inner {
427 self.value
428 }
429 }
430
431 impl<$($generics),* : ?Sized $(+ $traits)?> DerefMut for $name<$($generics),*> {
432 #[inline]
433 #[track_caller]
434 fn deref_mut(&mut self) -> &mut Self::Target {
435 self.set_changed();
436 self.changed_by.assign(MaybeLocation::caller());
437 self.value
438 }
439 }
440
441 impl<$($generics),* $(: $traits)?> AsMut<$target> for $name<$($generics),*> {
442 #[inline]
443 fn as_mut(&mut self) -> &mut $target {
444 self.deref_mut()
445 }
446 }
447 };
448}
449
450macro_rules! impl_methods {
451 ($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {
452 impl<$($generics),* : ?Sized $(+ $traits)?> $name<$($generics),*> {
453 /// Consume `self` and return a mutable reference to the
454 /// contained value while marking `self` as "changed".
455 #[inline]
456 pub fn into_inner(mut self) -> &'w mut $target {
457 self.set_changed();
458 self.value
459 }
460
461 /// Returns a `Mut<>` with a smaller lifetime.
462 /// This is useful if you have `&mut
463 #[doc = stringify!($name)]
464 /// <T>`, but you need a `Mut<T>`.
465 pub fn reborrow(&mut self) -> Mut<'_, $target> {
466 Mut {
467 value: self.value,
468 ticks: TicksMut {
469 added: self.ticks.added,
470 changed: self.ticks.changed,
471 last_run: self.ticks.last_run,
472 this_run: self.ticks.this_run,
473 },
474 changed_by: self.changed_by.as_deref_mut(),
475 }
476 }
477
478 /// Maps to an inner value by applying a function to the contained reference, without flagging a change.
479 ///
480 /// You should never modify the argument passed to the closure -- if you want to modify the data
481 /// without flagging a change, consider using [`DetectChangesMut::bypass_change_detection`] to make your intent explicit.
482 ///
483 /// ```
484 /// # use bevy_ecs::prelude::*;
485 /// # #[derive(PartialEq)] pub struct Vec2;
486 /// # impl Vec2 { pub const ZERO: Self = Self; }
487 /// # #[derive(Component)] pub struct Transform { translation: Vec2 }
488 /// // When run, zeroes the translation of every entity.
489 /// fn reset_positions(mut transforms: Query<&mut Transform>) {
490 /// for transform in &mut transforms {
491 /// // We pinky promise not to modify `t` within the closure.
492 /// // Breaking this promise will result in logic errors, but will never cause undefined behavior.
493 /// let mut translation = transform.map_unchanged(|t| &mut t.translation);
494 /// // Only reset the translation if it isn't already zero;
495 /// translation.set_if_neq(Vec2::ZERO);
496 /// }
497 /// }
498 /// # bevy_ecs::system::assert_is_system(reset_positions);
499 /// ```
500 pub fn map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> &mut U) -> Mut<'w, U> {
501 Mut {
502 value: f(self.value),
503 ticks: self.ticks,
504 changed_by: self.changed_by,
505 }
506 }
507
508 /// Optionally maps to an inner value by applying a function to the contained reference.
509 /// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.
510 ///
511 /// As with `map_unchanged`, you should never modify the argument passed to the closure.
512 pub fn filter_map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> Option<&mut U>) -> Option<Mut<'w, U>> {
513 let value = f(self.value);
514 value.map(|value| Mut {
515 value,
516 ticks: self.ticks,
517 changed_by: self.changed_by,
518 })
519 }
520
521 /// Optionally maps to an inner value by applying a function to the contained reference, returns an error on failure.
522 /// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.
523 ///
524 /// As with `map_unchanged`, you should never modify the argument passed to the closure.
525 pub fn try_map_unchanged<U: ?Sized, E>(self, f: impl FnOnce(&mut $target) -> Result<&mut U, E>) -> Result<Mut<'w, U>, E> {
526 let value = f(self.value);
527 value.map(|value| Mut {
528 value,
529 ticks: self.ticks,
530 changed_by: self.changed_by,
531 })
532 }
533
534 /// Allows you access to the dereferenced value of this pointer without immediately
535 /// triggering change detection.
536 pub fn as_deref_mut(&mut self) -> Mut<'_, <$target as Deref>::Target>
537 where $target: DerefMut
538 {
539 self.reborrow().map_unchanged(|v| v.deref_mut())
540 }
541
542 }
543 };
544}
545
546macro_rules! impl_debug {
547 ($name:ident < $( $generics:tt ),+ >, $($traits:ident)?) => {
548 impl<$($generics),* : ?Sized $(+ $traits)?> core::fmt::Debug for $name<$($generics),*>
549 where T: core::fmt::Debug
550 {
551 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
552 f.debug_tuple(stringify!($name))
553 .field(&self.value)
554 .finish()
555 }
556 }
557
558 };
559}
560
561#[derive(Clone)]
562pub(crate) struct Ticks<'w> {
563 pub(crate) added: &'w Tick,
564 pub(crate) changed: &'w Tick,
565 pub(crate) last_run: Tick,
566 pub(crate) this_run: Tick,
567}
568
569impl<'w> Ticks<'w> {
570 /// # Safety
571 /// This should never alias the underlying ticks with a mutable one such as `TicksMut`.
572 #[inline]
573 pub(crate) unsafe fn from_tick_cells(
574 cells: TickCells<'w>,
575 last_run: Tick,
576 this_run: Tick,
577 ) -> Self {
578 Self {
579 // SAFETY: Caller ensures there is no mutable access to the cell.
580 added: unsafe { cells.added.deref() },
581 // SAFETY: Caller ensures there is no mutable access to the cell.
582 changed: unsafe { cells.changed.deref() },
583 last_run,
584 this_run,
585 }
586 }
587}
588
589pub(crate) struct TicksMut<'w> {
590 pub(crate) added: &'w mut Tick,
591 pub(crate) changed: &'w mut Tick,
592 pub(crate) last_run: Tick,
593 pub(crate) this_run: Tick,
594}
595
596impl<'w> TicksMut<'w> {
597 /// # Safety
598 /// This should never alias the underlying ticks. All access must be unique.
599 #[inline]
600 pub(crate) unsafe fn from_tick_cells(
601 cells: TickCells<'w>,
602 last_run: Tick,
603 this_run: Tick,
604 ) -> Self {
605 Self {
606 // SAFETY: Caller ensures there is no alias to the cell.
607 added: unsafe { cells.added.deref_mut() },
608 // SAFETY: Caller ensures there is no alias to the cell.
609 changed: unsafe { cells.changed.deref_mut() },
610 last_run,
611 this_run,
612 }
613 }
614}
615
616impl<'w> From<TicksMut<'w>> for Ticks<'w> {
617 fn from(ticks: TicksMut<'w>) -> Self {
618 Ticks {
619 added: ticks.added,
620 changed: ticks.changed,
621 last_run: ticks.last_run,
622 this_run: ticks.this_run,
623 }
624 }
625}
626
627/// Shared borrow of a [`Resource`].
628///
629/// See the [`Resource`] documentation for usage.
630///
631/// If you need a unique mutable borrow, use [`ResMut`] instead.
632///
633/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.
634/// This will cause a panic, but can be configured to do nothing or warn once.
635///
636/// Use [`Option<Res<T>>`] instead if the resource might not always exist.
637pub struct Res<'w, T: ?Sized + Resource> {
638 pub(crate) value: &'w T,
639 pub(crate) ticks: Ticks<'w>,
640 pub(crate) changed_by: MaybeLocation<&'w &'static Location<'static>>,
641}
642
643impl<'w, T: Resource> Res<'w, T> {
644 /// Copies a reference to a resource.
645 ///
646 /// Note that unless you actually need an instance of `Res<T>`, you should
647 /// prefer to just convert it to `&T` which can be freely copied.
648 #[expect(
649 clippy::should_implement_trait,
650 reason = "As this struct derefs to the inner resource, a `Clone` trait implementation would interfere with the common case of cloning the inner content. (A similar case of this happening can be found with `std::cell::Ref::clone()`.)"
651 )]
652 pub fn clone(this: &Self) -> Self {
653 Self {
654 value: this.value,
655 ticks: this.ticks.clone(),
656 changed_by: this.changed_by,
657 }
658 }
659
660 /// Due to lifetime limitations of the `Deref` trait, this method can be used to obtain a
661 /// reference of the [`Resource`] with a lifetime bound to `'w` instead of the lifetime of the
662 /// struct itself.
663 pub fn into_inner(self) -> &'w T {
664 self.value
665 }
666}
667
668impl<'w, T: Resource> From<ResMut<'w, T>> for Res<'w, T> {
669 fn from(res: ResMut<'w, T>) -> Self {
670 Self {
671 value: res.value,
672 ticks: res.ticks.into(),
673 changed_by: res.changed_by.map(|changed_by| &*changed_by),
674 }
675 }
676}
677
678impl<'w, T: Resource> From<Res<'w, T>> for Ref<'w, T> {
679 /// Convert a `Res` into a `Ref`. This allows keeping the change-detection feature of `Ref`
680 /// while losing the specificity of `Res` for resources.
681 fn from(res: Res<'w, T>) -> Self {
682 Self {
683 value: res.value,
684 ticks: res.ticks,
685 changed_by: res.changed_by,
686 }
687 }
688}
689
690impl<'w, 'a, T: Resource> IntoIterator for &'a Res<'w, T>
691where
692 &'a T: IntoIterator,
693{
694 type Item = <&'a T as IntoIterator>::Item;
695 type IntoIter = <&'a T as IntoIterator>::IntoIter;
696
697 fn into_iter(self) -> Self::IntoIter {
698 self.value.into_iter()
699 }
700}
701change_detection_impl!(Res<'w, T>, T, Resource);
702impl_debug!(Res<'w, T>, Resource);
703
704/// Unique mutable borrow of a [`Resource`].
705///
706/// See the [`Resource`] documentation for usage.
707///
708/// If you need a shared borrow, use [`Res`] instead.
709///
710/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.
711/// This will cause a panic, but can be configured to do nothing or warn once.
712///
713/// Use [`Option<ResMut<T>>`] instead if the resource might not always exist.
714pub struct ResMut<'w, T: ?Sized + Resource> {
715 pub(crate) value: &'w mut T,
716 pub(crate) ticks: TicksMut<'w>,
717 pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
718}
719
720impl<'w, 'a, T: Resource> IntoIterator for &'a ResMut<'w, T>
721where
722 &'a T: IntoIterator,
723{
724 type Item = <&'a T as IntoIterator>::Item;
725 type IntoIter = <&'a T as IntoIterator>::IntoIter;
726
727 fn into_iter(self) -> Self::IntoIter {
728 self.value.into_iter()
729 }
730}
731
732impl<'w, 'a, T: Resource> IntoIterator for &'a mut ResMut<'w, T>
733where
734 &'a mut T: IntoIterator,
735{
736 type Item = <&'a mut T as IntoIterator>::Item;
737 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
738
739 fn into_iter(self) -> Self::IntoIter {
740 self.set_changed();
741 self.value.into_iter()
742 }
743}
744
745change_detection_impl!(ResMut<'w, T>, T, Resource);
746change_detection_mut_impl!(ResMut<'w, T>, T, Resource);
747impl_methods!(ResMut<'w, T>, T, Resource);
748impl_debug!(ResMut<'w, T>, Resource);
749
750impl<'w, T: Resource> From<ResMut<'w, T>> for Mut<'w, T> {
751 /// Convert this `ResMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
752 /// while losing the specificity of `ResMut` for resources.
753 fn from(other: ResMut<'w, T>) -> Mut<'w, T> {
754 Mut {
755 value: other.value,
756 ticks: other.ticks,
757 changed_by: other.changed_by,
758 }
759 }
760}
761
762/// Unique borrow of a non-[`Send`] resource.
763///
764/// Only [`Send`] resources may be accessed with the [`ResMut`] [`SystemParam`](crate::system::SystemParam). In case that the
765/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct
766/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
767/// over to another thread.
768///
769/// This [`SystemParam`](crate::system::SystemParam) fails validation if non-send resource doesn't exist.
770/// This will cause a panic, but can be configured to do nothing or warn once.
771///
772/// Use [`Option<NonSendMut<T>>`] instead if the resource might not always exist.
773pub struct NonSendMut<'w, T: ?Sized + 'static> {
774 pub(crate) value: &'w mut T,
775 pub(crate) ticks: TicksMut<'w>,
776 pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
777}
778
779change_detection_impl!(NonSendMut<'w, T>, T,);
780change_detection_mut_impl!(NonSendMut<'w, T>, T,);
781impl_methods!(NonSendMut<'w, T>, T,);
782impl_debug!(NonSendMut<'w, T>,);
783
784impl<'w, T: 'static> From<NonSendMut<'w, T>> for Mut<'w, T> {
785 /// Convert this `NonSendMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
786 /// while losing the specificity of `NonSendMut`.
787 fn from(other: NonSendMut<'w, T>) -> Mut<'w, T> {
788 Mut {
789 value: other.value,
790 ticks: other.ticks,
791 changed_by: other.changed_by,
792 }
793 }
794}
795
796/// Shared borrow of an entity's component with access to change detection.
797/// Similar to [`Mut`] but is immutable and so doesn't require unique access.
798///
799/// # Examples
800///
801/// These two systems produce the same output.
802///
803/// ```
804/// # use bevy_ecs::change_detection::DetectChanges;
805/// # use bevy_ecs::query::{Changed, With};
806/// # use bevy_ecs::system::Query;
807/// # use bevy_ecs::world::Ref;
808/// # use bevy_ecs_macros::Component;
809/// # #[derive(Component)]
810/// # struct MyComponent;
811///
812/// fn how_many_changed_1(query: Query<(), Changed<MyComponent>>) {
813/// println!("{} changed", query.iter().count());
814/// }
815///
816/// fn how_many_changed_2(query: Query<Ref<MyComponent>>) {
817/// println!("{} changed", query.iter().filter(|c| c.is_changed()).count());
818/// }
819/// ```
820pub struct Ref<'w, T: ?Sized> {
821 pub(crate) value: &'w T,
822 pub(crate) ticks: Ticks<'w>,
823 pub(crate) changed_by: MaybeLocation<&'w &'static Location<'static>>,
824}
825
826impl<'w, T: ?Sized> Ref<'w, T> {
827 /// Returns the reference wrapped by this type. The reference is allowed to outlive `self`, which makes this method more flexible than simply borrowing `self`.
828 pub fn into_inner(self) -> &'w T {
829 self.value
830 }
831
832 /// Map `Ref` to a different type using `f`.
833 ///
834 /// This doesn't do anything else than call `f` on the wrapped value.
835 /// This is equivalent to [`Mut::map_unchanged`].
836 pub fn map<U: ?Sized>(self, f: impl FnOnce(&T) -> &U) -> Ref<'w, U> {
837 Ref {
838 value: f(self.value),
839 ticks: self.ticks,
840 changed_by: self.changed_by,
841 }
842 }
843
844 /// Create a new `Ref` using provided values.
845 ///
846 /// This is an advanced feature, `Ref`s are designed to be _created_ by
847 /// engine-internal code and _consumed_ by end-user code.
848 ///
849 /// - `value` - The value wrapped by `Ref`.
850 /// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.
851 /// - `changed` - A [`Tick`] that stores the last time the wrapped value was changed.
852 /// - `last_run` - A [`Tick`], occurring before `this_run`, which is used
853 /// as a reference to determine whether the wrapped value is newly added or changed.
854 /// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".
855 pub fn new(
856 value: &'w T,
857 added: &'w Tick,
858 changed: &'w Tick,
859 last_run: Tick,
860 this_run: Tick,
861 caller: MaybeLocation<&'w &'static Location<'static>>,
862 ) -> Ref<'w, T> {
863 Ref {
864 value,
865 ticks: Ticks {
866 added,
867 changed,
868 last_run,
869 this_run,
870 },
871 changed_by: caller,
872 }
873 }
874
875 /// Overwrite the `last_run` and `this_run` tick that are used for change detection.
876 ///
877 /// This is an advanced feature. `Ref`s are usually _created_ by engine-internal code and
878 /// _consumed_ by end-user code.
879 pub fn set_ticks(&mut self, last_run: Tick, this_run: Tick) {
880 self.ticks.last_run = last_run;
881 self.ticks.this_run = this_run;
882 }
883}
884
885impl<'w, 'a, T> IntoIterator for &'a Ref<'w, T>
886where
887 &'a T: IntoIterator,
888{
889 type Item = <&'a T as IntoIterator>::Item;
890 type IntoIter = <&'a T as IntoIterator>::IntoIter;
891
892 fn into_iter(self) -> Self::IntoIter {
893 self.value.into_iter()
894 }
895}
896change_detection_impl!(Ref<'w, T>, T,);
897impl_debug!(Ref<'w, T>,);
898
899/// Unique mutable borrow of an entity's component or of a resource.
900///
901/// This can be used in queries to access change detection from immutable query methods, as opposed
902/// to `&mut T` which only provides access to change detection from mutable query methods.
903///
904/// ```rust
905/// # use bevy_ecs::prelude::*;
906/// # use bevy_ecs::query::QueryData;
907/// #
908/// #[derive(Component, Clone, Debug)]
909/// struct Name(String);
910///
911/// #[derive(Component, Clone, Copy, Debug)]
912/// struct Health(f32);
913///
914/// fn my_system(mut query: Query<(Mut<Name>, &mut Health)>) {
915/// // Mutable access provides change detection information for both parameters:
916/// // - `name` has type `Mut<Name>`
917/// // - `health` has type `Mut<Health>`
918/// for (name, health) in query.iter_mut() {
919/// println!("Name: {:?} (last changed {:?})", name, name.last_changed());
920/// println!("Health: {:?} (last changed: {:?})", health, health.last_changed());
921/// # println!("{}{}", name.0, health.0); // Silence dead_code warning
922/// }
923///
924/// // Immutable access only provides change detection for `Name`:
925/// // - `name` has type `Ref<Name>`
926/// // - `health` has type `&Health`
927/// for (name, health) in query.iter() {
928/// println!("Name: {:?} (last changed {:?})", name, name.last_changed());
929/// println!("Health: {:?}", health);
930/// }
931/// }
932///
933/// # bevy_ecs::system::assert_is_system(my_system);
934/// ```
935pub struct Mut<'w, T: ?Sized> {
936 pub(crate) value: &'w mut T,
937 pub(crate) ticks: TicksMut<'w>,
938 pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
939}
940
941impl<'w, T: ?Sized> Mut<'w, T> {
942 /// Creates a new change-detection enabled smart pointer.
943 /// In almost all cases you do not need to call this method manually,
944 /// as instances of `Mut` will be created by engine-internal code.
945 ///
946 /// Many use-cases of this method would be better served by [`Mut::map_unchanged`]
947 /// or [`Mut::reborrow`].
948 ///
949 /// - `value` - The value wrapped by this smart pointer.
950 /// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.
951 /// - `last_changed` - A [`Tick`] that stores the last time the wrapped value was changed.
952 /// This will be updated to the value of `change_tick` if the returned smart pointer
953 /// is modified.
954 /// - `last_run` - A [`Tick`], occurring before `this_run`, which is used
955 /// as a reference to determine whether the wrapped value is newly added or changed.
956 /// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".
957 pub fn new(
958 value: &'w mut T,
959 added: &'w mut Tick,
960 last_changed: &'w mut Tick,
961 last_run: Tick,
962 this_run: Tick,
963 caller: MaybeLocation<&'w mut &'static Location<'static>>,
964 ) -> Self {
965 Self {
966 value,
967 ticks: TicksMut {
968 added,
969 changed: last_changed,
970 last_run,
971 this_run,
972 },
973 changed_by: caller,
974 }
975 }
976
977 /// Overwrite the `last_run` and `this_run` tick that are used for change detection.
978 ///
979 /// This is an advanced feature. `Mut`s are usually _created_ by engine-internal code and
980 /// _consumed_ by end-user code.
981 pub fn set_ticks(&mut self, last_run: Tick, this_run: Tick) {
982 self.ticks.last_run = last_run;
983 self.ticks.this_run = this_run;
984 }
985}
986
987impl<'w, T: ?Sized> From<Mut<'w, T>> for Ref<'w, T> {
988 fn from(mut_ref: Mut<'w, T>) -> Self {
989 Self {
990 value: mut_ref.value,
991 ticks: mut_ref.ticks.into(),
992 changed_by: mut_ref.changed_by.map(|changed_by| &*changed_by),
993 }
994 }
995}
996
997impl<'w, 'a, T> IntoIterator for &'a Mut<'w, T>
998where
999 &'a T: IntoIterator,
1000{
1001 type Item = <&'a T as IntoIterator>::Item;
1002 type IntoIter = <&'a T as IntoIterator>::IntoIter;
1003
1004 fn into_iter(self) -> Self::IntoIter {
1005 self.value.into_iter()
1006 }
1007}
1008
1009impl<'w, 'a, T> IntoIterator for &'a mut Mut<'w, T>
1010where
1011 &'a mut T: IntoIterator,
1012{
1013 type Item = <&'a mut T as IntoIterator>::Item;
1014 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
1015
1016 fn into_iter(self) -> Self::IntoIter {
1017 self.set_changed();
1018 self.value.into_iter()
1019 }
1020}
1021
1022change_detection_impl!(Mut<'w, T>, T,);
1023change_detection_mut_impl!(Mut<'w, T>, T,);
1024impl_methods!(Mut<'w, T>, T,);
1025impl_debug!(Mut<'w, T>,);
1026
1027/// Unique mutable borrow of resources or an entity's component.
1028///
1029/// Similar to [`Mut`], but not generic over the component type, instead
1030/// exposing the raw pointer as a `*mut ()`.
1031///
1032/// Usually you don't need to use this and can instead use the APIs returning a
1033/// [`Mut`], but in situations where the types are not known at compile time
1034/// or are defined outside of rust this can be used.
1035pub struct MutUntyped<'w> {
1036 pub(crate) value: PtrMut<'w>,
1037 pub(crate) ticks: TicksMut<'w>,
1038 pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
1039}
1040
1041impl<'w> MutUntyped<'w> {
1042 /// Returns the pointer to the value, marking it as changed.
1043 ///
1044 /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).
1045 #[inline]
1046 pub fn into_inner(mut self) -> PtrMut<'w> {
1047 self.set_changed();
1048 self.value
1049 }
1050
1051 /// Returns a [`MutUntyped`] with a smaller lifetime.
1052 /// This is useful if you have `&mut MutUntyped`, but you need a `MutUntyped`.
1053 #[inline]
1054 pub fn reborrow(&mut self) -> MutUntyped<'_> {
1055 MutUntyped {
1056 value: self.value.reborrow(),
1057 ticks: TicksMut {
1058 added: self.ticks.added,
1059 changed: self.ticks.changed,
1060 last_run: self.ticks.last_run,
1061 this_run: self.ticks.this_run,
1062 },
1063 changed_by: self.changed_by.as_deref_mut(),
1064 }
1065 }
1066
1067 /// Returns `true` if this value was changed or mutably dereferenced
1068 /// either since a specific change tick.
1069 pub fn has_changed_since(&self, tick: Tick) -> bool {
1070 self.ticks.changed.is_newer_than(tick, self.ticks.this_run)
1071 }
1072
1073 /// Returns a pointer to the value without taking ownership of this smart pointer, marking it as changed.
1074 ///
1075 /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).
1076 #[inline]
1077 pub fn as_mut(&mut self) -> PtrMut<'_> {
1078 self.set_changed();
1079 self.value.reborrow()
1080 }
1081
1082 /// Returns an immutable pointer to the value without taking ownership.
1083 #[inline]
1084 pub fn as_ref(&self) -> Ptr<'_> {
1085 self.value.as_ref()
1086 }
1087
1088 /// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value,
1089 /// without flagging a change.
1090 /// This function is the untyped equivalent of [`Mut::map_unchanged`].
1091 ///
1092 /// 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.
1093 ///
1094 /// If you know the type of the value you can do
1095 /// ```no_run
1096 /// # use bevy_ecs::change_detection::{Mut, MutUntyped};
1097 /// # let mut_untyped: MutUntyped = unimplemented!();
1098 /// // SAFETY: ptr is of type `u8`
1099 /// mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::<u8>() });
1100 /// ```
1101 /// If you have a [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) that you know belongs to this [`MutUntyped`],
1102 /// you can do
1103 /// ```no_run
1104 /// # use bevy_ecs::change_detection::{Mut, MutUntyped};
1105 /// # let mut_untyped: MutUntyped = unimplemented!();
1106 /// # let reflect_from_ptr: bevy_reflect::ReflectFromPtr = unimplemented!();
1107 /// // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped`
1108 /// mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_mut(ptr) });
1109 /// ```
1110 pub fn map_unchanged<T: ?Sized>(self, f: impl FnOnce(PtrMut<'w>) -> &'w mut T) -> Mut<'w, T> {
1111 Mut {
1112 value: f(self.value),
1113 ticks: self.ticks,
1114 changed_by: self.changed_by,
1115 }
1116 }
1117
1118 /// Transforms this [`MutUntyped`] into a [`Mut<T>`] with the same lifetime.
1119 ///
1120 /// # Safety
1121 /// - `T` must be the erased pointee type for this [`MutUntyped`].
1122 pub unsafe fn with_type<T>(self) -> Mut<'w, T> {
1123 Mut {
1124 // SAFETY: `value` is `Aligned` and caller ensures the pointee type is `T`.
1125 value: unsafe { self.value.deref_mut() },
1126 ticks: self.ticks,
1127 // SAFETY: `caller` is `Aligned`.
1128 changed_by: self.changed_by,
1129 }
1130 }
1131}
1132
1133impl<'w> DetectChanges for MutUntyped<'w> {
1134 #[inline]
1135 fn is_added(&self) -> bool {
1136 self.ticks
1137 .added
1138 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
1139 }
1140
1141 #[inline]
1142 fn is_changed(&self) -> bool {
1143 self.ticks
1144 .changed
1145 .is_newer_than(self.ticks.last_run, self.ticks.this_run)
1146 }
1147
1148 #[inline]
1149 fn last_changed(&self) -> Tick {
1150 *self.ticks.changed
1151 }
1152
1153 #[inline]
1154 fn changed_by(&self) -> MaybeLocation {
1155 self.changed_by.copied()
1156 }
1157
1158 #[inline]
1159 fn added(&self) -> Tick {
1160 *self.ticks.added
1161 }
1162}
1163
1164impl<'w> DetectChangesMut for MutUntyped<'w> {
1165 type Inner = PtrMut<'w>;
1166
1167 #[inline]
1168 #[track_caller]
1169 fn set_changed(&mut self) {
1170 *self.ticks.changed = self.ticks.this_run;
1171 self.changed_by.assign(MaybeLocation::caller());
1172 }
1173
1174 #[inline]
1175 #[track_caller]
1176 fn set_added(&mut self) {
1177 *self.ticks.changed = self.ticks.this_run;
1178 *self.ticks.added = self.ticks.this_run;
1179 self.changed_by.assign(MaybeLocation::caller());
1180 }
1181
1182 #[inline]
1183 #[track_caller]
1184 fn set_last_changed(&mut self, last_changed: Tick) {
1185 *self.ticks.changed = last_changed;
1186 self.changed_by.assign(MaybeLocation::caller());
1187 }
1188
1189 #[inline]
1190 #[track_caller]
1191 fn set_last_added(&mut self, last_added: Tick) {
1192 *self.ticks.added = last_added;
1193 *self.ticks.changed = last_added;
1194 self.changed_by.assign(MaybeLocation::caller());
1195 }
1196
1197 #[inline]
1198 #[track_caller]
1199 fn bypass_change_detection(&mut self) -> &mut Self::Inner {
1200 &mut self.value
1201 }
1202}
1203
1204impl core::fmt::Debug for MutUntyped<'_> {
1205 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1206 f.debug_tuple("MutUntyped")
1207 .field(&self.value.as_ptr())
1208 .finish()
1209 }
1210}
1211
1212impl<'w, T> From<Mut<'w, T>> for MutUntyped<'w> {
1213 fn from(value: Mut<'w, T>) -> Self {
1214 MutUntyped {
1215 value: value.value.into(),
1216 ticks: value.ticks,
1217 changed_by: value.changed_by,
1218 }
1219 }
1220}
1221
1222/// A value that contains a `T` if the `track_location` feature is enabled,
1223/// and is a ZST if it is not.
1224///
1225/// The overall API is similar to [`Option`], but whether the value is `Some` or `None` is set at compile
1226/// time and is the same for all values.
1227///
1228/// If the `track_location` feature is disabled, then all functions on this type that return
1229/// an `MaybeLocation` will have an empty body and should be removed by the optimizer.
1230///
1231/// This allows code to be written that will be checked by the compiler even when the feature is disabled,
1232/// but that will be entirely removed during compilation.
1233#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
1234#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1235pub struct MaybeLocation<T: ?Sized = &'static Location<'static>> {
1236 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
1237 marker: PhantomData<T>,
1238 #[cfg(feature = "track_location")]
1239 value: T,
1240}
1241
1242impl<T: core::fmt::Display> core::fmt::Display for MaybeLocation<T> {
1243 fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1244 #[cfg(feature = "track_location")]
1245 {
1246 self.value.fmt(_f)?;
1247 }
1248 Ok(())
1249 }
1250}
1251
1252impl<T> MaybeLocation<T> {
1253 /// Constructs a new `MaybeLocation` that wraps the given value.
1254 ///
1255 /// This may only accept `Copy` types,
1256 /// since it needs to drop the value if the `track_location` feature is disabled,
1257 /// and non-`Copy` types cannot be dropped in `const` context.
1258 /// Use [`new_with`][Self::new_with] if you need to construct a non-`Copy` value.
1259 ///
1260 /// # See also
1261 /// - [`new_with`][Self::new_with] to initialize using a closure.
1262 /// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.
1263 #[inline]
1264 pub const fn new(_value: T) -> Self
1265 where
1266 T: Copy,
1267 {
1268 Self {
1269 #[cfg(feature = "track_location")]
1270 value: _value,
1271 marker: PhantomData,
1272 }
1273 }
1274
1275 /// Constructs a new `MaybeLocation` that wraps the result of the given closure.
1276 ///
1277 /// # See also
1278 /// - [`new`][Self::new] to initialize using a value.
1279 /// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.
1280 #[inline]
1281 pub fn new_with(_f: impl FnOnce() -> T) -> Self {
1282 Self {
1283 #[cfg(feature = "track_location")]
1284 value: _f(),
1285 marker: PhantomData,
1286 }
1287 }
1288
1289 /// Maps an `MaybeLocation<T> `to `MaybeLocation<U>` by applying a function to a contained value.
1290 #[inline]
1291 pub fn map<U>(self, _f: impl FnOnce(T) -> U) -> MaybeLocation<U> {
1292 MaybeLocation {
1293 #[cfg(feature = "track_location")]
1294 value: _f(self.value),
1295 marker: PhantomData,
1296 }
1297 }
1298
1299 /// Converts a pair of `MaybeLocation` values to an `MaybeLocation` of a tuple.
1300 #[inline]
1301 pub fn zip<U>(self, _other: MaybeLocation<U>) -> MaybeLocation<(T, U)> {
1302 MaybeLocation {
1303 #[cfg(feature = "track_location")]
1304 value: (self.value, _other.value),
1305 marker: PhantomData,
1306 }
1307 }
1308
1309 /// Returns the contained value or a default.
1310 /// If the `track_location` feature is enabled, this always returns the contained value.
1311 /// If it is disabled, this always returns `T::Default()`.
1312 #[inline]
1313 pub fn unwrap_or_default(self) -> T
1314 where
1315 T: Default,
1316 {
1317 self.into_option().unwrap_or_default()
1318 }
1319
1320 /// Converts an `MaybeLocation` to an [`Option`] to allow run-time branching.
1321 /// If the `track_location` feature is enabled, this always returns `Some`.
1322 /// If it is disabled, this always returns `None`.
1323 #[inline]
1324 pub fn into_option(self) -> Option<T> {
1325 #[cfg(feature = "track_location")]
1326 {
1327 Some(self.value)
1328 }
1329 #[cfg(not(feature = "track_location"))]
1330 {
1331 None
1332 }
1333 }
1334}
1335
1336impl<T> MaybeLocation<Option<T>> {
1337 /// Constructs a new `MaybeLocation` that wraps the result of the given closure.
1338 /// If the closure returns `Some`, it unwraps the inner value.
1339 ///
1340 /// # See also
1341 /// - [`new`][Self::new] to initialize using a value.
1342 /// - [`new_with`][Self::new_with] to initialize using a closure.
1343 #[inline]
1344 pub fn new_with_flattened(_f: impl FnOnce() -> Option<MaybeLocation<T>>) -> Self {
1345 Self {
1346 #[cfg(feature = "track_location")]
1347 value: _f().map(|value| value.value),
1348 marker: PhantomData,
1349 }
1350 }
1351
1352 /// Transposes a `MaybeLocation` of an [`Option`] into an [`Option`] of a `MaybeLocation`.
1353 ///
1354 /// This can be useful if you want to use the `?` operator to exit early
1355 /// if the `track_location` feature is enabled but the value is not found.
1356 ///
1357 /// If the `track_location` feature is enabled,
1358 /// this returns `Some` if the inner value is `Some`
1359 /// and `None` if the inner value is `None`.
1360 ///
1361 /// If it is disabled, this always returns `Some`.
1362 ///
1363 /// # Example
1364 ///
1365 /// ```
1366 /// # use bevy_ecs::{change_detection::MaybeLocation, world::World};
1367 /// # use core::panic::Location;
1368 /// #
1369 /// # fn test() -> Option<()> {
1370 /// let mut world = World::new();
1371 /// let entity = world.spawn(()).id();
1372 /// let location: MaybeLocation<Option<&'static Location<'static>>> =
1373 /// world.entities().entity_get_spawned_or_despawned_by(entity);
1374 /// let location: MaybeLocation<&'static Location<'static>> = location.transpose()?;
1375 /// # Some(())
1376 /// # }
1377 /// # test();
1378 /// ```
1379 ///
1380 /// # See also
1381 ///
1382 /// - [`into_option`][Self::into_option] to convert to an `Option<Option<T>>`.
1383 /// When used with [`Option::flatten`], this will have a similar effect,
1384 /// but will return `None` when the `track_location` feature is disabled.
1385 #[inline]
1386 pub fn transpose(self) -> Option<MaybeLocation<T>> {
1387 #[cfg(feature = "track_location")]
1388 {
1389 self.value.map(|value| MaybeLocation {
1390 value,
1391 marker: PhantomData,
1392 })
1393 }
1394 #[cfg(not(feature = "track_location"))]
1395 {
1396 Some(MaybeLocation {
1397 marker: PhantomData,
1398 })
1399 }
1400 }
1401}
1402
1403impl<T> MaybeLocation<&T> {
1404 /// Maps an `MaybeLocation<&T>` to an `MaybeLocation<T>` by copying the contents.
1405 #[inline]
1406 pub const fn copied(&self) -> MaybeLocation<T>
1407 where
1408 T: Copy,
1409 {
1410 MaybeLocation {
1411 #[cfg(feature = "track_location")]
1412 value: *self.value,
1413 marker: PhantomData,
1414 }
1415 }
1416}
1417
1418impl<T> MaybeLocation<&mut T> {
1419 /// Maps an `MaybeLocation<&mut T>` to an `MaybeLocation<T>` by copying the contents.
1420 #[inline]
1421 pub const fn copied(&self) -> MaybeLocation<T>
1422 where
1423 T: Copy,
1424 {
1425 MaybeLocation {
1426 #[cfg(feature = "track_location")]
1427 value: *self.value,
1428 marker: PhantomData,
1429 }
1430 }
1431
1432 /// Assigns the contents of an `MaybeLocation<T>` to an `MaybeLocation<&mut T>`.
1433 #[inline]
1434 pub fn assign(&mut self, _value: MaybeLocation<T>) {
1435 #[cfg(feature = "track_location")]
1436 {
1437 *self.value = _value.value;
1438 }
1439 }
1440}
1441
1442impl<T: ?Sized> MaybeLocation<T> {
1443 /// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T>`.
1444 #[inline]
1445 pub const fn as_ref(&self) -> MaybeLocation<&T> {
1446 MaybeLocation {
1447 #[cfg(feature = "track_location")]
1448 value: &self.value,
1449 marker: PhantomData,
1450 }
1451 }
1452
1453 /// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T>`.
1454 #[inline]
1455 pub const fn as_mut(&mut self) -> MaybeLocation<&mut T> {
1456 MaybeLocation {
1457 #[cfg(feature = "track_location")]
1458 value: &mut self.value,
1459 marker: PhantomData,
1460 }
1461 }
1462
1463 /// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T::Target>`.
1464 #[inline]
1465 pub fn as_deref(&self) -> MaybeLocation<&T::Target>
1466 where
1467 T: Deref,
1468 {
1469 MaybeLocation {
1470 #[cfg(feature = "track_location")]
1471 value: &*self.value,
1472 marker: PhantomData,
1473 }
1474 }
1475
1476 /// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T::Target>`.
1477 #[inline]
1478 pub fn as_deref_mut(&mut self) -> MaybeLocation<&mut T::Target>
1479 where
1480 T: DerefMut,
1481 {
1482 MaybeLocation {
1483 #[cfg(feature = "track_location")]
1484 value: &mut *self.value,
1485 marker: PhantomData,
1486 }
1487 }
1488}
1489
1490impl MaybeLocation {
1491 /// Returns the source location of the caller of this function. If that function's caller is
1492 /// annotated then its call location will be returned, and so on up the stack to the first call
1493 /// within a non-tracked function body.
1494 #[inline]
1495 #[track_caller]
1496 pub const fn caller() -> Self {
1497 // Note that this cannot use `new_with`, since `FnOnce` invocations cannot be annotated with `#[track_caller]`.
1498 MaybeLocation {
1499 #[cfg(feature = "track_location")]
1500 value: Location::caller(),
1501 marker: PhantomData,
1502 }
1503 }
1504}
1505
1506#[cfg(test)]
1507mod tests {
1508 use bevy_ecs_macros::Resource;
1509 use bevy_ptr::PtrMut;
1510 use bevy_reflect::{FromType, ReflectFromPtr};
1511 use core::ops::{Deref, DerefMut};
1512
1513 use crate::{
1514 change_detection::{
1515 MaybeLocation, Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD,
1516 MAX_CHANGE_AGE,
1517 },
1518 component::{Component, ComponentTicks, Tick},
1519 system::{IntoSystem, Single, System},
1520 world::World,
1521 };
1522
1523 use super::{DetectChanges, DetectChangesMut, MutUntyped};
1524
1525 #[derive(Component, PartialEq)]
1526 struct C;
1527
1528 #[derive(Resource)]
1529 struct R;
1530
1531 #[derive(Resource, PartialEq)]
1532 struct R2(u8);
1533
1534 impl Deref for R2 {
1535 type Target = u8;
1536 fn deref(&self) -> &u8 {
1537 &self.0
1538 }
1539 }
1540
1541 impl DerefMut for R2 {
1542 fn deref_mut(&mut self) -> &mut u8 {
1543 &mut self.0
1544 }
1545 }
1546
1547 #[test]
1548 fn change_expiration() {
1549 fn change_detected(query: Option<Single<Ref<C>>>) -> bool {
1550 query.unwrap().is_changed()
1551 }
1552
1553 fn change_expired(query: Option<Single<Ref<C>>>) -> bool {
1554 query.unwrap().is_changed()
1555 }
1556
1557 let mut world = World::new();
1558
1559 // component added: 1, changed: 1
1560 world.spawn(C);
1561
1562 let mut change_detected_system = IntoSystem::into_system(change_detected);
1563 let mut change_expired_system = IntoSystem::into_system(change_expired);
1564 change_detected_system.initialize(&mut world);
1565 change_expired_system.initialize(&mut world);
1566
1567 // world: 1, system last ran: 0, component changed: 1
1568 // The spawn will be detected since it happened after the system "last ran".
1569 assert!(change_detected_system.run((), &mut world).unwrap());
1570
1571 // world: 1 + MAX_CHANGE_AGE
1572 let change_tick = world.change_tick.get_mut();
1573 *change_tick = change_tick.wrapping_add(MAX_CHANGE_AGE);
1574
1575 // Both the system and component appeared `MAX_CHANGE_AGE` ticks ago.
1576 // Since we clamp things to `MAX_CHANGE_AGE` for determinism,
1577 // `ComponentTicks::is_changed` will now see `MAX_CHANGE_AGE > MAX_CHANGE_AGE`
1578 // and return `false`.
1579 assert!(!change_expired_system.run((), &mut world).unwrap());
1580 }
1581
1582 #[test]
1583 fn change_tick_wraparound() {
1584 let mut world = World::new();
1585 world.last_change_tick = Tick::new(u32::MAX);
1586 *world.change_tick.get_mut() = 0;
1587
1588 // component added: 0, changed: 0
1589 world.spawn(C);
1590
1591 world.increment_change_tick();
1592
1593 // Since the world is always ahead, as long as changes can't get older than `u32::MAX` (which we ensure),
1594 // the wrapping difference will always be positive, so wraparound doesn't matter.
1595 let mut query = world.query::<Ref<C>>();
1596 assert!(query.single(&world).unwrap().is_changed());
1597 }
1598
1599 #[test]
1600 fn change_tick_scan() {
1601 let mut world = World::new();
1602
1603 // component added: 1, changed: 1
1604 world.spawn(C);
1605
1606 // a bunch of stuff happens, the component is now older than `MAX_CHANGE_AGE`
1607 *world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD;
1608 let change_tick = world.change_tick();
1609
1610 let mut query = world.query::<Ref<C>>();
1611 for tracker in query.iter(&world) {
1612 let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();
1613 let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();
1614 assert!(ticks_since_insert > MAX_CHANGE_AGE);
1615 assert!(ticks_since_change > MAX_CHANGE_AGE);
1616 }
1617
1618 // scan change ticks and clamp those at risk of overflow
1619 world.check_change_ticks();
1620
1621 for tracker in query.iter(&world) {
1622 let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();
1623 let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();
1624 assert_eq!(ticks_since_insert, MAX_CHANGE_AGE);
1625 assert_eq!(ticks_since_change, MAX_CHANGE_AGE);
1626 }
1627 }
1628
1629 #[test]
1630 fn mut_from_res_mut() {
1631 let mut component_ticks = ComponentTicks {
1632 added: Tick::new(1),
1633 changed: Tick::new(2),
1634 };
1635 let ticks = TicksMut {
1636 added: &mut component_ticks.added,
1637 changed: &mut component_ticks.changed,
1638 last_run: Tick::new(3),
1639 this_run: Tick::new(4),
1640 };
1641 let mut res = R {};
1642 let mut caller = MaybeLocation::caller();
1643
1644 let res_mut = ResMut {
1645 value: &mut res,
1646 ticks,
1647 changed_by: caller.as_mut(),
1648 };
1649
1650 let into_mut: Mut<R> = res_mut.into();
1651 assert_eq!(1, into_mut.ticks.added.get());
1652 assert_eq!(2, into_mut.ticks.changed.get());
1653 assert_eq!(3, into_mut.ticks.last_run.get());
1654 assert_eq!(4, into_mut.ticks.this_run.get());
1655 }
1656
1657 #[test]
1658 fn mut_new() {
1659 let mut component_ticks = ComponentTicks {
1660 added: Tick::new(1),
1661 changed: Tick::new(3),
1662 };
1663 let mut res = R {};
1664 let mut caller = MaybeLocation::caller();
1665
1666 let val = Mut::new(
1667 &mut res,
1668 &mut component_ticks.added,
1669 &mut component_ticks.changed,
1670 Tick::new(2), // last_run
1671 Tick::new(4), // this_run
1672 caller.as_mut(),
1673 );
1674
1675 assert!(!val.is_added());
1676 assert!(val.is_changed());
1677 }
1678
1679 #[test]
1680 fn mut_from_non_send_mut() {
1681 let mut component_ticks = ComponentTicks {
1682 added: Tick::new(1),
1683 changed: Tick::new(2),
1684 };
1685 let ticks = TicksMut {
1686 added: &mut component_ticks.added,
1687 changed: &mut component_ticks.changed,
1688 last_run: Tick::new(3),
1689 this_run: Tick::new(4),
1690 };
1691 let mut res = R {};
1692 let mut caller = MaybeLocation::caller();
1693
1694 let non_send_mut = NonSendMut {
1695 value: &mut res,
1696 ticks,
1697 changed_by: caller.as_mut(),
1698 };
1699
1700 let into_mut: Mut<R> = non_send_mut.into();
1701 assert_eq!(1, into_mut.ticks.added.get());
1702 assert_eq!(2, into_mut.ticks.changed.get());
1703 assert_eq!(3, into_mut.ticks.last_run.get());
1704 assert_eq!(4, into_mut.ticks.this_run.get());
1705 }
1706
1707 #[test]
1708 fn map_mut() {
1709 use super::*;
1710 struct Outer(i64);
1711
1712 let last_run = Tick::new(2);
1713 let this_run = Tick::new(3);
1714 let mut component_ticks = ComponentTicks {
1715 added: Tick::new(1),
1716 changed: Tick::new(2),
1717 };
1718 let ticks = TicksMut {
1719 added: &mut component_ticks.added,
1720 changed: &mut component_ticks.changed,
1721 last_run,
1722 this_run,
1723 };
1724
1725 let mut outer = Outer(0);
1726 let mut caller = MaybeLocation::caller();
1727
1728 let ptr = Mut {
1729 value: &mut outer,
1730 ticks,
1731 changed_by: caller.as_mut(),
1732 };
1733 assert!(!ptr.is_changed());
1734
1735 // Perform a mapping operation.
1736 let mut inner = ptr.map_unchanged(|x| &mut x.0);
1737 assert!(!inner.is_changed());
1738
1739 // Mutate the inner value.
1740 *inner = 64;
1741 assert!(inner.is_changed());
1742 // Modifying one field of a component should flag a change for the entire component.
1743 assert!(component_ticks.is_changed(last_run, this_run));
1744 }
1745
1746 #[test]
1747 fn set_if_neq() {
1748 let mut world = World::new();
1749
1750 world.insert_resource(R2(0));
1751 // Resources are Changed when first added
1752 world.increment_change_tick();
1753 // This is required to update world::last_change_tick
1754 world.clear_trackers();
1755
1756 let mut r = world.resource_mut::<R2>();
1757 assert!(!r.is_changed(), "Resource must begin unchanged.");
1758
1759 r.set_if_neq(R2(0));
1760 assert!(
1761 !r.is_changed(),
1762 "Resource must not be changed after setting to the same value."
1763 );
1764
1765 r.set_if_neq(R2(3));
1766 assert!(
1767 r.is_changed(),
1768 "Resource must be changed after setting to a different value."
1769 );
1770 }
1771
1772 #[test]
1773 fn as_deref_mut() {
1774 let mut world = World::new();
1775
1776 world.insert_resource(R2(0));
1777 // Resources are Changed when first added
1778 world.increment_change_tick();
1779 // This is required to update world::last_change_tick
1780 world.clear_trackers();
1781
1782 let mut r = world.resource_mut::<R2>();
1783 assert!(!r.is_changed(), "Resource must begin unchanged.");
1784
1785 let mut r = r.as_deref_mut();
1786 assert!(
1787 !r.is_changed(),
1788 "Dereferencing should not mark the item as changed yet"
1789 );
1790
1791 r.set_if_neq(3);
1792 assert!(
1793 r.is_changed(),
1794 "Resource must be changed after setting to a different value."
1795 );
1796 }
1797
1798 #[test]
1799 fn mut_untyped_to_reflect() {
1800 let last_run = Tick::new(2);
1801 let this_run = Tick::new(3);
1802 let mut component_ticks = ComponentTicks {
1803 added: Tick::new(1),
1804 changed: Tick::new(2),
1805 };
1806 let ticks = TicksMut {
1807 added: &mut component_ticks.added,
1808 changed: &mut component_ticks.changed,
1809 last_run,
1810 this_run,
1811 };
1812
1813 let mut value: i32 = 5;
1814 let mut caller = MaybeLocation::caller();
1815
1816 let value = MutUntyped {
1817 value: PtrMut::from(&mut value),
1818 ticks,
1819 changed_by: caller.as_mut(),
1820 };
1821
1822 let reflect_from_ptr = <ReflectFromPtr as FromType<i32>>::from_type();
1823
1824 let mut new = value.map_unchanged(|ptr| {
1825 // SAFETY: The underlying type of `ptr` matches `reflect_from_ptr`.
1826 unsafe { reflect_from_ptr.as_reflect_mut(ptr) }
1827 });
1828
1829 assert!(!new.is_changed());
1830
1831 new.reflect_mut();
1832
1833 assert!(new.is_changed());
1834 }
1835
1836 #[test]
1837 fn mut_untyped_from_mut() {
1838 let mut component_ticks = ComponentTicks {
1839 added: Tick::new(1),
1840 changed: Tick::new(2),
1841 };
1842 let ticks = TicksMut {
1843 added: &mut component_ticks.added,
1844 changed: &mut component_ticks.changed,
1845 last_run: Tick::new(3),
1846 this_run: Tick::new(4),
1847 };
1848 let mut c = C {};
1849 let mut caller = MaybeLocation::caller();
1850
1851 let mut_typed = Mut {
1852 value: &mut c,
1853 ticks,
1854 changed_by: caller.as_mut(),
1855 };
1856
1857 let into_mut: MutUntyped = mut_typed.into();
1858 assert_eq!(1, into_mut.ticks.added.get());
1859 assert_eq!(2, into_mut.ticks.changed.get());
1860 assert_eq!(3, into_mut.ticks.last_run.get());
1861 assert_eq!(4, into_mut.ticks.this_run.get());
1862 }
1863}