Skip to main content

goud_engine/ecs/schedule/
core_system_label.rs

1//! Built-in system labels for common system phases.
2
3use std::any::TypeId;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6
7use super::stage_label::DynHasherWrapper;
8use super::system_label::SystemLabel;
9
10/// Built-in system labels for common system phases.
11///
12/// These labels represent standard system phases that many games use.
13/// They can be used to order custom systems relative to engine systems.
14///
15/// # Example
16///
17/// ```
18/// use goud_engine::ecs::schedule::{CoreSystemLabel, SystemLabel};
19///
20/// let input = CoreSystemLabel::Input;
21/// let physics = CoreSystemLabel::Physics;
22///
23/// assert_eq!(input.label_name(), "Input");
24/// assert_eq!(physics.label_name(), "Physics");
25/// ```
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
27pub enum CoreSystemLabel {
28    /// Input processing systems (keyboard, mouse, gamepad).
29    #[default]
30    Input,
31    /// Physics simulation systems.
32    Physics,
33    /// Animation update systems.
34    Animation,
35    /// AI/behavior systems.
36    AI,
37    /// Audio playback systems.
38    Audio,
39    /// Transform propagation systems.
40    TransformPropagate,
41    /// Collision detection systems.
42    Collision,
43    /// Event processing systems.
44    Events,
45    /// UI layout systems.
46    UILayout,
47    /// UI rendering systems.
48    UIRender,
49}
50
51impl CoreSystemLabel {
52    /// Returns all core system labels in recommended execution order.
53    pub fn all() -> &'static [CoreSystemLabel] {
54        &[
55            CoreSystemLabel::Input,
56            CoreSystemLabel::Events,
57            CoreSystemLabel::AI,
58            CoreSystemLabel::Physics,
59            CoreSystemLabel::Collision,
60            CoreSystemLabel::Animation,
61            CoreSystemLabel::TransformPropagate,
62            CoreSystemLabel::Audio,
63            CoreSystemLabel::UILayout,
64            CoreSystemLabel::UIRender,
65        ]
66    }
67
68    /// Returns the count of core system labels.
69    #[inline]
70    pub const fn count() -> usize {
71        10
72    }
73}
74
75impl SystemLabel for CoreSystemLabel {
76    fn label_id(&self) -> TypeId {
77        TypeId::of::<(CoreSystemLabel, u8)>()
78    }
79
80    fn label_name(&self) -> &'static str {
81        match self {
82            CoreSystemLabel::Input => "Input",
83            CoreSystemLabel::Physics => "Physics",
84            CoreSystemLabel::Animation => "Animation",
85            CoreSystemLabel::AI => "AI",
86            CoreSystemLabel::Audio => "Audio",
87            CoreSystemLabel::TransformPropagate => "TransformPropagate",
88            CoreSystemLabel::Collision => "Collision",
89            CoreSystemLabel::Events => "Events",
90            CoreSystemLabel::UILayout => "UILayout",
91            CoreSystemLabel::UIRender => "UIRender",
92        }
93    }
94
95    fn dyn_clone(&self) -> Box<dyn SystemLabel> {
96        Box::new(*self)
97    }
98
99    fn dyn_eq(&self, other: &dyn SystemLabel) -> bool {
100        if other.label_id() == TypeId::of::<(CoreSystemLabel, u8)>() {
101            self.label_name() == other.label_name()
102        } else {
103            false
104        }
105    }
106
107    fn dyn_hash(&self, state: &mut dyn Hasher) {
108        TypeId::of::<CoreSystemLabel>().hash(&mut DynHasherWrapper(state));
109        (*self as u8).hash(&mut DynHasherWrapper(state));
110    }
111}
112
113impl fmt::Display for CoreSystemLabel {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        write!(f, "{}", self.label_name())
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_all_labels() {
125        let all = CoreSystemLabel::all();
126        assert_eq!(all.len(), 10);
127        assert_eq!(all[0], CoreSystemLabel::Input);
128        assert_eq!(all[1], CoreSystemLabel::Events);
129        assert_eq!(all[2], CoreSystemLabel::AI);
130        assert_eq!(all[3], CoreSystemLabel::Physics);
131    }
132
133    #[test]
134    fn test_count() {
135        assert_eq!(CoreSystemLabel::count(), 10);
136    }
137
138    #[test]
139    fn test_label_names() {
140        assert_eq!(CoreSystemLabel::Input.label_name(), "Input");
141        assert_eq!(CoreSystemLabel::Physics.label_name(), "Physics");
142        assert_eq!(CoreSystemLabel::Animation.label_name(), "Animation");
143        assert_eq!(CoreSystemLabel::AI.label_name(), "AI");
144        assert_eq!(CoreSystemLabel::Audio.label_name(), "Audio");
145        assert_eq!(
146            CoreSystemLabel::TransformPropagate.label_name(),
147            "TransformPropagate"
148        );
149        assert_eq!(CoreSystemLabel::Collision.label_name(), "Collision");
150        assert_eq!(CoreSystemLabel::Events.label_name(), "Events");
151        assert_eq!(CoreSystemLabel::UILayout.label_name(), "UILayout");
152        assert_eq!(CoreSystemLabel::UIRender.label_name(), "UIRender");
153    }
154
155    #[test]
156    fn test_default() {
157        assert_eq!(CoreSystemLabel::default(), CoreSystemLabel::Input);
158    }
159
160    #[test]
161    fn test_display() {
162        assert_eq!(format!("{}", CoreSystemLabel::Physics), "Physics");
163    }
164
165    #[test]
166    fn test_debug() {
167        assert_eq!(format!("{:?}", CoreSystemLabel::Physics), "Physics");
168    }
169
170    #[test]
171    fn test_clone() {
172        let label = CoreSystemLabel::Physics;
173        let cloned = label.clone();
174        assert_eq!(label, cloned);
175    }
176
177    #[test]
178    fn test_dyn_clone() {
179        let label = CoreSystemLabel::Physics;
180        let boxed = label.dyn_clone();
181        assert_eq!(boxed.label_name(), "Physics");
182    }
183
184    #[test]
185    fn test_dyn_eq_same_variant() {
186        let a = CoreSystemLabel::Physics;
187        let b = CoreSystemLabel::Physics;
188        assert!(a.dyn_eq(&b));
189    }
190
191    #[test]
192    fn test_dyn_eq_different_variant() {
193        let a = CoreSystemLabel::Physics;
194        let b = CoreSystemLabel::Audio;
195        assert!(!a.dyn_eq(&b));
196    }
197
198    #[test]
199    fn test_send_sync() {
200        fn assert_send<T: Send>() {}
201        fn assert_sync<T: Sync>() {}
202        assert_send::<CoreSystemLabel>();
203        assert_sync::<CoreSystemLabel>();
204    }
205}