Skip to main content

bevy_reflect/
ty.rs

1//! Provides access to [`Type`]: a [`TypePath`]-powered replacement for [`TypeId`].
2
3use crate::{TypePath, TypePathTable};
4use core::any::{Any, TypeId};
5use core::fmt::{Debug, Formatter};
6use core::hash::Hash;
7
8/// The base representation of a Rust type.
9///
10/// When possible, it is recommended to use [`&'static TypeInfo`] instead of this
11/// as it provides more information as well as being smaller
12/// (since a reference only takes the same number of bytes as a `usize`).
13///
14/// However, where a static reference to [`TypeInfo`] is not possible,
15/// such as with trait objects and other types that can't implement [`Typed`],
16/// this type can be used instead.
17///
18/// It only requires that the type implements [`TypePath`].
19///
20/// And unlike [`TypeInfo`], this type implements [`Copy`], [`Eq`], and [`Hash`],
21/// making it useful as a key type.
22///
23/// It's especially helpful when compared to [`TypeId`] as it can provide the
24/// actual [type path] when debugging, while still having the same performance
25/// as hashing/comparing [`TypeId`] directly—at the cost of a little more memory.
26///
27/// # Examples
28///
29/// ```
30/// use bevy_reflect::{Type, TypePath};
31///
32/// fn assert_char<T: ?Sized + TypePath>(t: &T) -> Result<(), String> {
33///     let ty = Type::of::<T>();
34///     if Type::of::<char>() == ty {
35///         Ok(())
36///     } else {
37///         Err(format!("expected `char`, got `{}`", ty.path()))
38///     }
39/// }
40///
41/// assert_eq!(
42///     assert_char(&'a'),
43///     Ok(())
44/// );
45/// assert_eq!(
46///     assert_char(&String::from("Hello, world!")),
47///     Err(String::from("expected `char`, got `alloc::string::String`"))
48/// );
49/// ```
50///
51/// [`&'static TypeInfo`]: crate::info::TypeInfo
52/// [`TypeInfo`]: crate::info::TypeInfo
53/// [`Typed`]: crate::info::Typed
54#[derive(Copy, Clone)]
55pub struct Type {
56    type_path_table: TypePathTable,
57    type_id: TypeId,
58}
59
60impl Type {
61    /// Create a new [`Type`] from a type that implements [`TypePath`].
62    pub fn of<T: TypePath + ?Sized>() -> Self {
63        Self {
64            type_path_table: TypePathTable::of::<T>(),
65            type_id: TypeId::of::<T>(),
66        }
67    }
68
69    /// Returns the [`TypeId`] of the type.
70    #[inline]
71    pub fn id(&self) -> TypeId {
72        self.type_id
73    }
74
75    /// See [`crate::type_path::TypePath::type_path`].
76    pub fn path(&self) -> &'static str {
77        self.type_path_table.path()
78    }
79
80    /// See [`crate::type_path::TypePath::short_type_path`].
81    pub fn short_path(&self) -> &'static str {
82        self.type_path_table.short_path()
83    }
84
85    /// See [`crate::type_path::TypePath::type_ident`].
86    pub fn ident(&self) -> Option<&'static str> {
87        self.type_path_table.ident()
88    }
89
90    /// See [`crate::type_path::TypePath::crate_name`].
91    pub fn crate_name(&self) -> Option<&'static str> {
92        self.type_path_table.crate_name()
93    }
94
95    /// See [`crate::type_path::TypePath::module_path`].
96    pub fn module_path(&self) -> Option<&'static str> {
97        self.type_path_table.module_path()
98    }
99
100    /// A representation of the type path of this.
101    ///
102    /// Provides dynamic access to all methods on [`TypePath`].
103    pub fn type_path_table(&self) -> &TypePathTable {
104        &self.type_path_table
105    }
106
107    /// Check if the given type matches this one.
108    ///
109    /// This only compares the [`TypeId`] of the types
110    /// and does not verify they share the same [`TypePath`]
111    /// (though it implies they do).
112    pub fn is<T: Any>(&self) -> bool {
113        TypeId::of::<T>() == self.type_id
114    }
115}
116
117/// This implementation will only output the [type path] of the type.
118///
119/// If you need to include the [`TypeId`] in the output,
120/// you can access it through [`Type::id`].
121///
122/// [type path]: TypePath
123impl Debug for Type {
124    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
125        write!(f, "{}", self.type_path_table.path())
126    }
127}
128
129impl Eq for Type {}
130
131/// This implementation purely relies on the [`TypeId`] of the type,
132/// and not on the [type path].
133///
134/// [type path]: TypePath
135impl PartialEq for Type {
136    #[inline]
137    fn eq(&self, other: &Self) -> bool {
138        self.type_id == other.type_id
139    }
140}
141
142/// This implementation purely relies on the [`TypeId`] of the type,
143/// and not on the [type path].
144///
145/// [type path]: TypePath
146impl Hash for Type {
147    #[inline]
148    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
149        self.type_id.hash(state);
150    }
151}
152
153macro_rules! impl_type_methods {
154    // Generates the type methods based off a single field.
155    ($field:ident) => {
156        $crate::ty::impl_type_methods!(self => {
157            &self.$field
158        });
159    };
160    // Generates the type methods based off a custom expression.
161    ($self:ident => $expr:expr) => {
162        /// The underlying Rust [type].
163        ///
164        /// [type]: crate::ty::Type
165        pub fn ty(&$self) -> &$crate::ty::Type {
166            $expr
167        }
168
169        /// The [`TypeId`] of this type.
170        ///
171        /// [`TypeId`]: core::any::TypeId
172        pub fn type_id(&self) -> ::core::any::TypeId {
173            self.ty().id()
174        }
175
176        /// The [stable, full type path] of this type.
177        ///
178        /// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
179        ///
180        /// [stable, full type path]: TypePath
181        /// [`type_path_table`]: Self::type_path_table
182        pub fn type_path(&self) -> &'static str {
183            self.ty().path()
184        }
185
186        /// A representation of the type path of this type.
187        ///
188        /// Provides dynamic access to all methods on [`TypePath`].
189        ///
190        /// [`TypePath`]: crate::type_path::TypePath
191        pub fn type_path_table(&self) -> &$crate::type_path::TypePathTable {
192            &self.ty().type_path_table()
193        }
194
195        /// Check if the given type matches this one.
196        ///
197        /// This only compares the [`TypeId`] of the types
198        /// and does not verify they share the same [`TypePath`]
199        /// (though it implies they do).
200        ///
201        /// [`TypeId`]: core::any::TypeId
202        /// [`TypePath`]: crate::type_path::TypePath
203        pub fn is<T: ::core::any::Any>(&self) -> bool {
204            self.ty().is::<T>()
205        }
206    };
207}
208
209pub(crate) use impl_type_methods;