Skip to main content

bevy_ecs/change_detection/
tick.rs

1use bevy_ecs_macros::Event;
2#[cfg(feature = "bevy_reflect")]
3use bevy_reflect::Reflect;
4use core::{
5    cell::UnsafeCell,
6    fmt::{self, Debug, Formatter},
7    panic::Location,
8    sync::atomic::{AtomicU32, Ordering},
9};
10
11use crate::change_detection::{MaybeLocation, MAX_CHANGE_AGE};
12
13/// A value that tracks when a system ran relative to other systems.
14/// This is used to power change detection.
15///
16/// *Note* that a system that hasn't been run yet has a `Tick` of 0.
17#[derive(#[automatically_derived]impl ::core::marker::Copy for Tick { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for Tick {
}
#[automatically_derived]impl ::core::clone::Clone for Tick {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]impl ::core::default::Default for Tick {
    #[inline]
    fn default() -> Self {
        Tick { tick: ::core::default::Default::default() }
    }
}Default, #[automatically_derived]impl ::core::fmt::Debug for Tick {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "Tick", "tick",
            &&self.tick)
    }
}Debug, #[automatically_derived]impl ::core::cmp::Eq for Tick {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u32>;
    }
}Eq, #[automatically_derived]impl ::core::hash::Hash for Tick {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.tick, state)
    }
}Hash, #[automatically_derived]impl ::core::marker::StructuralPartialEq for Tick { }
#[automatically_derived]impl ::core::cmp::PartialEq for Tick {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.tick == other.tick }
}PartialEq)]
18#[cfg_attr(
19    feature = "bevy_reflect",
20    derive(const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for Tick where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert(<bevy_reflect::ReflectFromPtr as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration.insert(<bevy_reflect::ReflectFromReflect as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <u32 as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for Tick where  {
            #[inline(never)]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(#[inline(never)] ||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<u32>("tick")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for Tick where  {
            fn type_path() -> &'static str {
                "bevy_ecs::change_detection::tick::Tick"
            }
            fn short_type_path() -> &'static str { "Tick" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("Tick")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_ecs::change_detection::tick".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_ecs::change_detection::tick")
            }
        }
        impl bevy_reflect::Reflect for Tick where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        impl bevy_reflect::func::args::GetOwnership for Tick where  {
            fn ownership() -> bevy_reflect::func::args::Ownership {
                bevy_reflect::func::args::Ownership::Owned
            }
        }
        impl bevy_reflect::func::args::FromArg for Tick where  {
            type This<'from_arg> = Tick;
            fn from_arg(arg: bevy_reflect::func::args::Arg)
                ->
                    ::core::result::Result<Self::This<'_>,
                    bevy_reflect::func::args::ArgError> {
                arg.take_owned()
            }
        }
        impl bevy_reflect::func::IntoReturn for Tick where  {
            fn into_return<'into_return>(self)
                -> bevy_reflect::func::Return<'into_return> where
                Self: 'into_return {
                bevy_reflect::func::Return::Owned(bevy_reflect::__macro_exports::alloc_utils::Box::new(self))
            }
        }
        impl bevy_reflect::structs::Struct for Tick where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "tick" => ::core::option::Option::Some(&self.tick),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "tick" => ::core::option::Option::Some(&mut self.tick),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.tick),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.tick),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("tick"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "tick" => ::core::option::Option::Some(0usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 1usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                ->
                    ::core::result::Result<bevy_reflect::structs::DynamicStruct,
                    bevy_reflect::ReflectCloneError> {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed("tick",
                    bevy_reflect::PartialReflect::to_dynamic(&self.tick)?);
                ::core::result::Result::Ok(dynamic)
            }
        }
        impl bevy_reflect::PartialReflect for Tick where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_hash(&self) -> ::core::option::Option<u64> {
                use ::core::hash::{Hash, Hasher};
                let mut hasher = bevy_reflect::utility::reflect_hasher();
                Hash::hash(&::core::any::Any::type_id(self), &mut hasher);
                Hash::hash(self, &mut hasher);
                ::core::option::Option::Some(Hasher::finish(&hasher))
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                let value =
                    <dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
                if let ::core::option::Option::Some(value) = value {
                    ::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
                            value))
                } else { ::core::option::Option::Some(false) }
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
                -> ::core::fmt::Result {
                ::core::fmt::Debug::fmt(self, f)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for Tick where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let __this =
                        Self {
                            tick: <u32 as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "tick")?)?,
                        };
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect),
21    reflect(Debug, Hash, PartialEq, Clone)
22)]
23pub struct Tick {
24    tick: u32,
25}
26
27impl Tick {
28    /// The maximum relative age for a change tick.
29    /// The value of this is equal to [`MAX_CHANGE_AGE`].
30    ///
31    /// Since change detection will not work for any ticks older than this,
32    /// ticks are periodically scanned to ensure their relative values are below this.
33    pub const MAX: Self = Self::new(MAX_CHANGE_AGE);
34
35    /// Creates a new [`Tick`] wrapping the given value.
36    #[inline]
37    pub const fn new(tick: u32) -> Self {
38        Self { tick }
39    }
40
41    /// Gets the value of this change tick.
42    #[inline]
43    pub const fn get(self) -> u32 {
44        self.tick
45    }
46
47    /// Sets the value of this change tick.
48    #[inline]
49    pub fn set(&mut self, tick: u32) {
50        self.tick = tick;
51    }
52
53    /// Returns `true` if this `Tick` occurred since the system's `last_run`.
54    ///
55    /// `this_run` is the current tick of the system, used as a reference to help deal with wraparound.
56    #[inline]
57    pub fn is_newer_than(self, last_run: Tick, this_run: Tick) -> bool {
58        // This works even with wraparound because the world tick (`this_run`) is always "newer" than
59        // `last_run` and `self.tick`, and we scan periodically to clamp `ComponentTicks` values
60        // so they never get older than `u32::MAX` (the difference would overflow).
61        //
62        // The clamp here ensures determinism (since scans could differ between app runs).
63        let ticks_since_insert = this_run.relative_to(self).tick.min(MAX_CHANGE_AGE);
64        let ticks_since_system = this_run.relative_to(last_run).tick.min(MAX_CHANGE_AGE);
65
66        ticks_since_system > ticks_since_insert
67    }
68
69    /// Returns a change tick representing the relationship between `self` and `other`.
70    #[inline]
71    pub(crate) fn relative_to(self, other: Self) -> Self {
72        let tick = self.tick.wrapping_sub(other.tick);
73        Self { tick }
74    }
75
76    /// Wraps this change tick's value if it exceeds [`Tick::MAX`].
77    ///
78    /// Returns `true` if wrapping was performed. Otherwise, returns `false`.
79    #[inline]
80    pub fn check_tick(&mut self, check: CheckChangeTicks) -> bool {
81        let age = check.present_tick().relative_to(*self);
82        // This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true
83        // so long as this check always runs before that can happen.
84        if age.get() > Self::MAX.get() {
85            *self = check.present_tick().relative_to(Self::MAX);
86            true
87        } else {
88            false
89        }
90    }
91}
92
93/// A tick that can be updated from multiple threads.
94///
95/// This has exactly the same semantics as [`Tick`] but can be updated
96/// atomically. It's used for summary ticks.
97#[derive(#[automatically_derived]impl ::core::default::Default for AtomicTick {
    #[inline]
    fn default() -> Self {
        AtomicTick { tick: ::core::default::Default::default() }
    }
}Default)]
98pub struct AtomicTick {
99    /// The atomic tick value.
100    tick: AtomicU32,
101}
102
103impl AtomicTick {
104    /// Returns the current value of the tick.
105    pub fn get(&self) -> Tick {
106        Tick {
107            tick: self.tick.load(Ordering::Relaxed),
108        }
109    }
110
111    #[expect(
112        clippy::doc_markdown,
113        reason = "The word 'ARMv6' does not require backticks"
114    )]
115    /// Sets a new value for the tick.
116    ///
117    /// Note that this method takes `&self` and can therefore be called from
118    /// multiple threads. The tick is updated using relaxed ordering and is
119    /// therefore cheap to update on common architectures (x86-64, ARMv6 and
120    /// newer). However, be warned that, because it uses relaxed ordering, a
121    /// full mutex lock or similar barrier is required if you need to coordinate
122    /// the synchronization of this value with other memory locations.
123    pub fn set(&self, new_tick: Tick) {
124        // Do an unsynchronized read first.
125        //
126        // This is important on x86-64 (both Intel and AMD) to avoid a
127        // performance cliff. It has much smaller effects on AArch64, but it's
128        // still worth doing on e.g. Apple M2 in parallel mode, so I'm leaving
129        // it in.
130        //
131        // See benchmarks:
132        // https://github.com/bevyengine/bevy/pull/25157#issuecomment-5242287382
133        if self.tick.load(Ordering::Relaxed) != new_tick.get() {
134            self.tick.store(new_tick.get(), Ordering::Relaxed);
135        }
136    }
137}
138
139impl Debug for AtomicTick {
140    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
141        f.debug_struct("AtomicTick")
142            .field("tick", &self.get().get())
143            .finish()
144    }
145}
146
147/// An [`Event`] that can be used to maintain [`Tick`]s in custom data structures, enabling to make
148/// use of bevy's periodic checks that clamps ticks to a certain range, preventing overflows and thus
149/// keeping methods like [`Tick::is_newer_than`] reliably return `false` for ticks that got too old.
150///
151/// # Example
152///
153/// Here a schedule is stored in a custom resource. This way the systems in it would not have their change
154/// ticks automatically updated via [`World::check_change_ticks`](crate::world::World::check_change_ticks),
155/// possibly causing `Tick`-related bugs on long-running apps.
156///
157/// To fix that, add an observer for this event that calls the schedule's
158/// [`Schedule::check_change_ticks`](bevy_ecs::schedule::Schedule::check_change_ticks).
159///
160/// ```
161/// use bevy_ecs::prelude::*;
162/// use bevy_ecs::change_detection::CheckChangeTicks;
163///
164/// #[derive(Resource)]
165/// struct CustomSchedule(Schedule);
166///
167/// # let mut world = World::new();
168/// world.add_observer(|check: On<CheckChangeTicks>, mut schedule: ResMut<CustomSchedule>| {
169///     schedule.0.check_change_ticks(*check);
170/// });
171/// ```
172#[derive(#[automatically_derived]impl ::core::fmt::Debug for CheckChangeTicks {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "CheckChangeTicks", &&self.0)
    }
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for CheckChangeTicks {
}
#[automatically_derived]impl ::core::clone::Clone for CheckChangeTicks {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<Tick>;
        *self
    }
}Clone, #[automatically_derived]impl ::core::marker::Copy for CheckChangeTicks { }Copy, impl bevy_ecs::event::Event for CheckChangeTicks where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    type Trigger<'a> = bevy_ecs::event::GlobalTrigger;
}Event)]
173pub struct CheckChangeTicks(pub(crate) Tick);
174
175impl CheckChangeTicks {
176    /// Get the present `Tick` that other ticks get compared to.
177    pub fn present_tick(self) -> Tick {
178        self.0
179    }
180}
181
182/// Interior-mutable access to the [`Tick`]s of a single component or resource.
183#[derive(#[automatically_derived]impl<'a> ::core::marker::Copy for
    ComponentTickCells<'a> {
}Copy, #[automatically_derived]#[doc(hidden)]unsafe impl<'a>
    ::core::clone::TrivialClone for ComponentTickCells<'a> {
}
#[automatically_derived]impl<'a> ::core::clone::Clone for
    ComponentTickCells<'a> {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<&'a UnsafeCell<Tick>>;
        let _: ::core::clone::AssertParamIsClone<&'a UnsafeCell<Tick>>;
        let _:
                ::core::clone::AssertParamIsClone<MaybeLocation<&'a UnsafeCell<&'static Location<'static>>>>;
        let _: ::core::clone::AssertParamIsClone<Option<&'a AtomicTick>>;
        *self
    }
}Clone, #[automatically_derived]impl<'a> ::core::fmt::Debug for ComponentTickCells<'a>
    {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "ComponentTickCells", "added", &self.added, "changed",
            &self.changed, "changed_by", &self.changed_by, "summary_tick",
            &&self.summary_tick)
    }
}Debug)]
184pub struct ComponentTickCells<'a> {
185    /// The tick indicating when the value was added to the world.
186    pub added: &'a UnsafeCell<Tick>,
187    /// The tick indicating the last time the value was modified.
188    pub changed: &'a UnsafeCell<Tick>,
189    /// The calling location that last modified the value.
190    pub changed_by: MaybeLocation<&'a UnsafeCell<&'static Location<'static>>>,
191    /// The summary tick for the column, if the component is dense and has a
192    /// summary tick.
193    pub summary_tick: Option<&'a AtomicTick>,
194}
195
196/// Records when a component or resource was added and when it was last mutably dereferenced (or added).
197#[derive(#[automatically_derived]impl ::core::marker::Copy for ComponentTicks { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for ComponentTicks {
}
#[automatically_derived]impl ::core::clone::Clone for ComponentTicks {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<Tick>;
        *self
    }
}Clone, #[automatically_derived]impl ::core::fmt::Debug for ComponentTicks {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "ComponentTicks", "added", &self.added, "changed", &&self.changed)
    }
}Debug)]
198#[cfg_attr(feature = "bevy_reflect", derive(const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for ComponentTicks where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert(<bevy_reflect::ReflectFromPtr as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration.insert(<bevy_reflect::ReflectFromReflect as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <Tick as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for ComponentTicks where  {
            #[inline(never)]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(#[inline(never)] ||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<Tick>("added"),
                                                bevy_reflect::NamedField::new::<Tick>("changed")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for ComponentTicks where  {
            fn type_path() -> &'static str {
                "bevy_ecs::change_detection::tick::ComponentTicks"
            }
            fn short_type_path() -> &'static str { "ComponentTicks" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("ComponentTicks")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_ecs::change_detection::tick".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_ecs::change_detection::tick")
            }
        }
        impl bevy_reflect::Reflect for ComponentTicks where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        impl bevy_reflect::func::args::GetOwnership for ComponentTicks where
            {
            fn ownership() -> bevy_reflect::func::args::Ownership {
                bevy_reflect::func::args::Ownership::Owned
            }
        }
        impl bevy_reflect::func::args::FromArg for ComponentTicks where  {
            type This<'from_arg> = ComponentTicks;
            fn from_arg(arg: bevy_reflect::func::args::Arg)
                ->
                    ::core::result::Result<Self::This<'_>,
                    bevy_reflect::func::args::ArgError> {
                arg.take_owned()
            }
        }
        impl bevy_reflect::func::IntoReturn for ComponentTicks where  {
            fn into_return<'into_return>(self)
                -> bevy_reflect::func::Return<'into_return> where
                Self: 'into_return {
                bevy_reflect::func::Return::Owned(bevy_reflect::__macro_exports::alloc_utils::Box::new(self))
            }
        }
        impl bevy_reflect::structs::Struct for ComponentTicks where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "added" => ::core::option::Option::Some(&self.added),
                    "changed" => ::core::option::Option::Some(&self.changed),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "added" => ::core::option::Option::Some(&mut self.added),
                    "changed" =>
                        ::core::option::Option::Some(&mut self.changed),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.added),
                    1usize => ::core::option::Option::Some(&self.changed),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.added),
                    1usize => ::core::option::Option::Some(&mut self.changed),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("added"),
                    1usize => ::core::option::Option::Some("changed"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "added" => ::core::option::Option::Some(0usize),
                    "changed" => ::core::option::Option::Some(1usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 2usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                ->
                    ::core::result::Result<bevy_reflect::structs::DynamicStruct,
                    bevy_reflect::ReflectCloneError> {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed("added",
                    bevy_reflect::PartialReflect::to_dynamic(&self.added)?);
                dynamic.insert_boxed("changed",
                    bevy_reflect::PartialReflect::to_dynamic(&self.changed)?);
                ::core::result::Result::Ok(dynamic)
            }
        }
        impl bevy_reflect::PartialReflect for ComponentTicks where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
                -> ::core::fmt::Result {
                ::core::fmt::Debug::fmt(self, f)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for ComponentTicks where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let __this =
                        Self {
                            added: <Tick as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "added")?)?,
                            changed: <Tick as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "changed")?)?,
                        };
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect), reflect(Debug, Clone))]
199pub struct ComponentTicks {
200    /// Tick recording the time this component or resource was added.
201    pub added: Tick,
202
203    /// Tick recording the time this component or resource was most recently changed.
204    pub changed: Tick,
205}
206
207impl ComponentTicks {
208    /// Returns `true` if the component or resource was added after the system last ran
209    /// (or the system is running for the first time).
210    #[inline]
211    pub fn is_added(&self, last_run: Tick, this_run: Tick) -> bool {
212        self.added.is_newer_than(last_run, this_run)
213    }
214
215    /// Returns `true` if the component or resource was added or mutably dereferenced after the system last ran
216    /// (or the system is running for the first time).
217    #[inline]
218    pub fn is_changed(&self, last_run: Tick, this_run: Tick) -> bool {
219        self.changed.is_newer_than(last_run, this_run)
220    }
221
222    /// Creates a new instance with the same change tick for `added` and `changed`.
223    pub fn new(change_tick: Tick) -> Self {
224        Self {
225            added: change_tick,
226            changed: change_tick,
227        }
228    }
229
230    /// Manually sets the change tick.
231    ///
232    /// This is normally done automatically via the [`DerefMut`](core::ops::DerefMut) implementation
233    /// on [`Mut<T>`](crate::change_detection::Mut), [`ResMut<T>`](crate::change_detection::ResMut), etc.
234    /// However, components and resources that make use of interior mutability might require manual updates.
235    ///
236    /// # Example
237    /// ```no_run
238    /// # use bevy_ecs::{world::World, change_detection::ComponentTicks};
239    /// let world: World = unimplemented!();
240    /// let component_ticks: ComponentTicks = unimplemented!();
241    ///
242    /// component_ticks.set_changed(world.read_change_tick());
243    /// ```
244    #[inline]
245    pub fn set_changed(&mut self, change_tick: Tick) {
246        self.changed = change_tick;
247    }
248}