bevy_reflect/
kind.rs

1use derive_more::derive::{Display, Error};
2
3#[cfg(feature = "functions")]
4use crate::func::Function;
5use crate::{Array, Enum, List, Map, PartialReflect, Set, Struct, Tuple, TupleStruct};
6
7/// An enumeration of the "kinds" of a reflected type.
8///
9/// Each kind corresponds to a specific reflection trait,
10/// such as [`Struct`] or [`List`],
11/// which itself corresponds to the kind or structure of a type.
12///
13/// A [`ReflectKind`] is obtained via [`PartialReflect::reflect_kind`],
14/// or via [`ReflectRef::kind`],[`ReflectMut::kind`] or [`ReflectOwned::kind`].
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16pub enum ReflectKind {
17    /// A [struct-like] type.
18    ///
19    /// [struct-like]: Struct
20    Struct,
21    /// A [tuple-struct-like] type.
22    ///
23    /// [tuple-struct-like]: TupleStruct
24    TupleStruct,
25    /// A [tuple-like] type.
26    ///
27    /// [tuple-like]: Tuple
28    Tuple,
29    /// A [list-like] type.
30    ///
31    /// [list-like]: List
32    List,
33    /// An [array-like] type.
34    ///
35    /// [array-like]: Array
36    Array,
37    /// A [map-like] type.
38    ///
39    /// [map-like]: Map
40    Map,
41    /// A [set-like] type.
42    ///
43    /// [set-like]: Set
44    Set,
45    /// An [enum-like] type.
46    ///
47    /// [enum-like]: Enum
48    Enum,
49    /// A [function-like] type.
50    ///
51    /// [function-like]: Function
52    #[cfg(feature = "functions")]
53    Function,
54    /// An opaque type.
55    ///
56    /// This most often represents a type where it is either impossible, difficult,
57    /// or unuseful to reflect the type further.
58    ///
59    /// This includes types like `String` and `Instant`.
60    ///
61    /// Despite not technically being opaque types,
62    /// primitives like `u32` `i32` are considered opaque for the purposes of reflection.
63    ///
64    /// Additionally, any type that [derives `Reflect`] with the `#[reflect(opaque)]` attribute
65    /// will be considered an opaque type.
66    ///
67    /// [derives `Reflect`]: bevy_reflect_derive::Reflect
68    Opaque,
69}
70
71impl core::fmt::Display for ReflectKind {
72    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
73        match self {
74            ReflectKind::Struct => f.pad("struct"),
75            ReflectKind::TupleStruct => f.pad("tuple struct"),
76            ReflectKind::Tuple => f.pad("tuple"),
77            ReflectKind::List => f.pad("list"),
78            ReflectKind::Array => f.pad("array"),
79            ReflectKind::Map => f.pad("map"),
80            ReflectKind::Set => f.pad("set"),
81            ReflectKind::Enum => f.pad("enum"),
82            #[cfg(feature = "functions")]
83            ReflectKind::Function => f.pad("function"),
84            ReflectKind::Opaque => f.pad("opaque"),
85        }
86    }
87}
88
89macro_rules! impl_reflect_kind_conversions {
90    ($name:ident$(<$lifetime:lifetime>)?) => {
91        impl $name$(<$lifetime>)? {
92            /// Returns the "kind" of this reflected type without any information.
93            pub fn kind(&self) -> ReflectKind {
94                match self {
95                    Self::Struct(_) => ReflectKind::Struct,
96                    Self::TupleStruct(_) => ReflectKind::TupleStruct,
97                    Self::Tuple(_) => ReflectKind::Tuple,
98                    Self::List(_) => ReflectKind::List,
99                    Self::Array(_) => ReflectKind::Array,
100                    Self::Map(_) => ReflectKind::Map,
101                    Self::Set(_) => ReflectKind::Set,
102                    Self::Enum(_) => ReflectKind::Enum,
103                    #[cfg(feature = "functions")]
104                    Self::Function(_) => ReflectKind::Function,
105                    Self::Opaque(_) => ReflectKind::Opaque,
106                }
107            }
108        }
109
110        impl From<$name$(<$lifetime>)?> for ReflectKind {
111            fn from(value: $name) -> Self {
112                match value {
113                    $name::Struct(_) => Self::Struct,
114                    $name::TupleStruct(_) => Self::TupleStruct,
115                    $name::Tuple(_) => Self::Tuple,
116                    $name::List(_) => Self::List,
117                    $name::Array(_) => Self::Array,
118                    $name::Map(_) => Self::Map,
119                    $name::Set(_) => Self::Set,
120                    $name::Enum(_) => Self::Enum,
121                    #[cfg(feature = "functions")]
122                    $name::Function(_) => Self::Function,
123                    $name::Opaque(_) => Self::Opaque,
124                }
125            }
126        }
127    };
128}
129
130/// Caused when a type was expected to be of a certain [kind], but was not.
131///
132/// [kind]: ReflectKind
133#[derive(Debug, Error, Display)]
134#[display("kind mismatch: expected {expected:?}, received {received:?}")]
135pub struct ReflectKindMismatchError {
136    pub expected: ReflectKind,
137    pub received: ReflectKind,
138}
139
140macro_rules! impl_cast_method {
141    ($name:ident : Opaque => $retval:ty) => {
142        #[doc = "Attempts a cast to a [`PartialReflect`] trait object."]
143        #[doc = "\n\nReturns an error if `self` is not the [`Self::Opaque`] variant."]
144        pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
145            match self {
146                Self::Opaque(value) => Ok(value),
147                _ => Err(ReflectKindMismatchError {
148                    expected: ReflectKind::Opaque,
149                    received: self.kind(),
150                }),
151            }
152        }
153    };
154    ($name:ident : $kind:ident => $retval:ty) => {
155        #[doc = concat!("Attempts a cast to a [`", stringify!($kind), "`] trait object.")]
156        #[doc = concat!("\n\nReturns an error if `self` is not the [`Self::", stringify!($kind), "`] variant.")]
157        pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
158            match self {
159                Self::$kind(value) => Ok(value),
160                _ => Err(ReflectKindMismatchError {
161                    expected: ReflectKind::$kind,
162                    received: self.kind(),
163                }),
164            }
165        }
166    };
167}
168
169/// An immutable enumeration of ["kinds"] of a reflected type.
170///
171/// Each variant contains a trait object with methods specific to a kind of
172/// type.
173///
174/// A [`ReflectRef`] is obtained via [`PartialReflect::reflect_ref`].
175///
176/// ["kinds"]: ReflectKind
177pub enum ReflectRef<'a> {
178    Struct(&'a dyn Struct),
179    TupleStruct(&'a dyn TupleStruct),
180    Tuple(&'a dyn Tuple),
181    List(&'a dyn List),
182    Array(&'a dyn Array),
183    Map(&'a dyn Map),
184    Set(&'a dyn Set),
185    Enum(&'a dyn Enum),
186    #[cfg(feature = "functions")]
187    Function(&'a dyn Function),
188    Opaque(&'a dyn PartialReflect),
189}
190impl_reflect_kind_conversions!(ReflectRef<'_>);
191
192impl<'a> ReflectRef<'a> {
193    impl_cast_method!(as_struct: Struct => &'a dyn Struct);
194    impl_cast_method!(as_tuple_struct: TupleStruct => &'a dyn TupleStruct);
195    impl_cast_method!(as_tuple: Tuple => &'a dyn Tuple);
196    impl_cast_method!(as_list: List => &'a dyn List);
197    impl_cast_method!(as_array: Array => &'a dyn Array);
198    impl_cast_method!(as_map: Map => &'a dyn Map);
199    impl_cast_method!(as_set: Set => &'a dyn Set);
200    impl_cast_method!(as_enum: Enum => &'a dyn Enum);
201    impl_cast_method!(as_opaque: Opaque => &'a dyn PartialReflect);
202}
203
204/// A mutable enumeration of ["kinds"] of a reflected type.
205///
206/// Each variant contains a trait object with methods specific to a kind of
207/// type.
208///
209/// A [`ReflectMut`] is obtained via [`PartialReflect::reflect_mut`].
210///
211/// ["kinds"]: ReflectKind
212pub enum ReflectMut<'a> {
213    Struct(&'a mut dyn Struct),
214    TupleStruct(&'a mut dyn TupleStruct),
215    Tuple(&'a mut dyn Tuple),
216    List(&'a mut dyn List),
217    Array(&'a mut dyn Array),
218    Map(&'a mut dyn Map),
219    Set(&'a mut dyn Set),
220    Enum(&'a mut dyn Enum),
221    #[cfg(feature = "functions")]
222    Function(&'a mut dyn Function),
223    Opaque(&'a mut dyn PartialReflect),
224}
225impl_reflect_kind_conversions!(ReflectMut<'_>);
226
227impl<'a> ReflectMut<'a> {
228    impl_cast_method!(as_struct: Struct => &'a mut dyn Struct);
229    impl_cast_method!(as_tuple_struct: TupleStruct => &'a mut dyn TupleStruct);
230    impl_cast_method!(as_tuple: Tuple => &'a mut dyn Tuple);
231    impl_cast_method!(as_list: List => &'a mut dyn List);
232    impl_cast_method!(as_array: Array => &'a mut dyn Array);
233    impl_cast_method!(as_map: Map => &'a mut dyn Map);
234    impl_cast_method!(as_set: Set => &'a mut dyn Set);
235    impl_cast_method!(as_enum: Enum => &'a mut dyn Enum);
236    impl_cast_method!(as_opaque: Opaque => &'a mut dyn PartialReflect);
237}
238
239/// An owned enumeration of ["kinds"] of a reflected type.
240///
241/// Each variant contains a trait object with methods specific to a kind of
242/// type.
243///
244/// A [`ReflectOwned`] is obtained via [`PartialReflect::reflect_owned`].
245///
246/// ["kinds"]: ReflectKind
247pub enum ReflectOwned {
248    Struct(Box<dyn Struct>),
249    TupleStruct(Box<dyn TupleStruct>),
250    Tuple(Box<dyn Tuple>),
251    List(Box<dyn List>),
252    Array(Box<dyn Array>),
253    Map(Box<dyn Map>),
254    Set(Box<dyn Set>),
255    Enum(Box<dyn Enum>),
256    #[cfg(feature = "functions")]
257    Function(Box<dyn Function>),
258    Opaque(Box<dyn PartialReflect>),
259}
260impl_reflect_kind_conversions!(ReflectOwned);
261
262impl ReflectOwned {
263    impl_cast_method!(into_struct: Struct => Box<dyn Struct>);
264    impl_cast_method!(into_tuple_struct: TupleStruct => Box<dyn TupleStruct>);
265    impl_cast_method!(into_tuple: Tuple => Box<dyn Tuple>);
266    impl_cast_method!(into_list: List => Box<dyn List>);
267    impl_cast_method!(into_array: Array => Box<dyn Array>);
268    impl_cast_method!(into_map: Map => Box<dyn Map>);
269    impl_cast_method!(into_set: Set => Box<dyn Set>);
270    impl_cast_method!(into_enum: Enum => Box<dyn Enum>);
271    impl_cast_method!(into_value: Opaque => Box<dyn PartialReflect>);
272}
273
274#[cfg(test)]
275mod tests {
276    use std::collections::HashSet;
277
278    use super::*;
279
280    #[test]
281    fn should_cast_ref() {
282        let value = vec![1, 2, 3];
283
284        let result = value.reflect_ref().as_list();
285        assert!(result.is_ok());
286
287        let result = value.reflect_ref().as_array();
288        assert!(matches!(
289            result,
290            Err(ReflectKindMismatchError {
291                expected: ReflectKind::Array,
292                received: ReflectKind::List
293            })
294        ));
295    }
296
297    #[test]
298    fn should_cast_mut() {
299        let mut value: HashSet<i32> = HashSet::new();
300
301        let result = value.reflect_mut().as_set();
302        assert!(result.is_ok());
303
304        let result = value.reflect_mut().as_map();
305        assert!(matches!(
306            result,
307            Err(ReflectKindMismatchError {
308                expected: ReflectKind::Map,
309                received: ReflectKind::Set
310            })
311        ));
312    }
313
314    #[test]
315    fn should_cast_owned() {
316        let value = Box::new(Some(123));
317
318        let result = value.reflect_owned().into_enum();
319        assert!(result.is_ok());
320
321        let value = Box::new(Some(123));
322
323        let result = value.reflect_owned().into_struct();
324        assert!(matches!(
325            result,
326            Err(ReflectKindMismatchError {
327                expected: ReflectKind::Struct,
328                received: ReflectKind::Enum
329            })
330        ));
331    }
332}