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