Skip to main content

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}