From 2994e53d82e91fe8d0728a3ec34d624226d9bd7c Mon Sep 17 00:00:00 2001 From: yonzebu Date: Wed, 11 Dec 2024 09:06:08 -0800 Subject: [PATCH] Support tuple structs in AnimatedField (#16747) # Objective Partially fixes #16736. ## Solution `AnimatedField::new_unchecked` now supports tuple struct fields. `animated_field!` is unchanged. ## Testing Added a test to make sure common and simple uses of `AnimatedField::new_unchecked` with tuple structs don't panic. --------- Co-authored-by: yonzebu --- crates/bevy_animation/src/animation_curves.rs | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/crates/bevy_animation/src/animation_curves.rs b/crates/bevy_animation/src/animation_curves.rs index e41f83157b..0e535644cc 100644 --- a/crates/bevy_animation/src/animation_curves.rs +++ b/crates/bevy_animation/src/animation_curves.rs @@ -243,18 +243,26 @@ where impl &mut P + 'static> AnimatedField { /// Creates a new instance of [`AnimatedField`]. This operates under the assumption that - /// `C` is a reflect-able struct with named fields, and that `field_name` is a valid field on that struct. + /// `C` is a reflect-able struct, and that `field_name` is a valid field on that struct. /// /// # Panics - /// If the type of `C` is not a struct with named fields or if the `field_name` does not exist. + /// If the type of `C` is not a struct or if the `field_name` does not exist. pub fn new_unchecked(field_name: &str, func: F) -> Self { - let TypeInfo::Struct(struct_info) = C::type_info() else { + let field_index; + if let TypeInfo::Struct(struct_info) = C::type_info() { + field_index = struct_info + .index_of(field_name) + .expect("Field name should exist"); + } else if let TypeInfo::TupleStruct(struct_info) = C::type_info() { + field_index = field_name + .parse() + .expect("Field name should be a valid tuple index"); + if field_index >= struct_info.field_len() { + panic!("Field name should be a valid tuple index"); + } + } else { panic!("Only structs are supported in `AnimatedField::new_unchecked`") - }; - - let field_index = struct_info - .index_of(field_name) - .expect("Field name should exist"); + } Self { func, @@ -984,3 +992,21 @@ macro_rules! animated_field { }) }; } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_animated_field_tuple_struct_simple_uses() { + #[derive(Clone, Debug, Component, Reflect)] + struct A(f32); + let _ = AnimatedField::new_unchecked("0", |a: &mut A| &mut a.0); + + #[derive(Clone, Debug, Component, Reflect)] + struct B(f32, f64, f32); + let _ = AnimatedField::new_unchecked("0", |b: &mut B| &mut b.0); + let _ = AnimatedField::new_unchecked("1", |b: &mut B| &mut b.1); + let _ = AnimatedField::new_unchecked("2", |b: &mut B| &mut b.2); + } +}