bevy_ecs/system/
system_name.rs

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