bevy_reflect/type_info.rs
1use crate::{
2 ArrayInfo, EnumInfo, ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo,
3 TypePath, TypePathTable,
4};
5use std::any::{Any, TypeId};
6use std::fmt::Debug;
7
8/// A static accessor to compile-time type information.
9///
10/// This trait is automatically implemented by the [`#[derive(Reflect)]`](derive@crate::Reflect) macro
11/// and allows type information to be processed without an instance of that type.
12///
13/// # Implementing
14///
15/// While it is recommended to leave implementing this trait to the `#[derive(Reflect)]` macro,
16/// it is possible to implement this trait manually. If a manual implementation is needed,
17/// you _must_ ensure that the information you provide is correct, otherwise various systems that
18/// rely on this trait may fail in unexpected ways.
19///
20/// Implementors may have difficulty in generating a reference to [`TypeInfo`] with a static
21/// lifetime. Luckily, this crate comes with some [utility] structs, to make generating these
22/// statics much simpler.
23///
24/// # Example
25///
26/// ```
27/// # use std::any::Any;
28/// # use bevy_reflect::{DynamicTypePath, NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, TypePath, ValueInfo, ApplyError};
29/// # use bevy_reflect::utility::NonGenericTypeInfoCell;
30/// use bevy_reflect::Typed;
31///
32/// struct MyStruct {
33/// foo: usize,
34/// bar: (f32, f32)
35/// }
36///
37/// impl Typed for MyStruct {
38/// fn type_info() -> &'static TypeInfo {
39/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
40/// CELL.get_or_set(|| {
41/// let fields = [
42/// NamedField::new::<usize >("foo"),
43/// NamedField::new::<(f32, f32) >("bar"),
44/// ];
45/// let info = StructInfo::new::<Self>(&fields);
46/// TypeInfo::Struct(info)
47/// })
48/// }
49/// }
50///
51/// # impl TypePath for MyStruct {
52/// # fn type_path() -> &'static str { todo!() }
53/// # fn short_type_path() -> &'static str { todo!() }
54/// # }
55/// # impl Reflect for MyStruct {
56/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
57/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
58/// # fn as_any(&self) -> &dyn Any { todo!() }
59/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
60/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
61/// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
62/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
63/// # fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> { todo!() }
64/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
65/// # fn reflect_ref(&self) -> ReflectRef { todo!() }
66/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
67/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
68/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
69/// # }
70/// ```
71///
72/// [utility]: crate::utility
73#[diagnostic::on_unimplemented(
74 message = "`{Self}` can not provide type information through reflection",
75 note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
76)]
77pub trait Typed: Reflect + TypePath {
78 /// Returns the compile-time [info] for the underlying type.
79 ///
80 /// [info]: TypeInfo
81 fn type_info() -> &'static TypeInfo;
82}
83
84/// Compile-time type information for various reflected types.
85///
86/// Generally, for any given type, this value can be retrieved one of three ways:
87///
88/// 1. [`Typed::type_info`]
89/// 2. [`Reflect::get_represented_type_info`]
90/// 3. [`TypeRegistry::get_type_info`]
91///
92/// Each return a static reference to [`TypeInfo`], but they all have their own use cases.
93/// For example, if you know the type at compile time, [`Typed::type_info`] is probably
94/// the simplest. If all you have is a `dyn Reflect`, you'll probably want [`Reflect::get_represented_type_info`].
95/// Lastly, if all you have is a [`TypeId`] or [type path], you will need to go through
96/// [`TypeRegistry::get_type_info`].
97///
98/// You may also opt to use [`TypeRegistry::get_type_info`] in place of the other methods simply because
99/// it can be more performant. This is because those other methods may require attaining a lock on
100/// the static [`TypeInfo`], while the registry simply checks a map.
101///
102/// [`Reflect::get_represented_type_info`]: Reflect::get_represented_type_info
103/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
104/// [type path]: TypePath::type_path
105#[derive(Debug, Clone)]
106pub enum TypeInfo {
107 Struct(StructInfo),
108 TupleStruct(TupleStructInfo),
109 Tuple(TupleInfo),
110 List(ListInfo),
111 Array(ArrayInfo),
112 Map(MapInfo),
113 Enum(EnumInfo),
114 Value(ValueInfo),
115}
116
117impl TypeInfo {
118 /// The [`TypeId`] of the underlying type.
119 pub fn type_id(&self) -> TypeId {
120 match self {
121 Self::Struct(info) => info.type_id(),
122 Self::TupleStruct(info) => info.type_id(),
123 Self::Tuple(info) => info.type_id(),
124 Self::List(info) => info.type_id(),
125 Self::Array(info) => info.type_id(),
126 Self::Map(info) => info.type_id(),
127 Self::Enum(info) => info.type_id(),
128 Self::Value(info) => info.type_id(),
129 }
130 }
131
132 /// A representation of the type path of the underlying type.
133 ///
134 /// Provides dynamic access to all methods on [`TypePath`].
135 pub fn type_path_table(&self) -> &TypePathTable {
136 match self {
137 Self::Struct(info) => info.type_path_table(),
138 Self::TupleStruct(info) => info.type_path_table(),
139 Self::Tuple(info) => info.type_path_table(),
140 Self::List(info) => info.type_path_table(),
141 Self::Array(info) => info.type_path_table(),
142 Self::Map(info) => info.type_path_table(),
143 Self::Enum(info) => info.type_path_table(),
144 Self::Value(info) => info.type_path_table(),
145 }
146 }
147
148 /// The [stable, full type path] of the underlying type.
149 ///
150 /// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
151 ///
152 /// [stable, full type path]: TypePath
153 /// [`type_path_table`]: Self::type_path_table
154 pub fn type_path(&self) -> &'static str {
155 self.type_path_table().path()
156 }
157
158 /// Check if the given type matches the underlying type.
159 pub fn is<T: Any>(&self) -> bool {
160 TypeId::of::<T>() == self.type_id()
161 }
162
163 /// The docstring of the underlying type, if any.
164 #[cfg(feature = "documentation")]
165 pub fn docs(&self) -> Option<&str> {
166 match self {
167 Self::Struct(info) => info.docs(),
168 Self::TupleStruct(info) => info.docs(),
169 Self::Tuple(info) => info.docs(),
170 Self::List(info) => info.docs(),
171 Self::Array(info) => info.docs(),
172 Self::Map(info) => info.docs(),
173 Self::Enum(info) => info.docs(),
174 Self::Value(info) => info.docs(),
175 }
176 }
177}
178
179/// A container for compile-time info related to general value types, including primitives.
180///
181/// This typically represents a type which cannot be broken down any further. This is often
182/// due to technical reasons (or by definition), but it can also be a purposeful choice.
183///
184/// For example, [`i32`] cannot be broken down any further, so it is represented by a [`ValueInfo`].
185/// And while [`String`] itself is a struct, its fields are private, so we don't really treat
186/// it _as_ a struct. It therefore makes more sense to represent it as a [`ValueInfo`].
187#[derive(Debug, Clone)]
188pub struct ValueInfo {
189 type_path: TypePathTable,
190 type_id: TypeId,
191 #[cfg(feature = "documentation")]
192 docs: Option<&'static str>,
193}
194
195impl ValueInfo {
196 pub fn new<T: Reflect + TypePath + ?Sized>() -> Self {
197 Self {
198 type_path: TypePathTable::of::<T>(),
199 type_id: TypeId::of::<T>(),
200 #[cfg(feature = "documentation")]
201 docs: None,
202 }
203 }
204
205 /// Sets the docstring for this value.
206 #[cfg(feature = "documentation")]
207 pub fn with_docs(self, doc: Option<&'static str>) -> Self {
208 Self { docs: doc, ..self }
209 }
210
211 /// A representation of the type path of the value.
212 ///
213 /// Provides dynamic access to all methods on [`TypePath`].
214 pub fn type_path_table(&self) -> &TypePathTable {
215 &self.type_path
216 }
217
218 /// The [stable, full type path] of the value.
219 ///
220 /// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
221 ///
222 /// [stable, full type path]: TypePath
223 /// [`type_path_table`]: Self::type_path_table
224 pub fn type_path(&self) -> &'static str {
225 self.type_path_table().path()
226 }
227
228 /// The [`TypeId`] of the value.
229 pub fn type_id(&self) -> TypeId {
230 self.type_id
231 }
232
233 /// Check if the given type matches the value type.
234 pub fn is<T: Any>(&self) -> bool {
235 TypeId::of::<T>() == self.type_id
236 }
237
238 /// The docstring of this dynamic value, if any.
239 #[cfg(feature = "documentation")]
240 pub fn docs(&self) -> Option<&'static str> {
241 self.docs
242 }
243}