Path: blob/main/crates/bevy_ecs/src/change_detection.rs
6598 views
//! Types that detect when their internal data mutate.12use crate::{3component::{Tick, TickCells},4ptr::PtrMut,5resource::Resource,6};7use alloc::borrow::ToOwned;8use bevy_ptr::{Ptr, UnsafeCellDeref};9#[cfg(feature = "bevy_reflect")]10use bevy_reflect::Reflect;11use core::{12marker::PhantomData,13mem,14ops::{Deref, DerefMut},15panic::Location,16};1718/// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.19///20/// Change ticks can only be scanned when systems aren't running. Thus, if the threshold is `N`,21/// the maximum is `2 * N - 1` (i.e. the world ticks `N - 1` times, then `N` times).22///23/// If no change is older than `u32::MAX - (2 * N - 1)` following a scan, none of their ages can24/// overflow and cause false positives.25// (518,400,000 = 1000 ticks per frame * 144 frames per second * 3600 seconds per hour)26pub const CHECK_TICK_THRESHOLD: u32 = 518_400_000;2728/// The maximum change tick difference that won't overflow before the next `check_tick` scan.29///30/// Changes stop being detected once they become this old.31pub const MAX_CHANGE_AGE: u32 = u32::MAX - (2 * CHECK_TICK_THRESHOLD - 1);3233/// Types that can read change detection information.34/// This change detection is controlled by [`DetectChangesMut`] types such as [`ResMut`].35///36/// ## Example37/// Using types that implement [`DetectChanges`], such as [`Res`], provide38/// a way to query if a value has been mutated in another system.39///40/// ```41/// use bevy_ecs::prelude::*;42///43/// #[derive(Resource)]44/// struct MyResource(u32);45///46/// fn my_system(mut resource: Res<MyResource>) {47/// if resource.is_changed() {48/// println!("My component was mutated!");49/// }50/// }51/// ```52pub trait DetectChanges {53/// Returns `true` if this value was added after the system last ran.54fn is_added(&self) -> bool;5556/// Returns `true` if this value was added or mutably dereferenced57/// either since the last time the system ran or, if the system never ran,58/// since the beginning of the program.59///60/// To check if the value was mutably dereferenced only,61/// use `this.is_changed() && !this.is_added()`.62fn is_changed(&self) -> bool;6364/// Returns the change tick recording the time this data was most recently changed.65///66/// Note that components and resources are also marked as changed upon insertion.67///68/// For comparison, the previous change tick of a system can be read using the69/// [`SystemChangeTick`](crate::system::SystemChangeTick)70/// [`SystemParam`](crate::system::SystemParam).71fn last_changed(&self) -> Tick;7273/// Returns the change tick recording the time this data was added.74fn added(&self) -> Tick;7576/// The location that last caused this to change.77fn changed_by(&self) -> MaybeLocation;78}7980/// Types that implement reliable change detection.81///82/// ## Example83/// Using types that implement [`DetectChangesMut`], such as [`ResMut`], provide84/// a way to query if a value has been mutated in another system.85/// Normally change detection is triggered by either [`DerefMut`] or [`AsMut`], however86/// it can be manually triggered via [`set_changed`](DetectChangesMut::set_changed).87///88/// To ensure that changes are only triggered when the value actually differs,89/// check if the value would change before assignment, such as by checking that `new != old`.90/// You must be *sure* that you are not mutably dereferencing in this process.91///92/// [`set_if_neq`](DetectChangesMut::set_if_neq) is a helper93/// method for this common functionality.94///95/// ```96/// use bevy_ecs::prelude::*;97///98/// #[derive(Resource)]99/// struct MyResource(u32);100///101/// fn my_system(mut resource: ResMut<MyResource>) {102/// if resource.is_changed() {103/// println!("My resource was mutated!");104/// }105///106/// resource.0 = 42; // triggers change detection via [`DerefMut`]107/// }108/// ```109pub trait DetectChangesMut: DetectChanges {110/// The type contained within this smart pointer111///112/// For example, for `ResMut<T>` this would be `T`.113type Inner: ?Sized;114115/// Flags this value as having been changed.116///117/// Mutably accessing this smart pointer will automatically flag this value as having been changed.118/// However, mutation through interior mutability requires manual reporting.119///120/// **Note**: This operation cannot be undone.121fn set_changed(&mut self);122123/// Flags this value as having been added.124///125/// It is not normally necessary to call this method.126/// The 'added' tick is set when the value is first added,127/// and is not normally changed afterwards.128///129/// **Note**: This operation cannot be undone.130fn set_added(&mut self);131132/// Manually sets the change tick recording the time when this data was last mutated.133///134/// # Warning135/// This is a complex and error-prone operation, primarily intended for use with rollback networking strategies.136/// If you merely want to flag this data as changed, use [`set_changed`](DetectChangesMut::set_changed) instead.137/// If you want to avoid triggering change detection, use [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) instead.138fn set_last_changed(&mut self, last_changed: Tick);139140/// Manually sets the added tick recording the time when this data was last added.141///142/// # Warning143/// The caveats of [`set_last_changed`](DetectChangesMut::set_last_changed) apply. This modifies both the added and changed ticks together.144fn set_last_added(&mut self, last_added: Tick);145146/// Manually bypasses change detection, allowing you to mutate the underlying value without updating the change tick.147///148/// # Warning149/// This is a risky operation, that can have unexpected consequences on any system relying on this code.150/// However, it can be an essential escape hatch when, for example,151/// you are trying to synchronize representations using change detection and need to avoid infinite recursion.152fn bypass_change_detection(&mut self) -> &mut Self::Inner;153154/// Overwrites this smart pointer with the given value, if and only if `*self != value`.155/// Returns `true` if the value was overwritten, and returns `false` if it was not.156///157/// This is useful to ensure change detection is only triggered when the underlying value158/// changes, instead of every time it is mutably accessed.159///160/// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,161/// then consider applying a `map_unchanged` beforehand to allow changing only the relevant162/// field and prevent unnecessary copying and cloning.163/// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],164/// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example165///166/// If you need the previous value, use [`replace_if_neq`](DetectChangesMut::replace_if_neq).167///168/// # Examples169///170/// ```171/// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};172/// #[derive(Resource, PartialEq, Eq)]173/// pub struct Score(u32);174///175/// fn reset_score(mut score: ResMut<Score>) {176/// // Set the score to zero, unless it is already zero.177/// score.set_if_neq(Score(0));178/// }179/// # let mut world = World::new();180/// # world.insert_resource(Score(1));181/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);182/// # score_changed.initialize(&mut world);183/// # score_changed.run((), &mut world);184/// #185/// # let mut schedule = Schedule::default();186/// # schedule.add_systems(reset_score);187/// #188/// # // first time `reset_score` runs, the score is changed.189/// # schedule.run(&mut world);190/// # assert!(score_changed.run((), &mut world).unwrap());191/// # // second time `reset_score` runs, the score is not changed.192/// # schedule.run(&mut world);193/// # assert!(!score_changed.run((), &mut world).unwrap());194/// ```195#[inline]196#[track_caller]197fn set_if_neq(&mut self, value: Self::Inner) -> bool198where199Self::Inner: Sized + PartialEq,200{201let old = self.bypass_change_detection();202if *old != value {203*old = value;204self.set_changed();205true206} else {207false208}209}210211/// Overwrites this smart pointer with the given value, if and only if `*self != value`,212/// returning the previous value if this occurs.213///214/// This is useful to ensure change detection is only triggered when the underlying value215/// changes, instead of every time it is mutably accessed.216///217/// If you're dealing with non-trivial structs which have multiple fields of non-trivial size,218/// then consider applying a [`map_unchanged`](Mut::map_unchanged) beforehand to allow219/// changing only the relevant field and prevent unnecessary copying and cloning.220/// See the docs of [`Mut::map_unchanged`], [`MutUntyped::map_unchanged`],221/// [`ResMut::map_unchanged`] or [`NonSendMut::map_unchanged`] for an example222///223/// If you don't need the previous value, use [`set_if_neq`](DetectChangesMut::set_if_neq).224///225/// # Examples226///227/// ```228/// # use bevy_ecs::{prelude::*, schedule::common_conditions::{resource_changed, on_event}};229/// #[derive(Resource, PartialEq, Eq)]230/// pub struct Score(u32);231///232/// #[derive(BufferedEvent, PartialEq, Eq)]233/// pub struct ScoreChanged {234/// current: u32,235/// previous: u32,236/// }237///238/// fn reset_score(mut score: ResMut<Score>, mut score_changed: EventWriter<ScoreChanged>) {239/// // Set the score to zero, unless it is already zero.240/// let new_score = 0;241/// if let Some(Score(previous_score)) = score.replace_if_neq(Score(new_score)) {242/// // If `score` change, emit a `ScoreChanged` event.243/// score_changed.write(ScoreChanged {244/// current: new_score,245/// previous: previous_score,246/// });247/// }248/// }249/// # let mut world = World::new();250/// # world.insert_resource(Events::<ScoreChanged>::default());251/// # world.insert_resource(Score(1));252/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);253/// # score_changed.initialize(&mut world);254/// # score_changed.run((), &mut world);255/// #256/// # let mut score_changed_event = IntoSystem::into_system(on_event::<ScoreChanged>);257/// # score_changed_event.initialize(&mut world);258/// # score_changed_event.run((), &mut world);259/// #260/// # let mut schedule = Schedule::default();261/// # schedule.add_systems(reset_score);262/// #263/// # // first time `reset_score` runs, the score is changed.264/// # schedule.run(&mut world);265/// # assert!(score_changed.run((), &mut world).unwrap());266/// # assert!(score_changed_event.run((), &mut world).unwrap());267/// # // second time `reset_score` runs, the score is not changed.268/// # schedule.run(&mut world);269/// # assert!(!score_changed.run((), &mut world).unwrap());270/// # assert!(!score_changed_event.run((), &mut world).unwrap());271/// ```272#[inline]273#[must_use = "If you don't need to handle the previous value, use `set_if_neq` instead."]274fn replace_if_neq(&mut self, value: Self::Inner) -> Option<Self::Inner>275where276Self::Inner: Sized + PartialEq,277{278let old = self.bypass_change_detection();279if *old != value {280let previous = mem::replace(old, value);281self.set_changed();282Some(previous)283} else {284None285}286}287288/// Overwrites this smart pointer with a clone of the given value, if and only if `*self != value`.289/// Returns `true` if the value was overwritten, and returns `false` if it was not.290///291/// This method is useful when the caller only has a borrowed form of `Inner`,292/// e.g. when writing a `&str` into a `Mut<String>`.293///294/// # Examples295/// ```296/// # extern crate alloc;297/// # use alloc::borrow::ToOwned;298/// # use bevy_ecs::{prelude::*, schedule::common_conditions::resource_changed};299/// #[derive(Resource)]300/// pub struct Message(String);301///302/// fn update_message(mut message: ResMut<Message>) {303/// // Set the score to zero, unless it is already zero.304/// ResMut::map_unchanged(message, |Message(msg)| msg).clone_from_if_neq("another string");305/// }306/// # let mut world = World::new();307/// # world.insert_resource(Message("initial string".into()));308/// # let mut message_changed = IntoSystem::into_system(resource_changed::<Message>);309/// # message_changed.initialize(&mut world);310/// # message_changed.run((), &mut world);311/// #312/// # let mut schedule = Schedule::default();313/// # schedule.add_systems(update_message);314/// #315/// # // first time `reset_score` runs, the score is changed.316/// # schedule.run(&mut world);317/// # assert!(message_changed.run((), &mut world).unwrap());318/// # // second time `reset_score` runs, the score is not changed.319/// # schedule.run(&mut world);320/// # assert!(!message_changed.run((), &mut world).unwrap());321/// ```322fn clone_from_if_neq<T>(&mut self, value: &T) -> bool323where324T: ToOwned<Owned = Self::Inner> + ?Sized,325Self::Inner: PartialEq<T>,326{327let old = self.bypass_change_detection();328if old != value {329value.clone_into(old);330self.set_changed();331true332} else {333false334}335}336}337338macro_rules! change_detection_impl {339($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {340impl<$($generics),* : ?Sized $(+ $traits)?> DetectChanges for $name<$($generics),*> {341#[inline]342fn is_added(&self) -> bool {343self.ticks344.added345.is_newer_than(self.ticks.last_run, self.ticks.this_run)346}347348#[inline]349fn is_changed(&self) -> bool {350self.ticks351.changed352.is_newer_than(self.ticks.last_run, self.ticks.this_run)353}354355#[inline]356fn last_changed(&self) -> Tick {357*self.ticks.changed358}359360#[inline]361fn added(&self) -> Tick {362*self.ticks.added363}364365#[inline]366fn changed_by(&self) -> MaybeLocation {367self.changed_by.copied()368}369}370371impl<$($generics),*: ?Sized $(+ $traits)?> Deref for $name<$($generics),*> {372type Target = $target;373374#[inline]375fn deref(&self) -> &Self::Target {376self.value377}378}379380impl<$($generics),* $(: $traits)?> AsRef<$target> for $name<$($generics),*> {381#[inline]382fn as_ref(&self) -> &$target {383self.deref()384}385}386}387}388389macro_rules! change_detection_mut_impl {390($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {391impl<$($generics),* : ?Sized $(+ $traits)?> DetectChangesMut for $name<$($generics),*> {392type Inner = $target;393394#[inline]395#[track_caller]396fn set_changed(&mut self) {397*self.ticks.changed = self.ticks.this_run;398self.changed_by.assign(MaybeLocation::caller());399}400401#[inline]402#[track_caller]403fn set_added(&mut self) {404*self.ticks.changed = self.ticks.this_run;405*self.ticks.added = self.ticks.this_run;406self.changed_by.assign(MaybeLocation::caller());407}408409#[inline]410#[track_caller]411fn set_last_changed(&mut self, last_changed: Tick) {412*self.ticks.changed = last_changed;413self.changed_by.assign(MaybeLocation::caller());414}415416#[inline]417#[track_caller]418fn set_last_added(&mut self, last_added: Tick) {419*self.ticks.added = last_added;420*self.ticks.changed = last_added;421self.changed_by.assign(MaybeLocation::caller());422}423424#[inline]425fn bypass_change_detection(&mut self) -> &mut Self::Inner {426self.value427}428}429430impl<$($generics),* : ?Sized $(+ $traits)?> DerefMut for $name<$($generics),*> {431#[inline]432#[track_caller]433fn deref_mut(&mut self) -> &mut Self::Target {434self.set_changed();435self.changed_by.assign(MaybeLocation::caller());436self.value437}438}439440impl<$($generics),* $(: $traits)?> AsMut<$target> for $name<$($generics),*> {441#[inline]442fn as_mut(&mut self) -> &mut $target {443self.deref_mut()444}445}446};447}448449macro_rules! impl_methods {450($name:ident < $( $generics:tt ),+ >, $target:ty, $($traits:ident)?) => {451impl<$($generics),* : ?Sized $(+ $traits)?> $name<$($generics),*> {452/// Consume `self` and return a mutable reference to the453/// contained value while marking `self` as "changed".454#[inline]455pub fn into_inner(mut self) -> &'w mut $target {456self.set_changed();457self.value458}459460/// Returns a `Mut<>` with a smaller lifetime.461/// This is useful if you have `&mut462#[doc = stringify!($name)]463/// <T>`, but you need a `Mut<T>`.464pub fn reborrow(&mut self) -> Mut<'_, $target> {465Mut {466value: self.value,467ticks: TicksMut {468added: self.ticks.added,469changed: self.ticks.changed,470last_run: self.ticks.last_run,471this_run: self.ticks.this_run,472},473changed_by: self.changed_by.as_deref_mut(),474}475}476477/// Maps to an inner value by applying a function to the contained reference, without flagging a change.478///479/// You should never modify the argument passed to the closure -- if you want to modify the data480/// without flagging a change, consider using [`DetectChangesMut::bypass_change_detection`] to make your intent explicit.481///482/// ```483/// # use bevy_ecs::prelude::*;484/// # #[derive(PartialEq)] pub struct Vec2;485/// # impl Vec2 { pub const ZERO: Self = Self; }486/// # #[derive(Component)] pub struct Transform { translation: Vec2 }487/// // When run, zeroes the translation of every entity.488/// fn reset_positions(mut transforms: Query<&mut Transform>) {489/// for transform in &mut transforms {490/// // We pinky promise not to modify `t` within the closure.491/// // Breaking this promise will result in logic errors, but will never cause undefined behavior.492/// let mut translation = transform.map_unchanged(|t| &mut t.translation);493/// // Only reset the translation if it isn't already zero;494/// translation.set_if_neq(Vec2::ZERO);495/// }496/// }497/// # bevy_ecs::system::assert_is_system(reset_positions);498/// ```499pub fn map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> &mut U) -> Mut<'w, U> {500Mut {501value: f(self.value),502ticks: self.ticks,503changed_by: self.changed_by,504}505}506507/// Optionally maps to an inner value by applying a function to the contained reference.508/// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.509///510/// As with `map_unchanged`, you should never modify the argument passed to the closure.511pub fn filter_map_unchanged<U: ?Sized>(self, f: impl FnOnce(&mut $target) -> Option<&mut U>) -> Option<Mut<'w, U>> {512let value = f(self.value);513value.map(|value| Mut {514value,515ticks: self.ticks,516changed_by: self.changed_by,517})518}519520/// Optionally maps to an inner value by applying a function to the contained reference, returns an error on failure.521/// This is useful in a situation where you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains `U`.522///523/// As with `map_unchanged`, you should never modify the argument passed to the closure.524pub fn try_map_unchanged<U: ?Sized, E>(self, f: impl FnOnce(&mut $target) -> Result<&mut U, E>) -> Result<Mut<'w, U>, E> {525let value = f(self.value);526value.map(|value| Mut {527value,528ticks: self.ticks,529changed_by: self.changed_by,530})531}532533/// Allows you access to the dereferenced value of this pointer without immediately534/// triggering change detection.535pub fn as_deref_mut(&mut self) -> Mut<'_, <$target as Deref>::Target>536where $target: DerefMut537{538self.reborrow().map_unchanged(|v| v.deref_mut())539}540541}542};543}544545macro_rules! impl_debug {546($name:ident < $( $generics:tt ),+ >, $($traits:ident)?) => {547impl<$($generics),* : ?Sized $(+ $traits)?> core::fmt::Debug for $name<$($generics),*>548where T: core::fmt::Debug549{550fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {551f.debug_tuple(stringify!($name))552.field(&self.value)553.finish()554}555}556557};558}559560#[derive(Clone)]561pub(crate) struct Ticks<'w> {562pub(crate) added: &'w Tick,563pub(crate) changed: &'w Tick,564pub(crate) last_run: Tick,565pub(crate) this_run: Tick,566}567568impl<'w> Ticks<'w> {569/// # Safety570/// This should never alias the underlying ticks with a mutable one such as `TicksMut`.571#[inline]572pub(crate) unsafe fn from_tick_cells(573cells: TickCells<'w>,574last_run: Tick,575this_run: Tick,576) -> Self {577Self {578// SAFETY: Caller ensures there is no mutable access to the cell.579added: unsafe { cells.added.deref() },580// SAFETY: Caller ensures there is no mutable access to the cell.581changed: unsafe { cells.changed.deref() },582last_run,583this_run,584}585}586}587588pub(crate) struct TicksMut<'w> {589pub(crate) added: &'w mut Tick,590pub(crate) changed: &'w mut Tick,591pub(crate) last_run: Tick,592pub(crate) this_run: Tick,593}594595impl<'w> TicksMut<'w> {596/// # Safety597/// This should never alias the underlying ticks. All access must be unique.598#[inline]599pub(crate) unsafe fn from_tick_cells(600cells: TickCells<'w>,601last_run: Tick,602this_run: Tick,603) -> Self {604Self {605// SAFETY: Caller ensures there is no alias to the cell.606added: unsafe { cells.added.deref_mut() },607// SAFETY: Caller ensures there is no alias to the cell.608changed: unsafe { cells.changed.deref_mut() },609last_run,610this_run,611}612}613}614615impl<'w> From<TicksMut<'w>> for Ticks<'w> {616fn from(ticks: TicksMut<'w>) -> Self {617Ticks {618added: ticks.added,619changed: ticks.changed,620last_run: ticks.last_run,621this_run: ticks.this_run,622}623}624}625626/// Shared borrow of a [`Resource`].627///628/// See the [`Resource`] documentation for usage.629///630/// If you need a unique mutable borrow, use [`ResMut`] instead.631///632/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.633/// This will cause a panic, but can be configured to do nothing or warn once.634///635/// Use [`Option<Res<T>>`] instead if the resource might not always exist.636pub struct Res<'w, T: ?Sized + Resource> {637pub(crate) value: &'w T,638pub(crate) ticks: Ticks<'w>,639pub(crate) changed_by: MaybeLocation<&'w &'static Location<'static>>,640}641642impl<'w, T: Resource> Res<'w, T> {643/// Copies a reference to a resource.644///645/// Note that unless you actually need an instance of `Res<T>`, you should646/// prefer to just convert it to `&T` which can be freely copied.647#[expect(648clippy::should_implement_trait,649reason = "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()`.)"650)]651pub fn clone(this: &Self) -> Self {652Self {653value: this.value,654ticks: this.ticks.clone(),655changed_by: this.changed_by,656}657}658659/// Due to lifetime limitations of the `Deref` trait, this method can be used to obtain a660/// reference of the [`Resource`] with a lifetime bound to `'w` instead of the lifetime of the661/// struct itself.662pub fn into_inner(self) -> &'w T {663self.value664}665}666667impl<'w, T: Resource> From<ResMut<'w, T>> for Res<'w, T> {668fn from(res: ResMut<'w, T>) -> Self {669Self {670value: res.value,671ticks: res.ticks.into(),672changed_by: res.changed_by.map(|changed_by| &*changed_by),673}674}675}676677impl<'w, T: Resource> From<Res<'w, T>> for Ref<'w, T> {678/// Convert a `Res` into a `Ref`. This allows keeping the change-detection feature of `Ref`679/// while losing the specificity of `Res` for resources.680fn from(res: Res<'w, T>) -> Self {681Self {682value: res.value,683ticks: res.ticks,684changed_by: res.changed_by,685}686}687}688689impl<'w, 'a, T: Resource> IntoIterator for &'a Res<'w, T>690where691&'a T: IntoIterator,692{693type Item = <&'a T as IntoIterator>::Item;694type IntoIter = <&'a T as IntoIterator>::IntoIter;695696fn into_iter(self) -> Self::IntoIter {697self.value.into_iter()698}699}700change_detection_impl!(Res<'w, T>, T, Resource);701impl_debug!(Res<'w, T>, Resource);702703/// Unique mutable borrow of a [`Resource`].704///705/// See the [`Resource`] documentation for usage.706///707/// If you need a shared borrow, use [`Res`] instead.708///709/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.710/// This will cause a panic, but can be configured to do nothing or warn once.711///712/// Use [`Option<ResMut<T>>`] instead if the resource might not always exist.713pub struct ResMut<'w, T: ?Sized + Resource> {714pub(crate) value: &'w mut T,715pub(crate) ticks: TicksMut<'w>,716pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,717}718719impl<'w, 'a, T: Resource> IntoIterator for &'a ResMut<'w, T>720where721&'a T: IntoIterator,722{723type Item = <&'a T as IntoIterator>::Item;724type IntoIter = <&'a T as IntoIterator>::IntoIter;725726fn into_iter(self) -> Self::IntoIter {727self.value.into_iter()728}729}730731impl<'w, 'a, T: Resource> IntoIterator for &'a mut ResMut<'w, T>732where733&'a mut T: IntoIterator,734{735type Item = <&'a mut T as IntoIterator>::Item;736type IntoIter = <&'a mut T as IntoIterator>::IntoIter;737738fn into_iter(self) -> Self::IntoIter {739self.set_changed();740self.value.into_iter()741}742}743744change_detection_impl!(ResMut<'w, T>, T, Resource);745change_detection_mut_impl!(ResMut<'w, T>, T, Resource);746impl_methods!(ResMut<'w, T>, T, Resource);747impl_debug!(ResMut<'w, T>, Resource);748749impl<'w, T: Resource> From<ResMut<'w, T>> for Mut<'w, T> {750/// Convert this `ResMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`751/// while losing the specificity of `ResMut` for resources.752fn from(other: ResMut<'w, T>) -> Mut<'w, T> {753Mut {754value: other.value,755ticks: other.ticks,756changed_by: other.changed_by,757}758}759}760761/// Unique borrow of a non-[`Send`] resource.762///763/// Only [`Send`] resources may be accessed with the [`ResMut`] [`SystemParam`](crate::system::SystemParam). In case that the764/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct765/// the scheduler to instead run the system on the main thread so that it doesn't send the resource766/// over to another thread.767///768/// This [`SystemParam`](crate::system::SystemParam) fails validation if non-send resource doesn't exist.769/// This will cause a panic, but can be configured to do nothing or warn once.770///771/// Use [`Option<NonSendMut<T>>`] instead if the resource might not always exist.772pub struct NonSendMut<'w, T: ?Sized + 'static> {773pub(crate) value: &'w mut T,774pub(crate) ticks: TicksMut<'w>,775pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,776}777778change_detection_impl!(NonSendMut<'w, T>, T,);779change_detection_mut_impl!(NonSendMut<'w, T>, T,);780impl_methods!(NonSendMut<'w, T>, T,);781impl_debug!(NonSendMut<'w, T>,);782783impl<'w, T: 'static> From<NonSendMut<'w, T>> for Mut<'w, T> {784/// Convert this `NonSendMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`785/// while losing the specificity of `NonSendMut`.786fn from(other: NonSendMut<'w, T>) -> Mut<'w, T> {787Mut {788value: other.value,789ticks: other.ticks,790changed_by: other.changed_by,791}792}793}794795/// Shared borrow of an entity's component with access to change detection.796/// Similar to [`Mut`] but is immutable and so doesn't require unique access.797///798/// # Examples799///800/// These two systems produce the same output.801///802/// ```803/// # use bevy_ecs::change_detection::DetectChanges;804/// # use bevy_ecs::query::{Changed, With};805/// # use bevy_ecs::system::Query;806/// # use bevy_ecs::world::Ref;807/// # use bevy_ecs_macros::Component;808/// # #[derive(Component)]809/// # struct MyComponent;810///811/// fn how_many_changed_1(query: Query<(), Changed<MyComponent>>) {812/// println!("{} changed", query.iter().count());813/// }814///815/// fn how_many_changed_2(query: Query<Ref<MyComponent>>) {816/// println!("{} changed", query.iter().filter(|c| c.is_changed()).count());817/// }818/// ```819pub struct Ref<'w, T: ?Sized> {820pub(crate) value: &'w T,821pub(crate) ticks: Ticks<'w>,822pub(crate) changed_by: MaybeLocation<&'w &'static Location<'static>>,823}824825impl<'w, T: ?Sized> Ref<'w, T> {826/// Returns the reference wrapped by this type. The reference is allowed to outlive `self`, which makes this method more flexible than simply borrowing `self`.827pub fn into_inner(self) -> &'w T {828self.value829}830831/// Map `Ref` to a different type using `f`.832///833/// This doesn't do anything else than call `f` on the wrapped value.834/// This is equivalent to [`Mut::map_unchanged`].835pub fn map<U: ?Sized>(self, f: impl FnOnce(&T) -> &U) -> Ref<'w, U> {836Ref {837value: f(self.value),838ticks: self.ticks,839changed_by: self.changed_by,840}841}842843/// Create a new `Ref` using provided values.844///845/// This is an advanced feature, `Ref`s are designed to be _created_ by846/// engine-internal code and _consumed_ by end-user code.847///848/// - `value` - The value wrapped by `Ref`.849/// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.850/// - `changed` - A [`Tick`] that stores the last time the wrapped value was changed.851/// - `last_run` - A [`Tick`], occurring before `this_run`, which is used852/// as a reference to determine whether the wrapped value is newly added or changed.853/// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".854pub fn new(855value: &'w T,856added: &'w Tick,857changed: &'w Tick,858last_run: Tick,859this_run: Tick,860caller: MaybeLocation<&'w &'static Location<'static>>,861) -> Ref<'w, T> {862Ref {863value,864ticks: Ticks {865added,866changed,867last_run,868this_run,869},870changed_by: caller,871}872}873874/// Overwrite the `last_run` and `this_run` tick that are used for change detection.875///876/// This is an advanced feature. `Ref`s are usually _created_ by engine-internal code and877/// _consumed_ by end-user code.878pub fn set_ticks(&mut self, last_run: Tick, this_run: Tick) {879self.ticks.last_run = last_run;880self.ticks.this_run = this_run;881}882}883884impl<'w, 'a, T> IntoIterator for &'a Ref<'w, T>885where886&'a T: IntoIterator,887{888type Item = <&'a T as IntoIterator>::Item;889type IntoIter = <&'a T as IntoIterator>::IntoIter;890891fn into_iter(self) -> Self::IntoIter {892self.value.into_iter()893}894}895change_detection_impl!(Ref<'w, T>, T,);896impl_debug!(Ref<'w, T>,);897898/// Unique mutable borrow of an entity's component or of a resource.899///900/// This can be used in queries to access change detection from immutable query methods, as opposed901/// to `&mut T` which only provides access to change detection from mutable query methods.902///903/// ```rust904/// # use bevy_ecs::prelude::*;905/// # use bevy_ecs::query::QueryData;906/// #907/// #[derive(Component, Clone, Debug)]908/// struct Name(String);909///910/// #[derive(Component, Clone, Copy, Debug)]911/// struct Health(f32);912///913/// fn my_system(mut query: Query<(Mut<Name>, &mut Health)>) {914/// // Mutable access provides change detection information for both parameters:915/// // - `name` has type `Mut<Name>`916/// // - `health` has type `Mut<Health>`917/// for (name, health) in query.iter_mut() {918/// println!("Name: {:?} (last changed {:?})", name, name.last_changed());919/// println!("Health: {:?} (last changed: {:?})", health, health.last_changed());920/// # println!("{}{}", name.0, health.0); // Silence dead_code warning921/// }922///923/// // Immutable access only provides change detection for `Name`:924/// // - `name` has type `Ref<Name>`925/// // - `health` has type `&Health`926/// for (name, health) in query.iter() {927/// println!("Name: {:?} (last changed {:?})", name, name.last_changed());928/// println!("Health: {:?}", health);929/// }930/// }931///932/// # bevy_ecs::system::assert_is_system(my_system);933/// ```934pub struct Mut<'w, T: ?Sized> {935pub(crate) value: &'w mut T,936pub(crate) ticks: TicksMut<'w>,937pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,938}939940impl<'w, T: ?Sized> Mut<'w, T> {941/// Creates a new change-detection enabled smart pointer.942/// In almost all cases you do not need to call this method manually,943/// as instances of `Mut` will be created by engine-internal code.944///945/// Many use-cases of this method would be better served by [`Mut::map_unchanged`]946/// or [`Mut::reborrow`].947///948/// - `value` - The value wrapped by this smart pointer.949/// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.950/// - `last_changed` - A [`Tick`] that stores the last time the wrapped value was changed.951/// This will be updated to the value of `change_tick` if the returned smart pointer952/// is modified.953/// - `last_run` - A [`Tick`], occurring before `this_run`, which is used954/// as a reference to determine whether the wrapped value is newly added or changed.955/// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".956pub fn new(957value: &'w mut T,958added: &'w mut Tick,959last_changed: &'w mut Tick,960last_run: Tick,961this_run: Tick,962caller: MaybeLocation<&'w mut &'static Location<'static>>,963) -> Self {964Self {965value,966ticks: TicksMut {967added,968changed: last_changed,969last_run,970this_run,971},972changed_by: caller,973}974}975976/// Overwrite the `last_run` and `this_run` tick that are used for change detection.977///978/// This is an advanced feature. `Mut`s are usually _created_ by engine-internal code and979/// _consumed_ by end-user code.980pub fn set_ticks(&mut self, last_run: Tick, this_run: Tick) {981self.ticks.last_run = last_run;982self.ticks.this_run = this_run;983}984}985986impl<'w, T: ?Sized> From<Mut<'w, T>> for Ref<'w, T> {987fn from(mut_ref: Mut<'w, T>) -> Self {988Self {989value: mut_ref.value,990ticks: mut_ref.ticks.into(),991changed_by: mut_ref.changed_by.map(|changed_by| &*changed_by),992}993}994}995996impl<'w, 'a, T> IntoIterator for &'a Mut<'w, T>997where998&'a T: IntoIterator,999{1000type Item = <&'a T as IntoIterator>::Item;1001type IntoIter = <&'a T as IntoIterator>::IntoIter;10021003fn into_iter(self) -> Self::IntoIter {1004self.value.into_iter()1005}1006}10071008impl<'w, 'a, T> IntoIterator for &'a mut Mut<'w, T>1009where1010&'a mut T: IntoIterator,1011{1012type Item = <&'a mut T as IntoIterator>::Item;1013type IntoIter = <&'a mut T as IntoIterator>::IntoIter;10141015fn into_iter(self) -> Self::IntoIter {1016self.set_changed();1017self.value.into_iter()1018}1019}10201021change_detection_impl!(Mut<'w, T>, T,);1022change_detection_mut_impl!(Mut<'w, T>, T,);1023impl_methods!(Mut<'w, T>, T,);1024impl_debug!(Mut<'w, T>,);10251026/// Unique mutable borrow of resources or an entity's component.1027///1028/// Similar to [`Mut`], but not generic over the component type, instead1029/// exposing the raw pointer as a `*mut ()`.1030///1031/// Usually you don't need to use this and can instead use the APIs returning a1032/// [`Mut`], but in situations where the types are not known at compile time1033/// or are defined outside of rust this can be used.1034pub struct MutUntyped<'w> {1035pub(crate) value: PtrMut<'w>,1036pub(crate) ticks: TicksMut<'w>,1037pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,1038}10391040impl<'w> MutUntyped<'w> {1041/// Returns the pointer to the value, marking it as changed.1042///1043/// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).1044#[inline]1045pub fn into_inner(mut self) -> PtrMut<'w> {1046self.set_changed();1047self.value1048}10491050/// Returns a [`MutUntyped`] with a smaller lifetime.1051/// This is useful if you have `&mut MutUntyped`, but you need a `MutUntyped`.1052#[inline]1053pub fn reborrow(&mut self) -> MutUntyped<'_> {1054MutUntyped {1055value: self.value.reborrow(),1056ticks: TicksMut {1057added: self.ticks.added,1058changed: self.ticks.changed,1059last_run: self.ticks.last_run,1060this_run: self.ticks.this_run,1061},1062changed_by: self.changed_by.as_deref_mut(),1063}1064}10651066/// Returns `true` if this value was changed or mutably dereferenced1067/// either since a specific change tick.1068pub fn has_changed_since(&self, tick: Tick) -> bool {1069self.ticks.changed.is_newer_than(tick, self.ticks.this_run)1070}10711072/// Returns a pointer to the value without taking ownership of this smart pointer, marking it as changed.1073///1074/// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).1075#[inline]1076pub fn as_mut(&mut self) -> PtrMut<'_> {1077self.set_changed();1078self.value.reborrow()1079}10801081/// Returns an immutable pointer to the value without taking ownership.1082#[inline]1083pub fn as_ref(&self) -> Ptr<'_> {1084self.value.as_ref()1085}10861087/// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value,1088/// without flagging a change.1089/// This function is the untyped equivalent of [`Mut::map_unchanged`].1090///1091/// 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.1092///1093/// If you know the type of the value you can do1094/// ```no_run1095/// # use bevy_ecs::change_detection::{Mut, MutUntyped};1096/// # let mut_untyped: MutUntyped = unimplemented!();1097/// // SAFETY: ptr is of type `u8`1098/// mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::<u8>() });1099/// ```1100/// If you have a [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) that you know belongs to this [`MutUntyped`],1101/// you can do1102/// ```no_run1103/// # use bevy_ecs::change_detection::{Mut, MutUntyped};1104/// # let mut_untyped: MutUntyped = unimplemented!();1105/// # let reflect_from_ptr: bevy_reflect::ReflectFromPtr = unimplemented!();1106/// // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped`1107/// mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_mut(ptr) });1108/// ```1109pub fn map_unchanged<T: ?Sized>(self, f: impl FnOnce(PtrMut<'w>) -> &'w mut T) -> Mut<'w, T> {1110Mut {1111value: f(self.value),1112ticks: self.ticks,1113changed_by: self.changed_by,1114}1115}11161117/// Transforms this [`MutUntyped`] into a [`Mut<T>`] with the same lifetime.1118///1119/// # Safety1120/// - `T` must be the erased pointee type for this [`MutUntyped`].1121pub unsafe fn with_type<T>(self) -> Mut<'w, T> {1122Mut {1123// SAFETY: `value` is `Aligned` and caller ensures the pointee type is `T`.1124value: unsafe { self.value.deref_mut() },1125ticks: self.ticks,1126// SAFETY: `caller` is `Aligned`.1127changed_by: self.changed_by,1128}1129}1130}11311132impl<'w> DetectChanges for MutUntyped<'w> {1133#[inline]1134fn is_added(&self) -> bool {1135self.ticks1136.added1137.is_newer_than(self.ticks.last_run, self.ticks.this_run)1138}11391140#[inline]1141fn is_changed(&self) -> bool {1142self.ticks1143.changed1144.is_newer_than(self.ticks.last_run, self.ticks.this_run)1145}11461147#[inline]1148fn last_changed(&self) -> Tick {1149*self.ticks.changed1150}11511152#[inline]1153fn changed_by(&self) -> MaybeLocation {1154self.changed_by.copied()1155}11561157#[inline]1158fn added(&self) -> Tick {1159*self.ticks.added1160}1161}11621163impl<'w> DetectChangesMut for MutUntyped<'w> {1164type Inner = PtrMut<'w>;11651166#[inline]1167#[track_caller]1168fn set_changed(&mut self) {1169*self.ticks.changed = self.ticks.this_run;1170self.changed_by.assign(MaybeLocation::caller());1171}11721173#[inline]1174#[track_caller]1175fn set_added(&mut self) {1176*self.ticks.changed = self.ticks.this_run;1177*self.ticks.added = self.ticks.this_run;1178self.changed_by.assign(MaybeLocation::caller());1179}11801181#[inline]1182#[track_caller]1183fn set_last_changed(&mut self, last_changed: Tick) {1184*self.ticks.changed = last_changed;1185self.changed_by.assign(MaybeLocation::caller());1186}11871188#[inline]1189#[track_caller]1190fn set_last_added(&mut self, last_added: Tick) {1191*self.ticks.added = last_added;1192*self.ticks.changed = last_added;1193self.changed_by.assign(MaybeLocation::caller());1194}11951196#[inline]1197#[track_caller]1198fn bypass_change_detection(&mut self) -> &mut Self::Inner {1199&mut self.value1200}1201}12021203impl core::fmt::Debug for MutUntyped<'_> {1204fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {1205f.debug_tuple("MutUntyped")1206.field(&self.value.as_ptr())1207.finish()1208}1209}12101211impl<'w, T> From<Mut<'w, T>> for MutUntyped<'w> {1212fn from(value: Mut<'w, T>) -> Self {1213MutUntyped {1214value: value.value.into(),1215ticks: value.ticks,1216changed_by: value.changed_by,1217}1218}1219}12201221/// A value that contains a `T` if the `track_location` feature is enabled,1222/// and is a ZST if it is not.1223///1224/// The overall API is similar to [`Option`], but whether the value is `Some` or `None` is set at compile1225/// time and is the same for all values.1226///1227/// If the `track_location` feature is disabled, then all functions on this type that return1228/// an `MaybeLocation` will have an empty body and should be removed by the optimizer.1229///1230/// This allows code to be written that will be checked by the compiler even when the feature is disabled,1231/// but that will be entirely removed during compilation.1232#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]1233#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]1234pub struct MaybeLocation<T: ?Sized = &'static Location<'static>> {1235#[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]1236marker: PhantomData<T>,1237#[cfg(feature = "track_location")]1238value: T,1239}12401241impl<T: core::fmt::Display> core::fmt::Display for MaybeLocation<T> {1242fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {1243#[cfg(feature = "track_location")]1244{1245self.value.fmt(_f)?;1246}1247Ok(())1248}1249}12501251impl<T> MaybeLocation<T> {1252/// Constructs a new `MaybeLocation` that wraps the given value.1253///1254/// This may only accept `Copy` types,1255/// since it needs to drop the value if the `track_location` feature is disabled,1256/// and non-`Copy` types cannot be dropped in `const` context.1257/// Use [`new_with`][Self::new_with] if you need to construct a non-`Copy` value.1258///1259/// # See also1260/// - [`new_with`][Self::new_with] to initialize using a closure.1261/// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.1262#[inline]1263pub const fn new(_value: T) -> Self1264where1265T: Copy,1266{1267Self {1268#[cfg(feature = "track_location")]1269value: _value,1270marker: PhantomData,1271}1272}12731274/// Constructs a new `MaybeLocation` that wraps the result of the given closure.1275///1276/// # See also1277/// - [`new`][Self::new] to initialize using a value.1278/// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.1279#[inline]1280pub fn new_with(_f: impl FnOnce() -> T) -> Self {1281Self {1282#[cfg(feature = "track_location")]1283value: _f(),1284marker: PhantomData,1285}1286}12871288/// Maps an `MaybeLocation<T> `to `MaybeLocation<U>` by applying a function to a contained value.1289#[inline]1290pub fn map<U>(self, _f: impl FnOnce(T) -> U) -> MaybeLocation<U> {1291MaybeLocation {1292#[cfg(feature = "track_location")]1293value: _f(self.value),1294marker: PhantomData,1295}1296}12971298/// Converts a pair of `MaybeLocation` values to an `MaybeLocation` of a tuple.1299#[inline]1300pub fn zip<U>(self, _other: MaybeLocation<U>) -> MaybeLocation<(T, U)> {1301MaybeLocation {1302#[cfg(feature = "track_location")]1303value: (self.value, _other.value),1304marker: PhantomData,1305}1306}13071308/// Returns the contained value or a default.1309/// If the `track_location` feature is enabled, this always returns the contained value.1310/// If it is disabled, this always returns `T::Default()`.1311#[inline]1312pub fn unwrap_or_default(self) -> T1313where1314T: Default,1315{1316self.into_option().unwrap_or_default()1317}13181319/// Converts an `MaybeLocation` to an [`Option`] to allow run-time branching.1320/// If the `track_location` feature is enabled, this always returns `Some`.1321/// If it is disabled, this always returns `None`.1322#[inline]1323pub fn into_option(self) -> Option<T> {1324#[cfg(feature = "track_location")]1325{1326Some(self.value)1327}1328#[cfg(not(feature = "track_location"))]1329{1330None1331}1332}1333}13341335impl<T> MaybeLocation<Option<T>> {1336/// Constructs a new `MaybeLocation` that wraps the result of the given closure.1337/// If the closure returns `Some`, it unwraps the inner value.1338///1339/// # See also1340/// - [`new`][Self::new] to initialize using a value.1341/// - [`new_with`][Self::new_with] to initialize using a closure.1342#[inline]1343pub fn new_with_flattened(_f: impl FnOnce() -> Option<MaybeLocation<T>>) -> Self {1344Self {1345#[cfg(feature = "track_location")]1346value: _f().map(|value| value.value),1347marker: PhantomData,1348}1349}13501351/// Transposes a `MaybeLocation` of an [`Option`] into an [`Option`] of a `MaybeLocation`.1352///1353/// This can be useful if you want to use the `?` operator to exit early1354/// if the `track_location` feature is enabled but the value is not found.1355///1356/// If the `track_location` feature is enabled,1357/// this returns `Some` if the inner value is `Some`1358/// and `None` if the inner value is `None`.1359///1360/// If it is disabled, this always returns `Some`.1361///1362/// # Example1363///1364/// ```1365/// # use bevy_ecs::{change_detection::MaybeLocation, world::World};1366/// # use core::panic::Location;1367/// #1368/// # fn test() -> Option<()> {1369/// let mut world = World::new();1370/// let entity = world.spawn(()).id();1371/// let location: MaybeLocation<Option<&'static Location<'static>>> =1372/// world.entities().entity_get_spawned_or_despawned_by(entity);1373/// let location: MaybeLocation<&'static Location<'static>> = location.transpose()?;1374/// # Some(())1375/// # }1376/// # test();1377/// ```1378///1379/// # See also1380///1381/// - [`into_option`][Self::into_option] to convert to an `Option<Option<T>>`.1382/// When used with [`Option::flatten`], this will have a similar effect,1383/// but will return `None` when the `track_location` feature is disabled.1384#[inline]1385pub fn transpose(self) -> Option<MaybeLocation<T>> {1386#[cfg(feature = "track_location")]1387{1388self.value.map(|value| MaybeLocation {1389value,1390marker: PhantomData,1391})1392}1393#[cfg(not(feature = "track_location"))]1394{1395Some(MaybeLocation {1396marker: PhantomData,1397})1398}1399}1400}14011402impl<T> MaybeLocation<&T> {1403/// Maps an `MaybeLocation<&T>` to an `MaybeLocation<T>` by copying the contents.1404#[inline]1405pub const fn copied(&self) -> MaybeLocation<T>1406where1407T: Copy,1408{1409MaybeLocation {1410#[cfg(feature = "track_location")]1411value: *self.value,1412marker: PhantomData,1413}1414}1415}14161417impl<T> MaybeLocation<&mut T> {1418/// Maps an `MaybeLocation<&mut T>` to an `MaybeLocation<T>` by copying the contents.1419#[inline]1420pub const fn copied(&self) -> MaybeLocation<T>1421where1422T: Copy,1423{1424MaybeLocation {1425#[cfg(feature = "track_location")]1426value: *self.value,1427marker: PhantomData,1428}1429}14301431/// Assigns the contents of an `MaybeLocation<T>` to an `MaybeLocation<&mut T>`.1432#[inline]1433pub fn assign(&mut self, _value: MaybeLocation<T>) {1434#[cfg(feature = "track_location")]1435{1436*self.value = _value.value;1437}1438}1439}14401441impl<T: ?Sized> MaybeLocation<T> {1442/// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T>`.1443#[inline]1444pub const fn as_ref(&self) -> MaybeLocation<&T> {1445MaybeLocation {1446#[cfg(feature = "track_location")]1447value: &self.value,1448marker: PhantomData,1449}1450}14511452/// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T>`.1453#[inline]1454pub const fn as_mut(&mut self) -> MaybeLocation<&mut T> {1455MaybeLocation {1456#[cfg(feature = "track_location")]1457value: &mut self.value,1458marker: PhantomData,1459}1460}14611462/// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T::Target>`.1463#[inline]1464pub fn as_deref(&self) -> MaybeLocation<&T::Target>1465where1466T: Deref,1467{1468MaybeLocation {1469#[cfg(feature = "track_location")]1470value: &*self.value,1471marker: PhantomData,1472}1473}14741475/// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T::Target>`.1476#[inline]1477pub fn as_deref_mut(&mut self) -> MaybeLocation<&mut T::Target>1478where1479T: DerefMut,1480{1481MaybeLocation {1482#[cfg(feature = "track_location")]1483value: &mut *self.value,1484marker: PhantomData,1485}1486}1487}14881489impl MaybeLocation {1490/// Returns the source location of the caller of this function. If that function's caller is1491/// annotated then its call location will be returned, and so on up the stack to the first call1492/// within a non-tracked function body.1493#[inline]1494#[track_caller]1495pub const fn caller() -> Self {1496// Note that this cannot use `new_with`, since `FnOnce` invocations cannot be annotated with `#[track_caller]`.1497MaybeLocation {1498#[cfg(feature = "track_location")]1499value: Location::caller(),1500marker: PhantomData,1501}1502}1503}15041505#[cfg(test)]1506mod tests {1507use bevy_ecs_macros::Resource;1508use bevy_ptr::PtrMut;1509use bevy_reflect::{FromType, ReflectFromPtr};1510use core::ops::{Deref, DerefMut};15111512use crate::{1513change_detection::{1514MaybeLocation, Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD,1515MAX_CHANGE_AGE,1516},1517component::{Component, ComponentTicks, Tick},1518system::{IntoSystem, Single, System},1519world::World,1520};15211522use super::{DetectChanges, DetectChangesMut, MutUntyped};15231524#[derive(Component, PartialEq)]1525struct C;15261527#[derive(Resource)]1528struct R;15291530#[derive(Resource, PartialEq)]1531struct R2(u8);15321533impl Deref for R2 {1534type Target = u8;1535fn deref(&self) -> &u8 {1536&self.01537}1538}15391540impl DerefMut for R2 {1541fn deref_mut(&mut self) -> &mut u8 {1542&mut self.01543}1544}15451546#[test]1547fn change_expiration() {1548fn change_detected(query: Option<Single<Ref<C>>>) -> bool {1549query.unwrap().is_changed()1550}15511552fn change_expired(query: Option<Single<Ref<C>>>) -> bool {1553query.unwrap().is_changed()1554}15551556let mut world = World::new();15571558// component added: 1, changed: 11559world.spawn(C);15601561let mut change_detected_system = IntoSystem::into_system(change_detected);1562let mut change_expired_system = IntoSystem::into_system(change_expired);1563change_detected_system.initialize(&mut world);1564change_expired_system.initialize(&mut world);15651566// world: 1, system last ran: 0, component changed: 11567// The spawn will be detected since it happened after the system "last ran".1568assert!(change_detected_system.run((), &mut world).unwrap());15691570// world: 1 + MAX_CHANGE_AGE1571let change_tick = world.change_tick.get_mut();1572*change_tick = change_tick.wrapping_add(MAX_CHANGE_AGE);15731574// Both the system and component appeared `MAX_CHANGE_AGE` ticks ago.1575// Since we clamp things to `MAX_CHANGE_AGE` for determinism,1576// `ComponentTicks::is_changed` will now see `MAX_CHANGE_AGE > MAX_CHANGE_AGE`1577// and return `false`.1578assert!(!change_expired_system.run((), &mut world).unwrap());1579}15801581#[test]1582fn change_tick_wraparound() {1583let mut world = World::new();1584world.last_change_tick = Tick::new(u32::MAX);1585*world.change_tick.get_mut() = 0;15861587// component added: 0, changed: 01588world.spawn(C);15891590world.increment_change_tick();15911592// Since the world is always ahead, as long as changes can't get older than `u32::MAX` (which we ensure),1593// the wrapping difference will always be positive, so wraparound doesn't matter.1594let mut query = world.query::<Ref<C>>();1595assert!(query.single(&world).unwrap().is_changed());1596}15971598#[test]1599fn change_tick_scan() {1600let mut world = World::new();16011602// component added: 1, changed: 11603world.spawn(C);16041605// a bunch of stuff happens, the component is now older than `MAX_CHANGE_AGE`1606*world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD;1607let change_tick = world.change_tick();16081609let mut query = world.query::<Ref<C>>();1610for tracker in query.iter(&world) {1611let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();1612let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();1613assert!(ticks_since_insert > MAX_CHANGE_AGE);1614assert!(ticks_since_change > MAX_CHANGE_AGE);1615}16161617// scan change ticks and clamp those at risk of overflow1618world.check_change_ticks();16191620for tracker in query.iter(&world) {1621let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();1622let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();1623assert_eq!(ticks_since_insert, MAX_CHANGE_AGE);1624assert_eq!(ticks_since_change, MAX_CHANGE_AGE);1625}1626}16271628#[test]1629fn mut_from_res_mut() {1630let mut component_ticks = ComponentTicks {1631added: Tick::new(1),1632changed: Tick::new(2),1633};1634let ticks = TicksMut {1635added: &mut component_ticks.added,1636changed: &mut component_ticks.changed,1637last_run: Tick::new(3),1638this_run: Tick::new(4),1639};1640let mut res = R {};1641let mut caller = MaybeLocation::caller();16421643let res_mut = ResMut {1644value: &mut res,1645ticks,1646changed_by: caller.as_mut(),1647};16481649let into_mut: Mut<R> = res_mut.into();1650assert_eq!(1, into_mut.ticks.added.get());1651assert_eq!(2, into_mut.ticks.changed.get());1652assert_eq!(3, into_mut.ticks.last_run.get());1653assert_eq!(4, into_mut.ticks.this_run.get());1654}16551656#[test]1657fn mut_new() {1658let mut component_ticks = ComponentTicks {1659added: Tick::new(1),1660changed: Tick::new(3),1661};1662let mut res = R {};1663let mut caller = MaybeLocation::caller();16641665let val = Mut::new(1666&mut res,1667&mut component_ticks.added,1668&mut component_ticks.changed,1669Tick::new(2), // last_run1670Tick::new(4), // this_run1671caller.as_mut(),1672);16731674assert!(!val.is_added());1675assert!(val.is_changed());1676}16771678#[test]1679fn mut_from_non_send_mut() {1680let mut component_ticks = ComponentTicks {1681added: Tick::new(1),1682changed: Tick::new(2),1683};1684let ticks = TicksMut {1685added: &mut component_ticks.added,1686changed: &mut component_ticks.changed,1687last_run: Tick::new(3),1688this_run: Tick::new(4),1689};1690let mut res = R {};1691let mut caller = MaybeLocation::caller();16921693let non_send_mut = NonSendMut {1694value: &mut res,1695ticks,1696changed_by: caller.as_mut(),1697};16981699let into_mut: Mut<R> = non_send_mut.into();1700assert_eq!(1, into_mut.ticks.added.get());1701assert_eq!(2, into_mut.ticks.changed.get());1702assert_eq!(3, into_mut.ticks.last_run.get());1703assert_eq!(4, into_mut.ticks.this_run.get());1704}17051706#[test]1707fn map_mut() {1708use super::*;1709struct Outer(i64);17101711let last_run = Tick::new(2);1712let this_run = Tick::new(3);1713let mut component_ticks = ComponentTicks {1714added: Tick::new(1),1715changed: Tick::new(2),1716};1717let ticks = TicksMut {1718added: &mut component_ticks.added,1719changed: &mut component_ticks.changed,1720last_run,1721this_run,1722};17231724let mut outer = Outer(0);1725let mut caller = MaybeLocation::caller();17261727let ptr = Mut {1728value: &mut outer,1729ticks,1730changed_by: caller.as_mut(),1731};1732assert!(!ptr.is_changed());17331734// Perform a mapping operation.1735let mut inner = ptr.map_unchanged(|x| &mut x.0);1736assert!(!inner.is_changed());17371738// Mutate the inner value.1739*inner = 64;1740assert!(inner.is_changed());1741// Modifying one field of a component should flag a change for the entire component.1742assert!(component_ticks.is_changed(last_run, this_run));1743}17441745#[test]1746fn set_if_neq() {1747let mut world = World::new();17481749world.insert_resource(R2(0));1750// Resources are Changed when first added1751world.increment_change_tick();1752// This is required to update world::last_change_tick1753world.clear_trackers();17541755let mut r = world.resource_mut::<R2>();1756assert!(!r.is_changed(), "Resource must begin unchanged.");17571758r.set_if_neq(R2(0));1759assert!(1760!r.is_changed(),1761"Resource must not be changed after setting to the same value."1762);17631764r.set_if_neq(R2(3));1765assert!(1766r.is_changed(),1767"Resource must be changed after setting to a different value."1768);1769}17701771#[test]1772fn as_deref_mut() {1773let mut world = World::new();17741775world.insert_resource(R2(0));1776// Resources are Changed when first added1777world.increment_change_tick();1778// This is required to update world::last_change_tick1779world.clear_trackers();17801781let mut r = world.resource_mut::<R2>();1782assert!(!r.is_changed(), "Resource must begin unchanged.");17831784let mut r = r.as_deref_mut();1785assert!(1786!r.is_changed(),1787"Dereferencing should not mark the item as changed yet"1788);17891790r.set_if_neq(3);1791assert!(1792r.is_changed(),1793"Resource must be changed after setting to a different value."1794);1795}17961797#[test]1798fn mut_untyped_to_reflect() {1799let last_run = Tick::new(2);1800let this_run = Tick::new(3);1801let mut component_ticks = ComponentTicks {1802added: Tick::new(1),1803changed: Tick::new(2),1804};1805let ticks = TicksMut {1806added: &mut component_ticks.added,1807changed: &mut component_ticks.changed,1808last_run,1809this_run,1810};18111812let mut value: i32 = 5;1813let mut caller = MaybeLocation::caller();18141815let value = MutUntyped {1816value: PtrMut::from(&mut value),1817ticks,1818changed_by: caller.as_mut(),1819};18201821let reflect_from_ptr = <ReflectFromPtr as FromType<i32>>::from_type();18221823let mut new = value.map_unchanged(|ptr| {1824// SAFETY: The underlying type of `ptr` matches `reflect_from_ptr`.1825unsafe { reflect_from_ptr.as_reflect_mut(ptr) }1826});18271828assert!(!new.is_changed());18291830new.reflect_mut();18311832assert!(new.is_changed());1833}18341835#[test]1836fn mut_untyped_from_mut() {1837let mut component_ticks = ComponentTicks {1838added: Tick::new(1),1839changed: Tick::new(2),1840};1841let ticks = TicksMut {1842added: &mut component_ticks.added,1843changed: &mut component_ticks.changed,1844last_run: Tick::new(3),1845this_run: Tick::new(4),1846};1847let mut c = C {};1848let mut caller = MaybeLocation::caller();18491850let mut_typed = Mut {1851value: &mut c,1852ticks,1853changed_by: caller.as_mut(),1854};18551856let into_mut: MutUntyped = mut_typed.into();1857assert_eq!(1, into_mut.ticks.added.get());1858assert_eq!(2, into_mut.ticks.changed.get());1859assert_eq!(3, into_mut.ticks.last_run.get());1860assert_eq!(4, into_mut.ticks.this_run.get());1861}1862}186318641865