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