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}