Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/enums/mod.rs
9395 views
1
//! Traits and types used to power [enum-like] operations via reflection.
2
//!
3
//! [enum-like]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
4
mod dynamic_enum;
5
mod enum_trait;
6
mod helpers;
7
mod variants;
8
9
pub use dynamic_enum::*;
10
pub use enum_trait::*;
11
pub use helpers::*;
12
pub use variants::*;
13
14
#[cfg(test)]
15
mod tests {
16
use crate::{enums::*, structs::*, tuple::*, *};
17
use alloc::boxed::Box;
18
19
#[derive(Reflect, Debug, PartialEq)]
20
enum MyEnum {
21
A,
22
B(usize, i32),
23
C { foo: f32, bar: bool },
24
}
25
26
#[test]
27
fn should_get_enum_type_info() {
28
let info = MyEnum::type_info();
29
if let TypeInfo::Enum(info) = info {
30
assert!(info.is::<MyEnum>(), "expected type to be `MyEnum`");
31
assert_eq!(MyEnum::type_path(), info.type_path());
32
assert_eq!(MyEnum::type_path(), info.type_path_table().path());
33
assert_eq!(MyEnum::type_ident(), info.type_path_table().ident());
34
assert_eq!(MyEnum::module_path(), info.type_path_table().module_path());
35
assert_eq!(MyEnum::crate_name(), info.type_path_table().crate_name());
36
assert_eq!(
37
MyEnum::short_type_path(),
38
info.type_path_table().short_path()
39
);
40
41
// === MyEnum::A === //
42
assert_eq!("A", info.variant_at(0).unwrap().name());
43
assert_eq!("A", info.variant("A").unwrap().name());
44
if let VariantInfo::Unit(variant) = info.variant("A").unwrap() {
45
assert_eq!("A", variant.name());
46
} else {
47
panic!("Expected `VariantInfo::Unit`");
48
}
49
50
// === MyEnum::B === //
51
assert_eq!("B", info.variant_at(1).unwrap().name());
52
assert_eq!("B", info.variant("B").unwrap().name());
53
if let VariantInfo::Tuple(variant) = info.variant("B").unwrap() {
54
assert!(variant.field_at(0).unwrap().is::<usize>());
55
assert!(variant.field_at(1).unwrap().is::<i32>());
56
assert!(variant
57
.field_at(0)
58
.unwrap()
59
.type_info()
60
.unwrap()
61
.is::<usize>());
62
assert!(variant
63
.field_at(1)
64
.unwrap()
65
.type_info()
66
.unwrap()
67
.is::<i32>());
68
} else {
69
panic!("Expected `VariantInfo::Tuple`");
70
}
71
72
// === MyEnum::C === //
73
assert_eq!("C", info.variant_at(2).unwrap().name());
74
assert_eq!("C", info.variant("C").unwrap().name());
75
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
76
assert!(variant.field_at(0).unwrap().is::<f32>());
77
assert!(variant.field("foo").unwrap().is::<f32>());
78
assert!(variant
79
.field("foo")
80
.unwrap()
81
.type_info()
82
.unwrap()
83
.is::<f32>());
84
} else {
85
panic!("Expected `VariantInfo::Struct`");
86
}
87
} else {
88
panic!("Expected `TypeInfo::Enum`");
89
}
90
}
91
92
#[test]
93
fn dynamic_enum_should_set_variant_fields() {
94
// === Unit === //
95
let mut value = MyEnum::A;
96
let dyn_enum = DynamicEnum::from(MyEnum::A);
97
value.apply(&dyn_enum);
98
assert_eq!(MyEnum::A, value);
99
100
// === Tuple === //
101
let mut value = MyEnum::B(0, 0);
102
let dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
103
value.apply(&dyn_enum);
104
assert_eq!(MyEnum::B(123, 321), value);
105
106
// === Struct === //
107
let mut value = MyEnum::C {
108
foo: 0.0,
109
bar: false,
110
};
111
let dyn_enum = DynamicEnum::from(MyEnum::C {
112
foo: 1.23,
113
bar: true,
114
});
115
value.apply(&dyn_enum);
116
assert_eq!(
117
MyEnum::C {
118
foo: 1.23,
119
bar: true,
120
},
121
value
122
);
123
}
124
125
#[test]
126
fn partial_dynamic_enum_should_set_variant_fields() {
127
// === Tuple === //
128
let mut value = MyEnum::B(0, 0);
129
130
let mut data = DynamicTuple::default();
131
data.insert(123usize);
132
133
let mut dyn_enum = DynamicEnum::default();
134
dyn_enum.set_variant("B", data);
135
value.apply(&dyn_enum);
136
assert_eq!(MyEnum::B(123, 0), value);
137
138
// === Struct === //
139
let mut value = MyEnum::C {
140
foo: 1.23,
141
bar: false,
142
};
143
144
let mut data = DynamicStruct::default();
145
data.insert("bar", true);
146
147
let mut dyn_enum = DynamicEnum::default();
148
dyn_enum.set_variant("C", data);
149
value.apply(&dyn_enum);
150
assert_eq!(
151
MyEnum::C {
152
foo: 1.23,
153
bar: true,
154
},
155
value
156
);
157
}
158
159
#[test]
160
fn dynamic_enum_should_apply_dynamic_enum() {
161
let mut a = DynamicEnum::from(MyEnum::B(123, 321));
162
let b = DynamicEnum::from(MyEnum::B(123, 321));
163
164
// Sanity check that equality check works
165
assert!(
166
a.reflect_partial_eq(&b).unwrap_or_default(),
167
"dynamic enums should be equal"
168
);
169
170
a.set_variant("A", ());
171
assert!(
172
!a.reflect_partial_eq(&b).unwrap_or_default(),
173
"dynamic enums should not be equal"
174
);
175
176
a.apply(&b);
177
assert!(a.reflect_partial_eq(&b).unwrap_or_default());
178
}
179
180
#[test]
181
fn dynamic_enum_should_change_variant() {
182
let mut value = MyEnum::A;
183
184
// === MyEnum::A -> MyEnum::B === //
185
let mut dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
186
value.apply(&dyn_enum);
187
assert_eq!(MyEnum::B(123, 321), value);
188
189
// === MyEnum::B -> MyEnum::C === //
190
let mut data = DynamicStruct::default();
191
data.insert("foo", 1.23_f32);
192
data.insert("bar", true);
193
dyn_enum.set_variant("C", data);
194
value.apply(&dyn_enum);
195
assert_eq!(
196
MyEnum::C {
197
foo: 1.23,
198
bar: true
199
},
200
value
201
);
202
203
// === MyEnum::C -> MyEnum::B === //
204
let mut data = DynamicTuple::default();
205
data.insert(123_usize);
206
data.insert(321_i32);
207
dyn_enum.set_variant("B", data);
208
value.apply(&dyn_enum);
209
assert_eq!(MyEnum::B(123, 321), value);
210
211
// === MyEnum::B -> MyEnum::A === //
212
dyn_enum.set_variant("A", ());
213
value.apply(&dyn_enum);
214
assert_eq!(MyEnum::A, value);
215
}
216
217
#[test]
218
fn dynamic_enum_should_return_is_dynamic() {
219
let dyn_enum = DynamicEnum::from(MyEnum::B(123, 321));
220
assert!(dyn_enum.is_dynamic());
221
}
222
223
#[test]
224
fn enum_should_iterate_fields() {
225
// === Unit === //
226
let value: &dyn Enum = &MyEnum::A;
227
assert_eq!(0, value.field_len());
228
let mut iter = value.iter_fields();
229
assert!(iter.next().is_none());
230
231
// === Tuple === //
232
let value: &dyn Enum = &MyEnum::B(123, 321);
233
assert_eq!(2, value.field_len());
234
let mut iter = value.iter_fields();
235
assert!(iter
236
.next()
237
.and_then(|field| field.value().reflect_partial_eq(&123_usize))
238
.unwrap_or_default());
239
assert!(iter
240
.next()
241
.and_then(|field| field.value().reflect_partial_eq(&321_i32))
242
.unwrap_or_default());
243
244
// === Struct === //
245
let value: &dyn Enum = &MyEnum::C {
246
foo: 1.23,
247
bar: true,
248
};
249
assert_eq!(2, value.field_len());
250
let mut iter = value.iter_fields();
251
assert!(iter
252
.next()
253
.and_then(|field| field
254
.value()
255
.reflect_partial_eq(&1.23_f32)
256
.and(field.name().map(|name| name == "foo")))
257
.unwrap_or_default());
258
assert!(iter
259
.next()
260
.and_then(|field| field
261
.value()
262
.reflect_partial_eq(&true)
263
.and(field.name().map(|name| name == "bar")))
264
.unwrap_or_default());
265
}
266
267
#[test]
268
fn enum_should_return_correct_variant_type() {
269
// === Unit === //
270
let value = MyEnum::A;
271
assert_eq!(VariantType::Unit, value.variant_type());
272
273
// === Tuple === //
274
let value = MyEnum::B(0, 0);
275
assert_eq!(VariantType::Tuple, value.variant_type());
276
277
// === Struct === //
278
let value = MyEnum::C {
279
foo: 1.23,
280
bar: true,
281
};
282
assert_eq!(VariantType::Struct, value.variant_type());
283
}
284
285
#[test]
286
fn enum_should_return_correct_variant_path() {
287
// === Unit === //
288
let value = MyEnum::A;
289
assert_eq!(
290
"bevy_reflect::enums::tests::MyEnum::A",
291
value.variant_path()
292
);
293
294
// === Tuple === //
295
let value = MyEnum::B(0, 0);
296
assert_eq!(
297
"bevy_reflect::enums::tests::MyEnum::B",
298
value.variant_path()
299
);
300
301
// === Struct === //
302
let value = MyEnum::C {
303
foo: 1.23,
304
bar: true,
305
};
306
assert_eq!(
307
"bevy_reflect::enums::tests::MyEnum::C",
308
value.variant_path()
309
);
310
}
311
312
#[test]
313
#[should_panic(
314
expected = "called `Result::unwrap()` on an `Err` value: MismatchedKinds { from_kind: Tuple, to_kind: Enum }"
315
)]
316
fn applying_non_enum_should_panic() {
317
let mut value = MyEnum::B(0, 0);
318
let mut dyn_tuple = DynamicTuple::default();
319
dyn_tuple.insert((123_usize, 321_i32));
320
value.apply(&dyn_tuple);
321
}
322
323
#[test]
324
fn enum_try_apply_should_detect_type_mismatch() {
325
#[derive(Reflect, Debug, PartialEq)]
326
enum MyEnumAnalogue {
327
A(u32),
328
B(usize, usize),
329
C { foo: f32, bar: u8 },
330
}
331
332
let mut target = MyEnumAnalogue::A(0);
333
334
// === Tuple === //
335
let result = target.try_apply(&MyEnum::B(0, 1));
336
assert!(
337
matches!(result, Err(ApplyError::MismatchedTypes { .. })),
338
"`result` was {result:?}"
339
);
340
341
// === Struct === //
342
target = MyEnumAnalogue::C { foo: 0.0, bar: 1 };
343
let result = target.try_apply(&MyEnum::C {
344
foo: 1.0,
345
bar: true,
346
});
347
assert!(
348
matches!(result, Err(ApplyError::MismatchedTypes { .. })),
349
"`result` was {result:?}"
350
);
351
// Type mismatch should occur after partial application.
352
assert_eq!(target, MyEnumAnalogue::C { foo: 1.0, bar: 1 });
353
}
354
355
#[test]
356
fn should_skip_ignored_fields() {
357
#[derive(Reflect, Debug, PartialEq)]
358
enum TestEnum {
359
A,
360
B,
361
C {
362
#[reflect(ignore)]
363
foo: f32,
364
bar: bool,
365
},
366
}
367
368
if let TypeInfo::Enum(info) = TestEnum::type_info() {
369
assert_eq!(3, info.variant_len());
370
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
371
assert_eq!(
372
1,
373
variant.field_len(),
374
"expected one of the fields to be ignored"
375
);
376
assert!(variant.field_at(0).unwrap().is::<bool>());
377
} else {
378
panic!("expected `VariantInfo::Struct`");
379
}
380
} else {
381
panic!("expected `TypeInfo::Enum`");
382
}
383
}
384
385
#[test]
386
fn enum_should_allow_generics() {
387
#[derive(Reflect, Debug, PartialEq)]
388
enum TestEnum<T: FromReflect> {
389
A,
390
B(T),
391
C { value: T },
392
}
393
394
if let TypeInfo::Enum(info) = TestEnum::<f32>::type_info() {
395
if let VariantInfo::Tuple(variant) = info.variant("B").unwrap() {
396
assert!(variant.field_at(0).unwrap().is::<f32>());
397
} else {
398
panic!("expected `VariantInfo::Struct`");
399
}
400
if let VariantInfo::Struct(variant) = info.variant("C").unwrap() {
401
assert!(variant.field("value").unwrap().is::<f32>());
402
} else {
403
panic!("expected `VariantInfo::Struct`");
404
}
405
} else {
406
panic!("expected `TypeInfo::Enum`");
407
}
408
409
let mut value = TestEnum::<f32>::A;
410
411
// === Tuple === //
412
let mut data = DynamicTuple::default();
413
data.insert(1.23_f32);
414
let dyn_enum = DynamicEnum::new("B", data);
415
value.apply(&dyn_enum);
416
assert_eq!(TestEnum::B(1.23), value);
417
418
// === Struct === //
419
let mut data = DynamicStruct::default();
420
data.insert("value", 1.23_f32);
421
let dyn_enum = DynamicEnum::new("C", data);
422
value.apply(&dyn_enum);
423
assert_eq!(TestEnum::C { value: 1.23 }, value);
424
}
425
426
#[test]
427
fn enum_should_allow_struct_fields() {
428
#[derive(Reflect, Debug, PartialEq)]
429
enum TestEnum {
430
A,
431
B(TestStruct),
432
C { value: TestStruct },
433
}
434
435
#[derive(Reflect, Debug, PartialEq)]
436
struct TestStruct(usize);
437
438
let mut value = TestEnum::A;
439
440
// === Tuple === //
441
let mut data = DynamicTuple::default();
442
data.insert(TestStruct(123));
443
let dyn_enum = DynamicEnum::new("B", data);
444
value.apply(&dyn_enum);
445
assert_eq!(TestEnum::B(TestStruct(123)), value);
446
447
// === Struct === //
448
let mut data = DynamicStruct::default();
449
data.insert("value", TestStruct(123));
450
let dyn_enum = DynamicEnum::new("C", data);
451
value.apply(&dyn_enum);
452
assert_eq!(
453
TestEnum::C {
454
value: TestStruct(123)
455
},
456
value
457
);
458
}
459
460
#[test]
461
fn enum_should_allow_nesting_enums() {
462
#[derive(Reflect, Debug, PartialEq)]
463
enum TestEnum {
464
A,
465
B(OtherEnum),
466
C { value: OtherEnum },
467
}
468
469
#[derive(Reflect, Debug, PartialEq)]
470
enum OtherEnum {
471
A,
472
B(usize),
473
C { value: f32 },
474
}
475
476
let mut value = TestEnum::A;
477
478
// === Tuple === //
479
let mut data = DynamicTuple::default();
480
data.insert(OtherEnum::B(123));
481
let dyn_enum = DynamicEnum::new("B", data);
482
value.apply(&dyn_enum);
483
assert_eq!(TestEnum::B(OtherEnum::B(123)), value);
484
485
// === Struct === //
486
let mut data = DynamicStruct::default();
487
data.insert("value", OtherEnum::C { value: 1.23 });
488
let dyn_enum = DynamicEnum::new("C", data);
489
value.apply(&dyn_enum);
490
assert_eq!(
491
TestEnum::C {
492
value: OtherEnum::C { value: 1.23 }
493
},
494
value
495
);
496
}
497
498
#[test]
499
fn enum_should_apply() {
500
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
501
502
// === MyEnum::A -> MyEnum::A === //
503
value.apply(&MyEnum::A);
504
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
505
506
// === MyEnum::A -> MyEnum::B === //
507
value.apply(&MyEnum::B(123, 321));
508
assert!(value
509
.reflect_partial_eq(&MyEnum::B(123, 321))
510
.unwrap_or_default());
511
512
// === MyEnum::B -> MyEnum::B === //
513
value.apply(&MyEnum::B(321, 123));
514
assert!(value
515
.reflect_partial_eq(&MyEnum::B(321, 123))
516
.unwrap_or_default());
517
518
// === MyEnum::B -> MyEnum::C === //
519
value.apply(&MyEnum::C {
520
foo: 1.23,
521
bar: true,
522
});
523
assert!(value
524
.reflect_partial_eq(&MyEnum::C {
525
foo: 1.23,
526
bar: true
527
})
528
.unwrap_or_default());
529
530
// === MyEnum::C -> MyEnum::C === //
531
value.apply(&MyEnum::C {
532
foo: 3.21,
533
bar: false,
534
});
535
assert!(value
536
.reflect_partial_eq(&MyEnum::C {
537
foo: 3.21,
538
bar: false
539
})
540
.unwrap_or_default());
541
542
// === MyEnum::C -> MyEnum::B === //
543
value.apply(&MyEnum::B(123, 321));
544
assert!(value
545
.reflect_partial_eq(&MyEnum::B(123, 321))
546
.unwrap_or_default());
547
548
// === MyEnum::B -> MyEnum::A === //
549
value.apply(&MyEnum::A);
550
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
551
}
552
553
#[test]
554
fn enum_should_set() {
555
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
556
557
// === MyEnum::A -> MyEnum::A === //
558
value.set(Box::new(MyEnum::A)).unwrap();
559
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
560
561
// === MyEnum::A -> MyEnum::B === //
562
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
563
assert!(value
564
.reflect_partial_eq(&MyEnum::B(123, 321))
565
.unwrap_or_default());
566
567
// === MyEnum::B -> MyEnum::B === //
568
value.set(Box::new(MyEnum::B(321, 123))).unwrap();
569
assert!(value
570
.reflect_partial_eq(&MyEnum::B(321, 123))
571
.unwrap_or_default());
572
573
// === MyEnum::B -> MyEnum::C === //
574
value
575
.set(Box::new(MyEnum::C {
576
foo: 1.23,
577
bar: true,
578
}))
579
.unwrap();
580
assert!(value
581
.reflect_partial_eq(&MyEnum::C {
582
foo: 1.23,
583
bar: true
584
})
585
.unwrap_or_default());
586
587
// === MyEnum::C -> MyEnum::C === //
588
value
589
.set(Box::new(MyEnum::C {
590
foo: 3.21,
591
bar: false,
592
}))
593
.unwrap();
594
assert!(value
595
.reflect_partial_eq(&MyEnum::C {
596
foo: 3.21,
597
bar: false
598
})
599
.unwrap_or_default());
600
601
// === MyEnum::C -> MyEnum::B === //
602
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
603
assert!(value
604
.reflect_partial_eq(&MyEnum::B(123, 321))
605
.unwrap_or_default());
606
607
// === MyEnum::B -> MyEnum::A === //
608
value.set(Box::new(MyEnum::A)).unwrap();
609
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
610
}
611
612
#[test]
613
fn enum_should_partial_eq() {
614
#[derive(Reflect)]
615
enum TestEnum {
616
A,
617
A1,
618
B(usize),
619
B1(usize),
620
B2(usize, usize),
621
C { value: i32 },
622
C1 { value: i32 },
623
C2 { value: f32 },
624
}
625
626
let a: &dyn PartialReflect = &TestEnum::A;
627
let b: &dyn PartialReflect = &TestEnum::A;
628
assert!(
629
a.reflect_partial_eq(b).unwrap_or_default(),
630
"expected TestEnum::A == TestEnum::A"
631
);
632
633
let a: &dyn PartialReflect = &TestEnum::A;
634
let b: &dyn PartialReflect = &TestEnum::A1;
635
assert!(
636
!a.reflect_partial_eq(b).unwrap_or_default(),
637
"expected TestEnum::A != TestEnum::A1"
638
);
639
640
let a: &dyn PartialReflect = &TestEnum::B(123);
641
let b: &dyn PartialReflect = &TestEnum::B(123);
642
assert!(
643
a.reflect_partial_eq(b).unwrap_or_default(),
644
"expected TestEnum::B(123) == TestEnum::B(123)"
645
);
646
647
let a: &dyn PartialReflect = &TestEnum::B(123);
648
let b: &dyn PartialReflect = &TestEnum::B(321);
649
assert!(
650
!a.reflect_partial_eq(b).unwrap_or_default(),
651
"expected TestEnum::B(123) != TestEnum::B(321)"
652
);
653
654
let a: &dyn PartialReflect = &TestEnum::B(123);
655
let b: &dyn PartialReflect = &TestEnum::B1(123);
656
assert!(
657
!a.reflect_partial_eq(b).unwrap_or_default(),
658
"expected TestEnum::B(123) != TestEnum::B1(123)"
659
);
660
661
let a: &dyn PartialReflect = &TestEnum::B(123);
662
let b: &dyn PartialReflect = &TestEnum::B2(123, 123);
663
assert!(
664
!a.reflect_partial_eq(b).unwrap_or_default(),
665
"expected TestEnum::B(123) != TestEnum::B2(123, 123)"
666
);
667
668
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
669
let b: &dyn PartialReflect = &TestEnum::C { value: 123 };
670
assert!(
671
a.reflect_partial_eq(b).unwrap_or_default(),
672
"expected TestEnum::C{{value: 123}} == TestEnum::C{{value: 123}}"
673
);
674
675
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
676
let b: &dyn PartialReflect = &TestEnum::C { value: 321 };
677
assert!(
678
!a.reflect_partial_eq(b).unwrap_or_default(),
679
"expected TestEnum::C{{value: 123}} != TestEnum::C{{value: 321}}"
680
);
681
682
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
683
let b: &dyn PartialReflect = &TestEnum::C1 { value: 123 };
684
assert!(
685
!a.reflect_partial_eq(b).unwrap_or_default(),
686
"expected TestEnum::C{{value: 123}} != TestEnum::C1{{value: 123}}"
687
);
688
689
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
690
let b: &dyn PartialReflect = &TestEnum::C2 { value: 1.23 };
691
assert!(
692
!a.reflect_partial_eq(b).unwrap_or_default(),
693
"expected TestEnum::C{{value: 123}} != TestEnum::C2{{value: 1.23}}"
694
);
695
696
#[derive(Reflect)]
697
enum TestEnum2 {
698
A,
699
A1,
700
B(usize, usize),
701
C { value: i32, value2: f32 },
702
}
703
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
704
let a2: &dyn PartialReflect = &TestEnum2::C {
705
value: 123,
706
value2: 1.23,
707
};
708
assert!(
709
!a.reflect_partial_eq(a2).unwrap_or_default(),
710
"expected TestEnum::C{{value: 123}} != TestEnum2::C{{value: 123, value2: 1.23}}"
711
);
712
let b: &dyn PartialReflect = &TestEnum::B(123);
713
let b2 = &TestEnum2::B(123, 321);
714
assert!(
715
!b.reflect_partial_eq(b2).unwrap_or_default(),
716
"expected TestEnum::C{{value: 123}} != TestEnum2::B(123, 321)"
717
);
718
}
719
}
720
721