Skip to main content

bevy_diagnostic/
frame_count.rs

1use bevy_app::prelude::*;
2use bevy_ecs::prelude::*;
3
4#[cfg(feature = "serialize")]
5use serde::{
6    de::{Error, Visitor},
7    Deserialize, Deserializer, Serialize, Serializer,
8};
9
10/// Maintains a count of frames rendered since the start of the application.
11///
12/// [`FrameCount`] is incremented during [`Last`], providing predictable
13/// behavior: it will be 0 during the first update, 1 during the next, and so forth.
14///
15/// # Overflows
16///
17/// [`FrameCount`] will wrap to 0 after exceeding [`u32::MAX`]. Within reasonable
18/// assumptions, one may exploit wrapping arithmetic to determine the number of frames
19/// that have elapsed between two observations – see [`u32::wrapping_sub()`].
20#[derive(#[automatically_derived]impl ::core::fmt::Debug for FrameCount {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "FrameCount",
            &&self.0)
    }
}Debug, #[automatically_derived]impl ::core::default::Default for FrameCount {
    #[inline]
    fn default() -> Self { FrameCount(::core::default::Default::default()) }
}Default, impl bevy_ecs::component::Component for FrameCount where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::SparseSet;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {
        let resource_component_id =
            if let ::core::option::Option::Some(id) =
                    required_components.components_registrator().component_id::<FrameCount>()
                {
                id
            } else {
                required_components.components_registrator().register_component::<FrameCount>()
            };
        required_components.register_required::<bevy_ecs::resource::IsResource>(move
                ||
                bevy_ecs::resource::IsResource::new(resource_component_id));
    }
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}
impl bevy_ecs::resource::Resource for FrameCount where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for FrameCount {
}
#[automatically_derived]impl ::core::clone::Clone for FrameCount {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]impl ::core::marker::Copy for FrameCount { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    FrameCount {
}
#[automatically_derived]impl ::core::cmp::PartialEq for FrameCount {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for FrameCount {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u32>;
    }
}Eq, #[automatically_derived]impl ::core::cmp::PartialOrd for FrameCount {
    #[inline]
    fn partial_cmp(&self, other: &Self)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
    }
}PartialOrd, #[automatically_derived]impl ::core::cmp::Ord for FrameCount {
    #[inline]
    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord)]
21pub struct FrameCount(pub u32);
22
23/// Adds frame counting functionality to Apps.
24#[derive(#[automatically_derived]impl ::core::default::Default for FrameCountPlugin {
    #[inline]
    fn default() -> Self { FrameCountPlugin {} }
}Default)]
25pub struct FrameCountPlugin;
26
27impl Plugin for FrameCountPlugin {
28    fn build(&self, app: &mut App) {
29        app.init_resource::<FrameCount>();
30        app.add_systems(Last, update_frame_count);
31    }
32}
33
34/// A system used to increment [`FrameCount`] with wrapping addition.
35///
36/// See [`FrameCount`] for more details.
37pub fn update_frame_count(mut frame_count: ResMut<FrameCount>) {
38    frame_count.0 = frame_count.0.wrapping_add(1);
39}
40
41#[cfg(feature = "serialize")]
42// Manually implementing serialize/deserialize allows us to use a more compact representation as simple integers
43impl Serialize for FrameCount {
44    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
45        serializer.serialize_u32(self.0)
46    }
47}
48
49#[cfg(feature = "serialize")]
50impl<'de> Deserialize<'de> for FrameCount {
51    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
52        deserializer.deserialize_u32(FrameVisitor)
53    }
54}
55
56#[cfg(feature = "serialize")]
57struct FrameVisitor;
58
59#[cfg(feature = "serialize")]
60impl<'de> Visitor<'de> for FrameVisitor {
61    type Value = FrameCount;
62
63    fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
64        formatter.write_str(core::any::type_name::<FrameCount>())
65    }
66
67    fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
68    where
69        E: Error,
70    {
71        Ok(FrameCount(v))
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn frame_counter_update() {
81        let mut app = App::new();
82        app.add_plugins(FrameCountPlugin);
83        app.update();
84
85        let frame_count = app.world().resource::<FrameCount>();
86        assert_eq!(1, frame_count.0);
87    }
88}
89
90#[cfg(all(test, feature = "serialize"))]
91mod serde_tests {
92    use super::*;
93
94    use serde_test::{assert_tokens, Token};
95
96    #[test]
97    fn test_serde_frame_count() {
98        let frame_count = FrameCount(100);
99        assert_tokens(&frame_count, &[Token::U32(100)]);
100    }
101}