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}