Skip to main content

bevy_utils/
debug_info.rs

1use crate::cfg;
2cfg::alloc! {
3    use alloc::{borrow::Cow, fmt, string::String};
4}
5#[cfg(feature = "debug")]
6use core::any::type_name;
7use core::ops::Deref;
8use disqualified::ShortName;
9
10#[cfg(not(feature = "debug"))]
11const FEATURE_DISABLED: &str = "<Enable the debug feature to see the name>";
12
13/// Wrapper to help debugging ECS issues. This is used to display the names of systems, components, ...
14///
15/// * If the `debug` feature is enabled, the actual name will be used
16/// * If it is disabled, a string mentioning the disabled feature will be used
17#[derive(Clone, PartialEq, Eq)]
18pub struct DebugName {
19    #[cfg(feature = "debug")]
20    name: Cow<'static, str>,
21}
22
23cfg::alloc! {
24    impl fmt::Display for DebugName {
25        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
26            // Deref to `str`, which will use `FEATURE_DISABLED` if necessary
27            write!(f, "{}", &**self)
28        }
29    }
30
31    impl fmt::Debug for DebugName {
32        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33            // Deref to `str`, which will use `FEATURE_DISABLED` if necessary
34            write!(f, "{:?}", &**self)
35        }
36    }
37}
38
39impl DebugName {
40    /// Create a new `DebugName` from a `&str`
41    ///
42    /// The value will be ignored if the `debug` feature is not enabled
43    #[cfg_attr(
44        not(feature = "debug"),
45        expect(
46            unused_variables,
47            reason = "The value will be ignored if the `debug` feature is not enabled"
48        )
49    )]
50    pub const fn borrowed(value: &'static str) -> Self {
51        DebugName {
52            #[cfg(feature = "debug")]
53            name: Cow::Borrowed(value),
54        }
55    }
56
57    cfg::alloc! {
58        /// Create a new `DebugName` from a `String`
59        ///
60        /// The value will be ignored if the `debug` feature is not enabled
61        #[cfg_attr(
62            not(feature = "debug"),
63            expect(
64                unused_variables,
65                reason = "The value will be ignored if the `debug` feature is not enabled"
66            )
67        )]
68        pub fn owned(value: String) -> Self {
69            DebugName {
70                #[cfg(feature = "debug")]
71                name: Cow::Owned(value),
72            }
73        }
74    }
75
76    /// Create a new `DebugName` from a type by using its [`core::any::type_name`]
77    ///
78    /// The value will be ignored if the `debug` feature is not enabled
79    pub fn type_name<T>() -> Self {
80        DebugName {
81            #[cfg(feature = "debug")]
82            name: Cow::Borrowed(type_name::<T>()),
83        }
84    }
85
86    /// Create a new `DebugName` from a type by using its [`core::any::type_name`]
87    ///
88    /// This is the same as `type_name::<T>()`, but can be used where the type of a
89    /// variable is not easily available.
90    ///
91    /// The value will be ignored if the `debug` feature is not enabled
92    pub fn type_name_of_val<T>(_val: &T) -> Self {
93        DebugName {
94            #[cfg(feature = "debug")]
95            name: Cow::Borrowed(type_name::<T>()),
96        }
97    }
98
99    /// Get the [`ShortName`] corresponding to this debug name
100    ///
101    /// The value will be a static string if the `debug` feature is not enabled
102    pub fn shortname(&self) -> ShortName<'_> {
103        #[cfg(feature = "debug")]
104        return ShortName(self.name.as_ref());
105        #[cfg(not(feature = "debug"))]
106        return ShortName(FEATURE_DISABLED);
107    }
108
109    /// Return the string hold by this `DebugName`
110    ///
111    /// This is intended for debugging purpose, and only available if the `debug` feature is enabled
112    #[cfg(feature = "debug")]
113    pub fn as_string(&self) -> String {
114        self.name.clone().into_owned()
115    }
116}
117
118impl Deref for DebugName {
119    type Target = str;
120
121    fn deref(&self) -> &Self::Target {
122        #[cfg(feature = "debug")]
123        return &self.name;
124        #[cfg(not(feature = "debug"))]
125        return FEATURE_DISABLED;
126    }
127}
128
129cfg::alloc! {
130    impl From<Cow<'static, str>> for DebugName {
131        #[cfg_attr(
132            not(feature = "debug"),
133            expect(
134                unused_variables,
135                reason = "The value will be ignored if the `debug` feature is not enabled"
136            )
137        )]
138        fn from(value: Cow<'static, str>) -> Self {
139            Self {
140                #[cfg(feature = "debug")]
141                name: value,
142            }
143        }
144    }
145
146    impl From<String> for DebugName {
147        fn from(value: String) -> Self {
148            Self::owned(value)
149        }
150    }
151
152    impl From<DebugName> for Cow<'static, str> {
153        #[cfg_attr(
154            not(feature = "debug"),
155            expect(
156                unused_variables,
157                reason = "The value will be ignored if the `debug` feature is not enabled"
158            )
159        )]
160        fn from(value: DebugName) -> Self {
161            #[cfg(feature = "debug")]
162            {
163                value.name
164            }
165            #[cfg(not(feature = "debug"))]
166            {
167                Cow::Borrowed(FEATURE_DISABLED)
168            }
169        }
170    }
171}
172
173impl From<&'static str> for DebugName {
174    fn from(value: &'static str) -> Self {
175        Self::borrowed(value)
176    }
177}