Skip to main content

bevy_ecs/system/
system_name.rs

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