bevy_ecs/change_detection/
params.rs

1use crate::{
2    change_detection::{traits::*, ComponentTickCells, MaybeLocation, Tick},
3    ptr::PtrMut,
4    resource::Resource,
5};
6use bevy_ptr::{Ptr, UnsafeCellDeref};
7use core::{
8    ops::{Deref, DerefMut},
9    panic::Location,
10};
11
12/// Used by immutable query parameters (such as [`Ref`] and [`Res`])
13/// to store immutable access to the [`Tick`]s of a single component or resource.
14#[derive(Clone)]
15pub(crate) struct ComponentTicksRef<'w> {
16    pub(crate) added: &'w Tick,
17    pub(crate) changed: &'w Tick,
18    pub(crate) changed_by: MaybeLocation<&'w &'static Location<'static>>,
19    pub(crate) last_run: Tick,
20    pub(crate) this_run: Tick,
21}
22
23impl<'w> ComponentTicksRef<'w> {
24    /// # Safety
25    /// This should never alias the underlying ticks with a mutable one such as `ComponentTicksMut`.
26    #[inline]
27    pub(crate) unsafe fn from_tick_cells(
28        cells: ComponentTickCells<'w>,
29        last_run: Tick,
30        this_run: Tick,
31    ) -> Self {
32        Self {
33            // SAFETY: Caller ensures there is no mutable access to the cell.
34            added: unsafe { cells.added.deref() },
35            // SAFETY: Caller ensures there is no mutable access to the cell.
36            changed: unsafe { cells.changed.deref() },
37            // SAFETY: Caller ensures there is no mutable access to the cell.
38            changed_by: unsafe { cells.changed_by.map(|changed_by| changed_by.deref()) },
39            last_run,
40            this_run,
41        }
42    }
43}
44
45/// Used by mutable query parameters (such as [`Mut`] and [`ResMut`])
46/// to store mutable access to the [`Tick`]s of a single component or resource.
47pub(crate) struct ComponentTicksMut<'w> {
48    pub(crate) added: &'w mut Tick,
49    pub(crate) changed: &'w mut Tick,
50    pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
51    pub(crate) last_run: Tick,
52    pub(crate) this_run: Tick,
53}
54
55impl<'w> ComponentTicksMut<'w> {
56    /// # Safety
57    /// This should never alias the underlying ticks. All access must be unique.
58    #[inline]
59    pub(crate) unsafe fn from_tick_cells(
60        cells: ComponentTickCells<'w>,
61        last_run: Tick,
62        this_run: Tick,
63    ) -> Self {
64        Self {
65            // SAFETY: Caller ensures there is no alias to the cell.
66            added: unsafe { cells.added.deref_mut() },
67            // SAFETY: Caller ensures there is no alias to the cell.
68            changed: unsafe { cells.changed.deref_mut() },
69            // SAFETY: Caller ensures there is no alias to the cell.
70            changed_by: unsafe { cells.changed_by.map(|changed_by| changed_by.deref_mut()) },
71            last_run,
72            this_run,
73        }
74    }
75}
76
77impl<'w> From<ComponentTicksMut<'w>> for ComponentTicksRef<'w> {
78    fn from(ticks: ComponentTicksMut<'w>) -> Self {
79        ComponentTicksRef {
80            added: ticks.added,
81            changed: ticks.changed,
82            changed_by: ticks.changed_by.map(|changed_by| &*changed_by),
83            last_run: ticks.last_run,
84            this_run: ticks.this_run,
85        }
86    }
87}
88
89/// Shared borrow of a [`Resource`].
90///
91/// See the [`Resource`] documentation for usage.
92///
93/// If you need a unique mutable borrow, use [`ResMut`] instead.
94///
95/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.
96/// This will cause a panic, but can be configured to do nothing or warn once.
97///
98/// Use [`Option<Res<T>>`] instead if the resource might not always exist.
99pub struct Res<'w, T: ?Sized + Resource> {
100    pub(crate) value: &'w T,
101    pub(crate) ticks: ComponentTicksRef<'w>,
102}
103
104impl<'w, T: Resource> Res<'w, T> {
105    /// Copies a reference to a resource.
106    ///
107    /// Note that unless you actually need an instance of `Res<T>`, you should
108    /// prefer to just convert it to `&T` which can be freely copied.
109    #[expect(
110        clippy::should_implement_trait,
111        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()`.)"
112    )]
113    pub fn clone(this: &Self) -> Self {
114        Self {
115            value: this.value,
116            ticks: this.ticks.clone(),
117        }
118    }
119
120    /// Due to lifetime limitations of the `Deref` trait, this method can be used to obtain a
121    /// reference of the [`Resource`] with a lifetime bound to `'w` instead of the lifetime of the
122    /// struct itself.
123    pub fn into_inner(self) -> &'w T {
124        self.value
125    }
126}
127
128impl<'w, T: Resource> From<ResMut<'w, T>> for Res<'w, T> {
129    fn from(res: ResMut<'w, T>) -> Self {
130        Self {
131            value: res.value,
132            ticks: res.ticks.into(),
133        }
134    }
135}
136
137impl<'w, T: Resource> From<Res<'w, T>> for Ref<'w, T> {
138    /// Convert a `Res` into a `Ref`. This allows keeping the change-detection feature of `Ref`
139    /// while losing the specificity of `Res` for resources.
140    fn from(res: Res<'w, T>) -> Self {
141        Self {
142            value: res.value,
143            ticks: res.ticks,
144        }
145    }
146}
147
148impl<'w, 'a, T: Resource> IntoIterator for &'a Res<'w, T>
149where
150    &'a T: IntoIterator,
151{
152    type Item = <&'a T as IntoIterator>::Item;
153    type IntoIter = <&'a T as IntoIterator>::IntoIter;
154
155    fn into_iter(self) -> Self::IntoIter {
156        self.value.into_iter()
157    }
158}
159change_detection_impl!(Res<'w, T>, T, Resource);
160impl_debug!(Res<'w, T>, Resource);
161
162/// Unique mutable borrow of a [`Resource`].
163///
164/// See the [`Resource`] documentation for usage.
165///
166/// If you need a shared borrow, use [`Res`] instead.
167///
168/// This [`SystemParam`](crate::system::SystemParam) fails validation if resource doesn't exist.
169/// This will cause a panic, but can be configured to do nothing or warn once.
170///
171/// Use [`Option<ResMut<T>>`] instead if the resource might not always exist.
172pub struct ResMut<'w, T: ?Sized + Resource> {
173    pub(crate) value: &'w mut T,
174    pub(crate) ticks: ComponentTicksMut<'w>,
175}
176
177impl<'w, 'a, T: Resource> IntoIterator for &'a ResMut<'w, T>
178where
179    &'a T: IntoIterator,
180{
181    type Item = <&'a T as IntoIterator>::Item;
182    type IntoIter = <&'a T as IntoIterator>::IntoIter;
183
184    fn into_iter(self) -> Self::IntoIter {
185        self.value.into_iter()
186    }
187}
188
189impl<'w, 'a, T: Resource> IntoIterator for &'a mut ResMut<'w, T>
190where
191    &'a mut T: IntoIterator,
192{
193    type Item = <&'a mut T as IntoIterator>::Item;
194    type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
195
196    fn into_iter(self) -> Self::IntoIter {
197        self.set_changed();
198        self.value.into_iter()
199    }
200}
201
202change_detection_impl!(ResMut<'w, T>, T, Resource);
203change_detection_mut_impl!(ResMut<'w, T>, T, Resource);
204impl_methods!(ResMut<'w, T>, T, Resource);
205impl_debug!(ResMut<'w, T>, Resource);
206
207impl<'w, T: Resource> From<ResMut<'w, T>> for Mut<'w, T> {
208    /// Convert this `ResMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
209    /// while losing the specificity of `ResMut` for resources.
210    fn from(other: ResMut<'w, T>) -> Mut<'w, T> {
211        Mut {
212            value: other.value,
213            ticks: other.ticks,
214        }
215    }
216}
217
218/// Shared borrow of a non-[`Send`] resource.
219///
220/// Only [`Send`] resources may be accessed with the [`Res`] [`SystemParam`](crate::system::SystemParam). In case that the
221/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct
222/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
223/// over to another thread.
224///
225/// This [`SystemParam`](crate::system::SystemParam) fails validation if the non-send resource doesn't exist.
226/// This will cause a panic, but can be configured to do nothing or warn once.
227///
228/// Use [`Option<NonSend<T>>`] instead if the resource might not always exist.
229pub struct NonSend<'w, T: ?Sized + 'static> {
230    pub(crate) value: &'w T,
231    pub(crate) ticks: ComponentTicksRef<'w>,
232}
233
234change_detection_impl!(NonSend<'w, T>, T,);
235impl_debug!(NonSend<'w, T>,);
236
237impl<'w, T> From<NonSendMut<'w, T>> for NonSend<'w, T> {
238    fn from(other: NonSendMut<'w, T>) -> Self {
239        Self {
240            value: other.value,
241            ticks: other.ticks.into(),
242        }
243    }
244}
245
246/// Unique borrow of a non-[`Send`] resource.
247///
248/// Only [`Send`] resources may be accessed with the [`ResMut`] [`SystemParam`](crate::system::SystemParam). In case that the
249/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct
250/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
251/// over to another thread.
252///
253/// This [`SystemParam`](crate::system::SystemParam) fails validation if non-send resource doesn't exist.
254/// This will cause a panic, but can be configured to do nothing or warn once.
255///
256/// Use [`Option<NonSendMut<T>>`] instead if the resource might not always exist.
257pub struct NonSendMut<'w, T: ?Sized + 'static> {
258    pub(crate) value: &'w mut T,
259    pub(crate) ticks: ComponentTicksMut<'w>,
260}
261
262change_detection_impl!(NonSendMut<'w, T>, T,);
263change_detection_mut_impl!(NonSendMut<'w, T>, T,);
264impl_methods!(NonSendMut<'w, T>, T,);
265impl_debug!(NonSendMut<'w, T>,);
266
267impl<'w, T: 'static> From<NonSendMut<'w, T>> for Mut<'w, T> {
268    /// Convert this `NonSendMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
269    /// while losing the specificity of `NonSendMut`.
270    fn from(other: NonSendMut<'w, T>) -> Mut<'w, T> {
271        Mut {
272            value: other.value,
273            ticks: other.ticks,
274        }
275    }
276}
277
278/// Shared borrow of an entity's component with access to change detection.
279/// Similar to [`Mut`] but is immutable and so doesn't require unique access.
280///
281/// # Examples
282///
283/// These two systems produce the same output.
284///
285/// ```
286/// # use bevy_ecs::change_detection::DetectChanges;
287/// # use bevy_ecs::query::{Changed, With};
288/// # use bevy_ecs::system::Query;
289/// # use bevy_ecs::world::Ref;
290/// # use bevy_ecs_macros::Component;
291/// # #[derive(Component)]
292/// # struct MyComponent;
293///
294/// fn how_many_changed_1(query: Query<(), Changed<MyComponent>>) {
295///     println!("{} changed", query.iter().count());
296/// }
297///
298/// fn how_many_changed_2(query: Query<Ref<MyComponent>>) {
299///     println!("{} changed", query.iter().filter(|c| c.is_changed()).count());
300/// }
301/// ```
302pub struct Ref<'w, T: ?Sized> {
303    pub(crate) value: &'w T,
304    pub(crate) ticks: ComponentTicksRef<'w>,
305}
306
307impl<'w, T: ?Sized> Ref<'w, T> {
308    /// Returns the reference wrapped by this type. The reference is allowed to outlive `self`, which makes this method more flexible than simply borrowing `self`.
309    pub fn into_inner(self) -> &'w T {
310        self.value
311    }
312
313    /// Map `Ref` to a different type using `f`.
314    ///
315    /// This doesn't do anything else than call `f` on the wrapped value.
316    /// This is equivalent to [`Mut::map_unchanged`].
317    pub fn map<U: ?Sized>(self, f: impl FnOnce(&T) -> &U) -> Ref<'w, U> {
318        Ref {
319            value: f(self.value),
320            ticks: self.ticks,
321        }
322    }
323
324    /// Create a new `Ref` using provided values.
325    ///
326    /// This is an advanced feature, `Ref`s are designed to be _created_ by
327    /// engine-internal code and _consumed_ by end-user code.
328    ///
329    /// - `value` - The value wrapped by `Ref`.
330    /// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.
331    /// - `changed` - A [`Tick`] that stores the last time the wrapped value was changed.
332    /// - `last_run` - A [`Tick`], occurring before `this_run`, which is used
333    ///   as a reference to determine whether the wrapped value is newly added or changed.
334    /// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".
335    pub fn new(
336        value: &'w T,
337        added: &'w Tick,
338        changed: &'w Tick,
339        last_run: Tick,
340        this_run: Tick,
341        caller: MaybeLocation<&'w &'static Location<'static>>,
342    ) -> Ref<'w, T> {
343        Ref {
344            value,
345            ticks: ComponentTicksRef {
346                added,
347                changed,
348                changed_by: caller,
349                last_run,
350                this_run,
351            },
352        }
353    }
354
355    /// Overwrite the `last_run` and `this_run` tick that are used for change detection.
356    ///
357    /// This is an advanced feature. `Ref`s are usually _created_ by engine-internal code and
358    /// _consumed_ by end-user code.
359    pub fn set_ticks(&mut self, last_run: Tick, this_run: Tick) {
360        self.ticks.last_run = last_run;
361        self.ticks.this_run = this_run;
362    }
363}
364
365impl<'w, 'a, T> IntoIterator for &'a Ref<'w, T>
366where
367    &'a T: IntoIterator,
368{
369    type Item = <&'a T as IntoIterator>::Item;
370    type IntoIter = <&'a T as IntoIterator>::IntoIter;
371
372    fn into_iter(self) -> Self::IntoIter {
373        self.value.into_iter()
374    }
375}
376change_detection_impl!(Ref<'w, T>, T,);
377impl_debug!(Ref<'w, T>,);
378
379/// Unique mutable borrow of an entity's component or of a resource.
380///
381/// This can be used in queries to access change detection from immutable query methods, as opposed
382/// to `&mut T` which only provides access to change detection from mutable query methods.
383///
384/// ```rust
385/// # use bevy_ecs::prelude::*;
386/// # use bevy_ecs::query::QueryData;
387/// #
388/// #[derive(Component, Clone, Debug)]
389/// struct Name(String);
390///
391/// #[derive(Component, Clone, Copy, Debug)]
392/// struct Health(f32);
393///
394/// fn my_system(mut query: Query<(Mut<Name>, &mut Health)>) {
395///     // Mutable access provides change detection information for both parameters:
396///     // - `name` has type `Mut<Name>`
397///     // - `health` has type `Mut<Health>`
398///     for (name, health) in query.iter_mut() {
399///         println!("Name: {:?} (last changed {:?})", name, name.last_changed());
400///         println!("Health: {:?} (last changed: {:?})", health, health.last_changed());
401/// #        println!("{}{}", name.0, health.0); // Silence dead_code warning
402///     }
403///
404///     // Immutable access only provides change detection for `Name`:
405///     // - `name` has type `Ref<Name>`
406///     // - `health` has type `&Health`
407///     for (name, health) in query.iter() {
408///         println!("Name: {:?} (last changed {:?})", name, name.last_changed());
409///         println!("Health: {:?}", health);
410///     }
411/// }
412///
413/// # bevy_ecs::system::assert_is_system(my_system);
414/// ```
415pub struct Mut<'w, T: ?Sized> {
416    pub(crate) value: &'w mut T,
417    pub(crate) ticks: ComponentTicksMut<'w>,
418}
419
420impl<'w, T: ?Sized> Mut<'w, T> {
421    /// Creates a new change-detection enabled smart pointer.
422    /// In almost all cases you do not need to call this method manually,
423    /// as instances of `Mut` will be created by engine-internal code.
424    ///
425    /// Many use-cases of this method would be better served by [`Mut::map_unchanged`]
426    /// or [`Mut::reborrow`].
427    ///
428    /// - `value` - The value wrapped by this smart pointer.
429    /// - `added` - A [`Tick`] that stores the tick when the wrapped value was created.
430    /// - `last_changed` - A [`Tick`] that stores the last time the wrapped value was changed.
431    ///   This will be updated to the value of `change_tick` if the returned smart pointer
432    ///   is modified.
433    /// - `last_run` - A [`Tick`], occurring before `this_run`, which is used
434    ///   as a reference to determine whether the wrapped value is newly added or changed.
435    /// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".
436    pub fn new(
437        value: &'w mut T,
438        added: &'w mut Tick,
439        last_changed: &'w mut Tick,
440        last_run: Tick,
441        this_run: Tick,
442        caller: MaybeLocation<&'w mut &'static Location<'static>>,
443    ) -> Self {
444        Self {
445            value,
446            ticks: ComponentTicksMut {
447                added,
448                changed: last_changed,
449                changed_by: caller,
450                last_run,
451                this_run,
452            },
453        }
454    }
455
456    /// Overwrite the `last_run` and `this_run` tick that are used for change detection.
457    ///
458    /// This is an advanced feature. `Mut`s are usually _created_ by engine-internal code and
459    /// _consumed_ by end-user code.
460    pub fn set_ticks(&mut self, last_run: Tick, this_run: Tick) {
461        self.ticks.last_run = last_run;
462        self.ticks.this_run = this_run;
463    }
464}
465
466impl<'w, T: ?Sized> From<Mut<'w, T>> for Ref<'w, T> {
467    fn from(mut_ref: Mut<'w, T>) -> Self {
468        Self {
469            value: mut_ref.value,
470            ticks: mut_ref.ticks.into(),
471        }
472    }
473}
474
475impl<'w, 'a, T> IntoIterator for &'a Mut<'w, T>
476where
477    &'a T: IntoIterator,
478{
479    type Item = <&'a T as IntoIterator>::Item;
480    type IntoIter = <&'a T as IntoIterator>::IntoIter;
481
482    fn into_iter(self) -> Self::IntoIter {
483        self.value.into_iter()
484    }
485}
486
487impl<'w, 'a, T> IntoIterator for &'a mut Mut<'w, T>
488where
489    &'a mut T: IntoIterator,
490{
491    type Item = <&'a mut T as IntoIterator>::Item;
492    type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
493
494    fn into_iter(self) -> Self::IntoIter {
495        self.set_changed();
496        self.value.into_iter()
497    }
498}
499
500change_detection_impl!(Mut<'w, T>, T,);
501change_detection_mut_impl!(Mut<'w, T>, T,);
502impl_methods!(Mut<'w, T>, T,);
503impl_debug!(Mut<'w, T>,);
504
505/// Unique mutable borrow of resources or an entity's component.
506///
507/// Similar to [`Mut`], but not generic over the component type, instead
508/// exposing the raw pointer as a `*mut ()`.
509///
510/// Usually you don't need to use this and can instead use the APIs returning a
511/// [`Mut`], but in situations where the types are not known at compile time
512/// or are defined outside of rust this can be used.
513pub struct MutUntyped<'w> {
514    pub(crate) value: PtrMut<'w>,
515    pub(crate) ticks: ComponentTicksMut<'w>,
516}
517
518impl<'w> MutUntyped<'w> {
519    /// Returns the pointer to the value, marking it as changed.
520    ///
521    /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).
522    #[inline]
523    pub fn into_inner(mut self) -> PtrMut<'w> {
524        self.set_changed();
525        self.value
526    }
527
528    /// Returns a [`MutUntyped`] with a smaller lifetime.
529    /// This is useful if you have `&mut MutUntyped`, but you need a `MutUntyped`.
530    #[inline]
531    pub fn reborrow(&mut self) -> MutUntyped<'_> {
532        MutUntyped {
533            value: self.value.reborrow(),
534            ticks: ComponentTicksMut {
535                added: self.ticks.added,
536                changed: self.ticks.changed,
537                changed_by: self.ticks.changed_by.as_deref_mut(),
538                last_run: self.ticks.last_run,
539                this_run: self.ticks.this_run,
540            },
541        }
542    }
543
544    /// Returns `true` if this value was changed or mutably dereferenced
545    /// either since a specific change tick.
546    pub fn has_changed_since(&self, tick: Tick) -> bool {
547        self.ticks.changed.is_newer_than(tick, self.ticks.this_run)
548    }
549
550    /// Returns a pointer to the value without taking ownership of this smart pointer, marking it as changed.
551    ///
552    /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChangesMut::bypass_change_detection).
553    #[inline]
554    pub fn as_mut(&mut self) -> PtrMut<'_> {
555        self.set_changed();
556        self.value.reborrow()
557    }
558
559    /// Returns an immutable pointer to the value without taking ownership.
560    #[inline]
561    pub fn as_ref(&self) -> Ptr<'_> {
562        self.value.as_ref()
563    }
564
565    /// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value,
566    /// without flagging a change.
567    /// This function is the untyped equivalent of [`Mut::map_unchanged`].
568    ///
569    /// 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.
570    ///
571    /// If you know the type of the value you can do
572    /// ```no_run
573    /// # use bevy_ecs::change_detection::{Mut, MutUntyped};
574    /// # let mut_untyped: MutUntyped = unimplemented!();
575    /// // SAFETY: ptr is of type `u8`
576    /// mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::<u8>() });
577    /// ```
578    /// If you have a [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) that you know belongs to this [`MutUntyped`],
579    /// you can do
580    /// ```no_run
581    /// # use bevy_ecs::change_detection::{Mut, MutUntyped};
582    /// # let mut_untyped: MutUntyped = unimplemented!();
583    /// # let reflect_from_ptr: bevy_reflect::ReflectFromPtr = unimplemented!();
584    /// // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped`
585    /// mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_mut(ptr) });
586    /// ```
587    pub fn map_unchanged<T: ?Sized>(self, f: impl FnOnce(PtrMut<'w>) -> &'w mut T) -> Mut<'w, T> {
588        Mut {
589            value: f(self.value),
590            ticks: self.ticks,
591        }
592    }
593
594    /// Transforms this [`MutUntyped`] into a [`Mut<T>`] with the same lifetime.
595    ///
596    /// # Safety
597    /// - `T` must be the erased pointee type for this [`MutUntyped`].
598    pub unsafe fn with_type<T>(self) -> Mut<'w, T> {
599        Mut {
600            // SAFETY: `value` is `Aligned` and caller ensures the pointee type is `T`.
601            value: unsafe { self.value.deref_mut() },
602            ticks: self.ticks,
603        }
604    }
605}
606
607impl<'w> DetectChanges for MutUntyped<'w> {
608    #[inline]
609    fn is_added(&self) -> bool {
610        self.ticks
611            .added
612            .is_newer_than(self.ticks.last_run, self.ticks.this_run)
613    }
614
615    #[inline]
616    fn is_changed(&self) -> bool {
617        self.ticks
618            .changed
619            .is_newer_than(self.ticks.last_run, self.ticks.this_run)
620    }
621
622    #[inline]
623    fn last_changed(&self) -> Tick {
624        *self.ticks.changed
625    }
626
627    #[inline]
628    fn changed_by(&self) -> MaybeLocation {
629        self.ticks.changed_by.copied()
630    }
631
632    #[inline]
633    fn added(&self) -> Tick {
634        *self.ticks.added
635    }
636}
637
638impl<'w> DetectChangesMut for MutUntyped<'w> {
639    type Inner = PtrMut<'w>;
640
641    #[inline]
642    #[track_caller]
643    fn set_changed(&mut self) {
644        *self.ticks.changed = self.ticks.this_run;
645        self.ticks.changed_by.assign(MaybeLocation::caller());
646    }
647
648    #[inline]
649    #[track_caller]
650    fn set_added(&mut self) {
651        *self.ticks.changed = self.ticks.this_run;
652        *self.ticks.added = self.ticks.this_run;
653        self.ticks.changed_by.assign(MaybeLocation::caller());
654    }
655
656    #[inline]
657    #[track_caller]
658    fn set_last_changed(&mut self, last_changed: Tick) {
659        *self.ticks.changed = last_changed;
660        self.ticks.changed_by.assign(MaybeLocation::caller());
661    }
662
663    #[inline]
664    #[track_caller]
665    fn set_last_added(&mut self, last_added: Tick) {
666        *self.ticks.added = last_added;
667        *self.ticks.changed = last_added;
668        self.ticks.changed_by.assign(MaybeLocation::caller());
669    }
670
671    #[inline]
672    #[track_caller]
673    fn bypass_change_detection(&mut self) -> &mut Self::Inner {
674        &mut self.value
675    }
676}
677
678impl core::fmt::Debug for MutUntyped<'_> {
679    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
680        f.debug_tuple("MutUntyped")
681            .field(&self.value.as_ptr())
682            .finish()
683    }
684}
685
686impl<'w, T> From<Mut<'w, T>> for MutUntyped<'w> {
687    fn from(value: Mut<'w, T>) -> Self {
688        MutUntyped {
689            value: value.value.into(),
690            ticks: value.ticks,
691        }
692    }
693}