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}