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