diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 90fa58dc372ecd..693ca39d7e88e9 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -696,8 +696,7 @@ impl Reflect for Option { if self.variant_name() == value.variant_name() { // Same variant -> just update fields for (index, field) in value.iter_fields().enumerate() { - let name = value.name_at(index).unwrap(); - if let Some(v) = self.field_mut(name) { + if let Some(v) = self.field_at_mut(index) { v.apply(field.value()); } } @@ -707,14 +706,23 @@ impl Reflect for Option { "Some" => { let field = value .field_at(0) - .expect("Field at index 0 should exist") - .clone_value(); - let field = field.take::().unwrap_or_else(|_| { - panic!( - "Field at index 0 should be of type {}", - std::any::type_name::() - ) - }); + .unwrap_or_else(|| { + panic!( + "Field in `Some` variant of {} should exist", + std::any::type_name::>() + ) + }) + .clone_value() + .take::() + .unwrap_or_else(|value| { + T::from_reflect(&*value).unwrap_or_else(|| { + panic!( + "Field in `Some` variant of {} should be of type {}", + std::any::type_name::>(), + std::any::type_name::() + ) + }) + }); *self = Some(field); } "None" => { @@ -761,14 +769,23 @@ impl FromReflect for Option { "Some" => { let field = dyn_enum .field_at(0) - .expect("Field at index 0 should exist") - .clone_value(); - let field = T::from_reflect(field.as_ref()).unwrap_or_else(|| { - panic!( - "Field at index 0 should be of type {}", - std::any::type_name::() - ) - }); + .unwrap_or_else(|| { + panic!( + "Field in `Some` variant of {} should exist", + std::any::type_name::>() + ) + }) + .clone_value() + .take::() + .unwrap_or_else(|value| { + T::from_reflect(&*value).unwrap_or_else(|| { + panic!( + "Field in `Some` variant of {} should be of type {}", + std::any::type_name::>(), + std::any::type_name::() + ) + }) + }); Some(Some(field)) } "None" => Some(None), @@ -953,6 +970,40 @@ mod tests { assert_eq!(expected, output); } + #[test] + fn option_should_apply() { + #[derive(Reflect, FromReflect, PartialEq, Debug)] + struct Foo(usize); + + // === None on None === // + let patch = None::; + let mut value = None; + Reflect::apply(&mut value, &patch); + + assert_eq!(patch, value, "None apply onto None"); + + // === Some on None === // + let patch = Some(Foo(123)); + let mut value = None; + Reflect::apply(&mut value, &patch); + + assert_eq!(patch, value, "Some apply onto None"); + + // === None on Some === // + let patch = None::; + let mut value = Some(Foo(321)); + Reflect::apply(&mut value, &patch); + + assert_eq!(patch, value, "None apply onto Some"); + + // === Some on Some === // + let patch = Some(Foo(123)); + let mut value = Some(Foo(321)); + Reflect::apply(&mut value, &patch); + + assert_eq!(patch, value, "Some apply onto Some"); + } + #[test] fn option_should_impl_typed() { type MyOption = Option;