bevy_reflect/type_path.rs
1use core::fmt;
2
3/// A static accessor to type paths and names.
4///
5/// The engine uses this trait over [`std::any::type_name`] for stability and flexibility.
6///
7/// This trait is automatically implemented by the `#[derive(Reflect)]` macro
8/// and allows type path information to be processed without an instance of that type.
9///
10/// Implementors may have difficulty in generating references with static
11/// lifetimes. Luckily, this crate comes with some [utility] structs, to make generating these
12/// statics much simpler.
13///
14/// # Stability
15///
16/// Certain parts of the engine, e.g. [(de)serialization], rely on type paths as identifiers
17/// for matching dynamic values to concrete types.
18///
19/// Using [`std::any::type_name`], a scene containing `my_crate::foo::MyComponent` would break,
20/// failing to deserialize if the component was moved from the `foo` module to the `bar` module,
21/// becoming `my_crate::bar::MyComponent`.
22/// This trait, through attributes when deriving itself or [`Reflect`], can ensure breaking changes are avoidable.
23///
24/// The only external factor we rely on for stability when deriving is the [`module_path!`] macro,
25/// only if the derive does not provide a `#[type_path = "..."]` attribute.
26///
27/// # Anonymity
28///
29/// Some methods on this trait return `Option<&'static str>` over `&'static str`
30/// because not all types define all parts of a type path, for example the array type `[T; N]`.
31///
32/// Such types are 'anonymous' in that they have only a defined [`type_path`] and [`short_type_path`]
33/// and the methods [`crate_name`], [`module_path`] and [`type_ident`] all return `None`.
34///
35/// Primitives are treated like anonymous types, except they also have a defined [`type_ident`].
36///
37/// # Example
38///
39/// ```
40/// use bevy_reflect::TypePath;
41///
42/// // This type path will not change with compiler versions or recompiles,
43/// // although it will not be the same if the definition is moved.
44/// #[derive(TypePath)]
45/// struct NonStableTypePath;
46///
47/// // This type path will never change, even if the definition is moved.
48/// #[derive(TypePath)]
49/// #[type_path = "my_crate::foo"]
50/// struct StableTypePath;
51///
52/// // Type paths can have any number of path segments.
53/// #[derive(TypePath)]
54/// #[type_path = "my_crate::foo::bar::baz"]
55/// struct DeeplyNestedStableTypePath;
56///
57/// // Including just a crate name!
58/// #[derive(TypePath)]
59/// #[type_path = "my_crate"]
60/// struct ShallowStableTypePath;
61///
62/// // We can also rename the identifier/name of types.
63/// #[derive(TypePath)]
64/// #[type_path = "my_crate::foo"]
65/// #[type_name = "RenamedStableTypePath"]
66/// struct NamedStableTypePath;
67///
68/// // Generics are also supported.
69/// #[derive(TypePath)]
70/// #[type_path = "my_crate::foo"]
71/// struct StableGenericTypePath<T, const N: usize>([T; N]);
72/// ```
73///
74/// [utility]: crate::utility
75/// [(de)serialization]: crate::serde::ReflectDeserializer
76/// [`Reflect`]: crate::Reflect
77/// [`type_path`]: TypePath::type_path
78/// [`short_type_path`]: TypePath::short_type_path
79/// [`crate_name`]: TypePath::crate_name
80/// [`module_path`]: TypePath::module_path
81/// [`type_ident`]: TypePath::type_ident
82#[diagnostic::on_unimplemented(
83 message = "`{Self}` does not implement `TypePath` so cannot provide static type path information",
84 note = "consider annotating `{Self}` with `#[derive(Reflect)]` or `#[derive(TypePath)]`"
85)]
86pub trait TypePath: 'static {
87 /// Returns the fully qualified path of the underlying type.
88 ///
89 /// Generic parameter types are also fully expanded.
90 ///
91 /// For `Option<Vec<usize>>`, this is `"std::option::Option<std::vec::Vec<usize>>"`.
92 fn type_path() -> &'static str;
93
94 /// Returns a short, pretty-print enabled path to the type.
95 ///
96 /// Generic parameter types are also shortened.
97 ///
98 /// For `Option<Vec<usize>>`, this is `"Option<Vec<usize>>"`.
99 fn short_type_path() -> &'static str;
100
101 /// Returns the name of the type, or [`None`] if it is [anonymous].
102 ///
103 /// Primitive types will return [`Some`].
104 ///
105 /// For `Option<Vec<usize>>`, this is `"Option"`.
106 ///
107 /// [anonymous]: TypePath#anonymity
108 fn type_ident() -> Option<&'static str> {
109 None
110 }
111
112 /// Returns the name of the crate the type is in, or [`None`] if it is [anonymous].
113 ///
114 /// For `Option<Vec<usize>>`, this is `"core"`.
115 ///
116 /// [anonymous]: TypePath#anonymity
117 fn crate_name() -> Option<&'static str> {
118 None
119 }
120
121 /// Returns the path to the module the type is in, or [`None`] if it is [anonymous].
122 ///
123 /// For `Option<Vec<usize>>`, this is `"std::option"`.
124 ///
125 /// [anonymous]: TypePath#anonymity
126 fn module_path() -> Option<&'static str> {
127 None
128 }
129}
130
131/// Dynamic dispatch for [`TypePath`].
132///
133/// Since this is a supertrait of [`Reflect`] its methods can be called on a `dyn Reflect`.
134///
135/// [`Reflect`]: crate::Reflect
136#[diagnostic::on_unimplemented(
137 message = "`{Self}` does not implement `TypePath` so cannot provide dynamic type path information",
138 note = "consider annotating `{Self}` with `#[derive(Reflect)]` or `#[derive(TypePath)]`"
139)]
140pub trait DynamicTypePath {
141 /// See [`TypePath::type_path`].
142 fn reflect_type_path(&self) -> &str;
143
144 /// See [`TypePath::short_type_path`].
145 fn reflect_short_type_path(&self) -> &str;
146
147 /// See [`TypePath::type_ident`].
148 fn reflect_type_ident(&self) -> Option<&str>;
149
150 /// See [`TypePath::crate_name`].
151 fn reflect_crate_name(&self) -> Option<&str>;
152
153 /// See [`TypePath::module_path`].
154 fn reflect_module_path(&self) -> Option<&str>;
155}
156
157impl<T: TypePath> DynamicTypePath for T {
158 #[inline]
159 fn reflect_type_path(&self) -> &str {
160 Self::type_path()
161 }
162
163 #[inline]
164 fn reflect_short_type_path(&self) -> &str {
165 Self::short_type_path()
166 }
167
168 #[inline]
169 fn reflect_type_ident(&self) -> Option<&str> {
170 Self::type_ident()
171 }
172
173 #[inline]
174 fn reflect_crate_name(&self) -> Option<&str> {
175 Self::crate_name()
176 }
177
178 #[inline]
179 fn reflect_module_path(&self) -> Option<&str> {
180 Self::module_path()
181 }
182}
183
184/// Provides dynamic access to all methods on [`TypePath`].
185#[derive(Clone, Copy)]
186pub struct TypePathTable {
187 // Cache the type path as it is likely the only one that will be used.
188 type_path: &'static str,
189 short_type_path: fn() -> &'static str,
190 type_ident: fn() -> Option<&'static str>,
191 crate_name: fn() -> Option<&'static str>,
192 module_path: fn() -> Option<&'static str>,
193}
194
195impl fmt::Debug for TypePathTable {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 f.debug_struct("TypePathVtable")
198 .field("type_path", &self.type_path)
199 .field("short_type_path", &(self.short_type_path)())
200 .field("type_ident", &(self.type_ident)())
201 .field("crate_name", &(self.crate_name)())
202 .field("module_path", &(self.module_path)())
203 .finish()
204 }
205}
206
207impl TypePathTable {
208 /// Creates a new table from a type.
209 pub fn of<T: TypePath + ?Sized>() -> Self {
210 Self {
211 type_path: T::type_path(),
212 short_type_path: T::short_type_path,
213 type_ident: T::type_ident,
214 crate_name: T::crate_name,
215 module_path: T::module_path,
216 }
217 }
218
219 /// See [`TypePath::type_path`].
220 pub fn path(&self) -> &'static str {
221 self.type_path
222 }
223
224 /// See [`TypePath::short_type_path`].
225 pub fn short_path(&self) -> &'static str {
226 (self.short_type_path)()
227 }
228
229 /// See [`TypePath::type_ident`].
230 pub fn ident(&self) -> Option<&'static str> {
231 (self.type_ident)()
232 }
233
234 /// See [`TypePath::crate_name`].
235 pub fn crate_name(&self) -> Option<&'static str> {
236 (self.crate_name)()
237 }
238
239 /// See [`TypePath::module_path`].
240 pub fn module_path(&self) -> Option<&'static str> {
241 (self.module_path)()
242 }
243}