Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/change_detection.rs
6598 views
1
//! Types that detect when their internal data mutate.
2
3
use crate::{
4
component::{Tick, TickCells},
5
ptr::PtrMut,
6
resource::Resource,
7
};
8
use alloc::borrow::ToOwned;
9
use bevy_ptr::{Ptr, UnsafeCellDeref};
10
#[cfg(feature = "bevy_reflect")]
11
use bevy_reflect::Reflect;
12
use 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)
27
pub 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.
32
pub 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
/// ```
53
pub 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
/// ```
110
pub 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(BufferedEvent, 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: EventWriter<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
339
macro_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
390
macro_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
450
macro_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
546
macro_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)]
562
pub(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
569
impl<'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
589
pub(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
596
impl<'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
616
impl<'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.
637
pub 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
643
impl<'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
668
impl<'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
678
impl<'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
690
impl<'w, 'a, T: Resource> IntoIterator for &'a Res<'w, T>
691
where
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
}
701
change_detection_impl!(Res<'w, T>, T, Resource);
702
impl_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.
714
pub 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
720
impl<'w, 'a, T: Resource> IntoIterator for &'a ResMut<'w, T>
721
where
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
732
impl<'w, 'a, T: Resource> IntoIterator for &'a mut ResMut<'w, T>
733
where
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
745
change_detection_impl!(ResMut<'w, T>, T, Resource);
746
change_detection_mut_impl!(ResMut<'w, T>, T, Resource);
747
impl_methods!(ResMut<'w, T>, T, Resource);
748
impl_debug!(ResMut<'w, T>, Resource);
749
750
impl<'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.
773
pub 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
779
change_detection_impl!(NonSendMut<'w, T>, T,);
780
change_detection_mut_impl!(NonSendMut<'w, T>, T,);
781
impl_methods!(NonSendMut<'w, T>, T,);
782
impl_debug!(NonSendMut<'w, T>,);
783
784
impl<'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
/// ```
820
pub 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
826
impl<'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
885
impl<'w, 'a, T> IntoIterator for &'a Ref<'w, T>
886
where
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
}
896
change_detection_impl!(Ref<'w, T>, T,);
897
impl_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
/// ```
935
pub 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
941
impl<'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
987
impl<'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
997
impl<'w, 'a, T> IntoIterator for &'a Mut<'w, T>
998
where
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
1009
impl<'w, 'a, T> IntoIterator for &'a mut Mut<'w, T>
1010
where
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
1022
change_detection_impl!(Mut<'w, T>, T,);
1023
change_detection_mut_impl!(Mut<'w, T>, T,);
1024
impl_methods!(Mut<'w, T>, T,);
1025
impl_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.
1035
pub 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
1041
impl<'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
1133
impl<'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
1164
impl<'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
1204
impl 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
1212
impl<'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)]
1235
pub 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
1242
impl<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
1252
impl<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
1336
impl<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
1403
impl<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
1418
impl<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
1442
impl<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
1490
impl 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)]
1507
mod 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
}
1864
1865