From a09104b62ce860daad9ced214470f352471c051c Mon Sep 17 00:00:00 2001 From: Matty Date: Tue, 15 Oct 2024 15:55:36 -0400 Subject: [PATCH] Infer `StableInterpolate` on tuples (#15931) # Objective Make `StableInterpolate` "just work" on tuples whose parts are each `StableInterpolate` types. These types arise notably through `Curve::zip` (or just through explicit mapping of a similar form). It would otherwise be kind of frustrating to stumble upon such a thing and then realize that, e.g., automatic resampling just doesn't work, even though there is a very "obvious" way to do it. ## Solution Infer `StableInterpolate` on tuples of up to size 11. I can make that number bigger, if desired. Unfortunately, I don't think that our standard "fake variadics" tools actually work for this; the anonymous field accessors of tuples are `:tt` for purposes of macro expansion, which means that you can't simplify away the identifiers by doing something clever like using recursion (which would work if they were `:expr`). Maybe someone who knows some incredibly dark magic could chime in with a better solution. The expanded impls look like this: ```rust impl< T0: StableInterpolate, T1: StableInterpolate, T2: StableInterpolate, T3: StableInterpolate, T4: StableInterpolate, > StableInterpolate for (T0, T1, T2, T3, T4) { fn interpolate_stable(&self, other: &Self, t: f32) -> Self { ( ::interpolate_stable(&self.0, &other.0, t), ::interpolate_stable(&self.1, &other.1, t), ::interpolate_stable(&self.2, &other.2, t), ::interpolate_stable(&self.3, &other.3, t), ::interpolate_stable(&self.4, &other.4, t), ) } } ``` ## Testing Expanded macros; it compiles. ## Future Make a version of the fake variadics workflow that supports this kind of thing. --- crates/bevy_math/src/common_traits.rs | 78 +++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/crates/bevy_math/src/common_traits.rs b/crates/bevy_math/src/common_traits.rs index c015f73113..a6aeb04683 100644 --- a/crates/bevy_math/src/common_traits.rs +++ b/crates/bevy_math/src/common_traits.rs @@ -309,3 +309,81 @@ impl StableInterpolate for Dir3A { self.slerp(*other, t) } } + +macro_rules! impl_stable_interpolate_tuple { + ($(($T:ident, $n:tt)),*) => { + impl<$($T: StableInterpolate),*> StableInterpolate for ($($T,)*) { + fn interpolate_stable(&self, other: &Self, t: f32) -> Self { + ( + $( + <$T as StableInterpolate>::interpolate_stable(&self.$n, &other.$n, t), + )* + ) + } + } + }; +} + +// (See `macro_metavar_expr`, which might make this better.) +// This currently implements `StableInterpolate` for tuples of up to 11 elements. +impl_stable_interpolate_tuple!((T, 0)); +impl_stable_interpolate_tuple!((T0, 0), (T1, 1)); +impl_stable_interpolate_tuple!((T0, 0), (T1, 1), (T2, 2)); +impl_stable_interpolate_tuple!((T0, 0), (T1, 1), (T2, 2), (T3, 3)); +impl_stable_interpolate_tuple!((T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4)); +impl_stable_interpolate_tuple!((T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5)); +impl_stable_interpolate_tuple!( + (T0, 0), + (T1, 1), + (T2, 2), + (T3, 3), + (T4, 4), + (T5, 5), + (T6, 6) +); +impl_stable_interpolate_tuple!( + (T0, 0), + (T1, 1), + (T2, 2), + (T3, 3), + (T4, 4), + (T5, 5), + (T6, 6), + (T7, 7) +); +impl_stable_interpolate_tuple!( + (T0, 0), + (T1, 1), + (T2, 2), + (T3, 3), + (T4, 4), + (T5, 5), + (T6, 6), + (T7, 7), + (T8, 8) +); +impl_stable_interpolate_tuple!( + (T0, 0), + (T1, 1), + (T2, 2), + (T3, 3), + (T4, 4), + (T5, 5), + (T6, 6), + (T7, 7), + (T8, 8), + (T9, 9) +); +impl_stable_interpolate_tuple!( + (T0, 0), + (T1, 1), + (T2, 2), + (T3, 3), + (T4, 4), + (T5, 5), + (T6, 6), + (T7, 7), + (T8, 8), + (T9, 9), + (T10, 10) +);