Skip to content

Commit db54952

Browse files
committed
Fix DynamicEnum::apply for differing variants
1 parent 4f0b16d commit db54952

File tree

2 files changed

+173
-6
lines changed

2 files changed

+173
-6
lines changed

crates/bevy_reflect/src/enums/dynamic_enum.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,15 +280,47 @@ impl Reflect for DynamicEnum {
280280

281281
#[inline]
282282
fn apply(&mut self, value: &dyn Reflect) {
283-
if let ReflectRef::Enum(enum_value) = value.reflect_ref() {
284-
for field in enum_value.iter_fields() {
285-
let name = field.name().unwrap();
286-
if let Some(v) = self.field_mut(name) {
287-
v.apply(field.value());
283+
if let ReflectRef::Enum(value) = value.reflect_ref() {
284+
if Enum::variant_name(self) == value.variant_name() {
285+
// Same variant -> just update fields
286+
match value.variant_type() {
287+
VariantType::Struct => {
288+
for field in value.iter_fields() {
289+
let name = field.name().unwrap();
290+
Enum::field_mut(self, name).map(|v| v.apply(field.value()));
291+
}
292+
}
293+
VariantType::Tuple => {
294+
for (index, field) in value.iter_fields().enumerate() {
295+
Enum::field_at_mut(self, index).map(|v| v.apply(field.value()));
296+
}
297+
}
298+
_ => {}
288299
}
300+
} else {
301+
// New variant -> perform a switch
302+
let dyn_variant = match value.variant_type() {
303+
VariantType::Unit => DynamicVariant::Unit,
304+
VariantType::Tuple => {
305+
let mut dyn_tuple = DynamicTuple::default();
306+
for field in value.iter_fields() {
307+
dyn_tuple.insert_boxed(field.value().clone_value());
308+
}
309+
DynamicVariant::Tuple(dyn_tuple)
310+
}
311+
VariantType::Struct => {
312+
let mut dyn_struct = DynamicStruct::default();
313+
for field in value.iter_fields() {
314+
dyn_struct
315+
.insert_boxed(field.name().unwrap(), field.value().clone_value());
316+
}
317+
DynamicVariant::Struct(dyn_struct)
318+
}
319+
};
320+
self.set_variant(value.variant_name(), dyn_variant);
289321
}
290322
} else {
291-
panic!("Attempted to apply non-enum type to enum type.");
323+
panic!("`{}` is not an enum", value.type_name());
292324
}
293325
}
294326

crates/bevy_reflect/src/enums/mod.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,27 @@ mod tests {
127127
);
128128
}
129129

130+
#[test]
131+
fn dynamic_enum_should_apply_dynamic_enum() {
132+
let mut a = DynamicEnum::from(MyEnum::B(123, 321));
133+
let b = DynamicEnum::from(MyEnum::B(123, 321));
134+
135+
// Sanity check that equality check works
136+
assert!(
137+
a.reflect_partial_eq(&b).unwrap_or_default(),
138+
"dynamic enums should be equal"
139+
);
140+
141+
a.set_variant("A", ());
142+
assert!(
143+
!a.reflect_partial_eq(&b).unwrap_or_default(),
144+
"dynamic enums should not be equal"
145+
);
146+
147+
a.apply(&b);
148+
assert!(a.reflect_partial_eq(&b).unwrap_or_default());
149+
}
150+
130151
#[test]
131152
fn dynamic_enum_should_change_variant() {
132153
let mut value = MyEnum::A;
@@ -429,6 +450,120 @@ mod tests {
429450
);
430451
}
431452

453+
#[test]
454+
fn enum_should_apply() {
455+
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
456+
457+
// === MyEnum::A -> MyEnum::A === //
458+
value.apply(&MyEnum::A);
459+
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
460+
461+
// === MyEnum::A -> MyEnum::B === //
462+
value.apply(&MyEnum::B(123, 321));
463+
assert!(value
464+
.reflect_partial_eq(&MyEnum::B(123, 321))
465+
.unwrap_or_default());
466+
467+
// === MyEnum::B -> MyEnum::B === //
468+
value.apply(&MyEnum::B(321, 123));
469+
assert!(value
470+
.reflect_partial_eq(&MyEnum::B(321, 123))
471+
.unwrap_or_default());
472+
473+
// === MyEnum::B -> MyEnum::C === //
474+
value.apply(&MyEnum::C {
475+
foo: 1.23,
476+
bar: true,
477+
});
478+
assert!(value
479+
.reflect_partial_eq(&MyEnum::C {
480+
foo: 1.23,
481+
bar: true
482+
})
483+
.unwrap_or_default());
484+
485+
// === MyEnum::C -> MyEnum::C === //
486+
value.apply(&MyEnum::C {
487+
foo: 3.21,
488+
bar: false,
489+
});
490+
assert!(value
491+
.reflect_partial_eq(&MyEnum::C {
492+
foo: 3.21,
493+
bar: false
494+
})
495+
.unwrap_or_default());
496+
497+
// === MyEnum::C -> MyEnum::B === //
498+
value.apply(&MyEnum::B(123, 321));
499+
assert!(value
500+
.reflect_partial_eq(&MyEnum::B(123, 321))
501+
.unwrap_or_default());
502+
503+
// === MyEnum::B -> MyEnum::A === //
504+
value.apply(&MyEnum::A);
505+
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
506+
}
507+
508+
#[test]
509+
fn enum_should_set() {
510+
let mut value: Box<dyn Reflect> = Box::new(MyEnum::A);
511+
512+
// === MyEnum::A -> MyEnum::A === //
513+
value.set(Box::new(MyEnum::A)).unwrap();
514+
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
515+
516+
// === MyEnum::A -> MyEnum::B === //
517+
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
518+
assert!(value
519+
.reflect_partial_eq(&MyEnum::B(123, 321))
520+
.unwrap_or_default());
521+
522+
// === MyEnum::B -> MyEnum::B === //
523+
value.set(Box::new(MyEnum::B(321, 123))).unwrap();
524+
assert!(value
525+
.reflect_partial_eq(&MyEnum::B(321, 123))
526+
.unwrap_or_default());
527+
528+
// === MyEnum::B -> MyEnum::C === //
529+
value
530+
.set(Box::new(MyEnum::C {
531+
foo: 1.23,
532+
bar: true,
533+
}))
534+
.unwrap();
535+
assert!(value
536+
.reflect_partial_eq(&MyEnum::C {
537+
foo: 1.23,
538+
bar: true
539+
})
540+
.unwrap_or_default());
541+
542+
// === MyEnum::C -> MyEnum::C === //
543+
value
544+
.set(Box::new(MyEnum::C {
545+
foo: 3.21,
546+
bar: false,
547+
}))
548+
.unwrap();
549+
assert!(value
550+
.reflect_partial_eq(&MyEnum::C {
551+
foo: 3.21,
552+
bar: false
553+
})
554+
.unwrap_or_default());
555+
556+
// === MyEnum::C -> MyEnum::B === //
557+
value.set(Box::new(MyEnum::B(123, 321))).unwrap();
558+
assert!(value
559+
.reflect_partial_eq(&MyEnum::B(123, 321))
560+
.unwrap_or_default());
561+
562+
// === MyEnum::B -> MyEnum::A === //
563+
value.set(Box::new(MyEnum::A)).unwrap();
564+
assert!(value.reflect_partial_eq(&MyEnum::A).unwrap_or_default());
565+
}
566+
432567
#[test]
433568
fn enum_should_partial_eq() {
434569
#[derive(Reflect)]

0 commit comments

Comments
 (0)