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;