bevy_ecs/system/
system_name.rs

1use crate::component::Tick;
2use crate::prelude::World;
3use crate::system::{ExclusiveSystemParam, ReadOnlySystemParam, SystemMeta, SystemParam};
4use crate::world::unsafe_world_cell::UnsafeWorldCell;
5use std::borrow::Cow;
6use std::ops::Deref;
7
8/// [`SystemParam`] that returns the name of the system which it is used in.
9///
10/// This is not a reliable identifier, it is more so useful for debugging or logging.
11///
12/// # Examples
13///
14/// ```
15/// # use bevy_ecs::system::SystemName;
16/// # use bevy_ecs::system::SystemParam;
17///
18/// #[derive(SystemParam)]
19/// struct Logger<'s> {
20///     system_name: SystemName<'s>,
21/// }
22///
23/// impl<'s> Logger<'s> {
24///     fn log(&mut self, message: &str) {
25///         eprintln!("{}: {}", self.system_name, message);
26///     }
27/// }
28///
29/// fn system1(mut logger: Logger) {
30///     // Prints: "crate_name::mod_name::system1: Hello".
31///     logger.log("Hello");
32/// }
33/// ```
34#[derive(Debug)]
35pub struct SystemName<'s>(&'s str);
36
37impl<'s> SystemName<'s> {
38    /// Gets the name of the system.
39    pub fn name(&self) -> &str {
40        self.0
41    }
42}
43
44impl<'s> Deref for SystemName<'s> {
45    type Target = str;
46    fn deref(&self) -> &Self::Target {
47        self.name()
48    }
49}
50
51impl<'s> AsRef<str> for SystemName<'s> {
52    fn as_ref(&self) -> &str {
53        self.name()
54    }
55}
56
57impl<'s> From<SystemName<'s>> for &'s str {
58    fn from(name: SystemName<'s>) -> &'s str {
59        name.0
60    }
61}
62
63impl<'s> std::fmt::Display for SystemName<'s> {
64    #[inline(always)]
65    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
66        std::fmt::Display::fmt(&self.name(), f)
67    }
68}
69
70// SAFETY: no component value access
71unsafe impl SystemParam for SystemName<'_> {
72    type State = Cow<'static, str>;
73    type Item<'w, 's> = SystemName<'s>;
74
75    fn init_state(_world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
76        system_meta.name.clone()
77    }
78
79    #[inline]
80    unsafe fn get_param<'w, 's>(
81        name: &'s mut Self::State,
82        _system_meta: &SystemMeta,
83        _world: UnsafeWorldCell<'w>,
84        _change_tick: Tick,
85    ) -> Self::Item<'w, 's> {
86        SystemName(name)
87    }
88}
89
90// SAFETY: Only reads internal system state
91unsafe impl<'s> ReadOnlySystemParam for SystemName<'s> {}
92
93impl ExclusiveSystemParam for SystemName<'_> {
94    type State = Cow<'static, str>;
95    type Item<'s> = SystemName<'s>;
96
97    fn init(_world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
98        system_meta.name.clone()
99    }
100
101    fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {
102        SystemName(state)
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use crate::system::SystemName;
109    use crate::world::World;
110
111    #[test]
112    fn test_system_name_regular_param() {
113        fn testing(name: SystemName) -> String {
114            name.name().to_owned()
115        }
116
117        let mut world = World::default();
118        let id = world.register_system(testing);
119        let name = world.run_system(id).unwrap();
120        assert!(name.ends_with("testing"));
121    }
122
123    #[test]
124    fn test_system_name_exclusive_param() {
125        fn testing(_world: &mut World, name: SystemName) -> String {
126            name.name().to_owned()
127        }
128
129        let mut world = World::default();
130        let id = world.register_system(testing);
131        let name = world.run_system(id).unwrap();
132        assert!(name.ends_with("testing"));
133    }
134}