bevy_reflect/info/type_info.rs
1use crate::{
2 array::ArrayInfo, enums::EnumInfo, generics::impl_generic_info_methods, list::ListInfo,
3 map::MapInfo, set::SetInfo, structs::StructInfo, tuple::TupleInfo,
4 tuple_struct::TupleStructInfo, OpaqueInfo, ReflectKind, Type, TypePathTable,
5};
6use core::any::{Any, TypeId};
7
8/// Compile-time type information for various reflected types.
9///
10/// Generally, for any given type, this value can be retrieved in one of four ways:
11///
12/// 1. [`Typed::type_info`]
13/// 2. [`DynamicTyped::reflect_type_info`]
14/// 3. [`PartialReflect::get_represented_type_info`]
15/// 4. [`TypeRegistry::get_type_info`]
16///
17/// Each returns a static reference to [`TypeInfo`], but they all have their own use cases.
18/// For example, if you know the type at compile time, [`Typed::type_info`] is probably
19/// the simplest. If you have a `dyn Reflect` you can use [`DynamicTyped::reflect_type_info`].
20/// If all you have is a `dyn PartialReflect`, you'll probably want [`PartialReflect::get_represented_type_info`].
21/// Lastly, if all you have is a [`TypeId`] or [type path], you will need to go through
22/// [`TypeRegistry::get_type_info`].
23///
24/// You may also opt to use [`TypeRegistry::get_type_info`] in place of the other methods simply because
25/// it can be more performant. This is because those other methods may require attaining a lock on
26/// the static [`TypeInfo`], while the registry simply checks a map.
27///
28/// [`Typed::type_info`]: crate::info::Typed::type_info
29/// [`DynamicTyped::reflect_type_info`]: crate::info::DynamicTyped::reflect_type_info
30/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
31/// [`PartialReflect::get_represented_type_info`]: crate::PartialReflect::get_represented_type_info
32/// [type path]: crate::type_path::TypePath::type_path
33#[derive(Debug, Clone)]
34pub enum TypeInfo {
35 /// Type information for a [struct-like] type.
36 ///
37 /// [struct-like]: crate::structs::Struct
38 Struct(StructInfo),
39 /// Type information for a [tuple-struct-like] type.
40 ///
41 /// [tuple-struct-like]: crate::tuple_struct::TupleStruct
42 TupleStruct(TupleStructInfo),
43 /// Type information for a [tuple-like] type.
44 ///
45 /// [tuple-like]: crate::tuple::Tuple
46 Tuple(TupleInfo),
47 /// Type information for a [list-like] type.
48 ///
49 /// [list-like]: crate::list::List
50 List(ListInfo),
51 /// Type information for an [array-like] type.
52 ///
53 /// [array-like]: crate::array::Array
54 Array(ArrayInfo),
55 /// Type information for a [map-like] type.
56 ///
57 /// [map-like]: crate::map::Map
58 Map(MapInfo),
59 /// Type information for a [set-like] type.
60 ///
61 /// [set-like]: crate::set::Set
62 Set(SetInfo),
63 /// Type information for an [enum-like] type.
64 ///
65 /// [enum-like]: crate::enums::Enum
66 Enum(EnumInfo),
67 /// Type information for an opaque type - see the [`OpaqueInfo`] docs for
68 /// a discussion of opaque types.
69 Opaque(OpaqueInfo),
70}
71
72impl TypeInfo {
73 /// The underlying Rust [type].
74 ///
75 /// [type]: Type
76 pub fn ty(&self) -> &Type {
77 match self {
78 Self::Struct(info) => info.ty(),
79 Self::TupleStruct(info) => info.ty(),
80 Self::Tuple(info) => info.ty(),
81 Self::List(info) => info.ty(),
82 Self::Array(info) => info.ty(),
83 Self::Map(info) => info.ty(),
84 Self::Set(info) => info.ty(),
85 Self::Enum(info) => info.ty(),
86 Self::Opaque(info) => info.ty(),
87 }
88 }
89
90 /// The [`TypeId`] of the underlying type.
91 #[inline]
92 pub fn type_id(&self) -> TypeId {
93 self.ty().id()
94 }
95
96 /// A representation of the type path of the underlying type.
97 ///
98 /// Provides dynamic access to all methods on [`TypePath`].
99 ///
100 /// [`TypePath`]: crate::type_path::TypePath
101 pub fn type_path_table(&self) -> &TypePathTable {
102 self.ty().type_path_table()
103 }
104
105 /// The [stable, full type path] of the underlying type.
106 ///
107 /// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
108 ///
109 /// [stable, full type path]: crate::type_path::TypePath
110 /// [`type_path_table`]: Self::type_path_table
111 /// [`TypePath`]: crate::type_path::TypePath
112 pub fn type_path(&self) -> &'static str {
113 self.ty().path()
114 }
115
116 /// Check if the given type matches this one.
117 ///
118 /// This only compares the [`TypeId`] of the types
119 /// and does not verify they share the same [`TypePath`]
120 /// (though it implies they do).
121 ///
122 /// [`TypePath`]: crate::type_path::TypePath
123 pub fn is<T: Any>(&self) -> bool {
124 self.ty().is::<T>()
125 }
126
127 /// The docstring of the underlying type, if any.
128 #[cfg(feature = "reflect_documentation")]
129 pub fn docs(&self) -> Option<&str> {
130 match self {
131 Self::Struct(info) => info.docs(),
132 Self::TupleStruct(info) => info.docs(),
133 Self::Tuple(info) => info.docs(),
134 Self::List(info) => info.docs(),
135 Self::Array(info) => info.docs(),
136 Self::Map(info) => info.docs(),
137 Self::Set(info) => info.docs(),
138 Self::Enum(info) => info.docs(),
139 Self::Opaque(info) => info.docs(),
140 }
141 }
142
143 /// Returns the [kind] of this `TypeInfo`.
144 ///
145 /// [kind]: ReflectKind
146 pub fn kind(&self) -> ReflectKind {
147 match self {
148 Self::Struct(_) => ReflectKind::Struct,
149 Self::TupleStruct(_) => ReflectKind::TupleStruct,
150 Self::Tuple(_) => ReflectKind::Tuple,
151 Self::List(_) => ReflectKind::List,
152 Self::Array(_) => ReflectKind::Array,
153 Self::Map(_) => ReflectKind::Map,
154 Self::Set(_) => ReflectKind::Set,
155 Self::Enum(_) => ReflectKind::Enum,
156 Self::Opaque(_) => ReflectKind::Opaque,
157 }
158 }
159
160 impl_generic_info_methods!(self => {
161 match self {
162 Self::Struct(info) => info.generics(),
163 Self::TupleStruct(info) => info.generics(),
164 Self::Tuple(info) => info.generics(),
165 Self::List(info) => info.generics(),
166 Self::Array(info) => info.generics(),
167 Self::Map(info) => info.generics(),
168 Self::Set(info) => info.generics(),
169 Self::Enum(info) => info.generics(),
170 Self::Opaque(info) => info.generics(),
171 }
172 });
173}
174
175macro_rules! impl_cast_method {
176 ($name:ident : $kind:ident => $info:ident) => {
177 #[doc = concat!("Attempts a cast to [`", stringify!($info), "`].")]
178 #[doc = concat!("\n\nReturns an error if `self` is not [`TypeInfo::", stringify!($kind), "`].")]
179 pub fn $name(&self) -> Result<&$info, $crate::info::error::TypeInfoError> {
180 match self {
181 Self::$kind(info) => Ok(info),
182 _ => Err($crate::info::error::TypeInfoError::KindMismatch {
183 expected: ReflectKind::$kind,
184 received: self.kind(),
185 }),
186 }
187 }
188 };
189}
190
191/// Conversion convenience methods for [`TypeInfo`].
192impl TypeInfo {
193 impl_cast_method!(as_struct: Struct => StructInfo);
194 impl_cast_method!(as_tuple_struct: TupleStruct => TupleStructInfo);
195 impl_cast_method!(as_tuple: Tuple => TupleInfo);
196 impl_cast_method!(as_list: List => ListInfo);
197 impl_cast_method!(as_array: Array => ArrayInfo);
198 impl_cast_method!(as_map: Map => MapInfo);
199 impl_cast_method!(as_set: Set => SetInfo);
200 impl_cast_method!(as_enum: Enum => EnumInfo);
201 impl_cast_method!(as_opaque: Opaque => OpaqueInfo);
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use crate::info::typed::Typed;
208 use crate::TypeInfoError;
209 use alloc::vec::Vec;
210 use bevy_platform::collections::HashSet;
211
212 #[test]
213 fn should_return_error_on_invalid_cast() {
214 let info = <Vec<i32> as Typed>::type_info();
215 assert!(matches!(
216 info.as_struct(),
217 Err(TypeInfoError::KindMismatch {
218 expected: ReflectKind::Struct,
219 received: ReflectKind::List
220 })
221 ));
222 }
223
224 #[test]
225 fn should_cast_to_set() {
226 let info = <HashSet<u64> as Typed>::type_info();
227 assert!(info.as_set().is_ok());
228 }
229}