-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Description
What problem does this solve or what need does it fill?
The StableInterpolate
trait is very useful! Unfortunately, there are some data types such as Val
and Color
which may or may not be possible to interpolate depending on whether the two input values have the same enum variant. In practice, these will almost always be the same variant, but they might not be, in which case it should fail gracefully.
What solution would you like?
I propose a new trait, FallibleInterpolate
, which can fail:
/// A trait that indicates that a value may be interpolable via [`StableInterpolate`]. An
/// interpolation may fail if the values have different units - for example, attempting to
/// interpolate between `Val::Px` and `Val::Percent` will fail with a `MismatchedUnits` error,
/// even though they are the same Rust type.
pub trait FallibleInterpolate: Clone {
/// Attempt to interpolate the value. This may fail if the two interpolation values have
/// different units.
fn try_interpolate(&self, other: &Self, t: f32) -> Result<Self, InterpolationError>;
}
Code that uses this trait can take appropriate action on failure. For example, an animated transition attempting to interpolate between a start and end point can simply jump directly to the end without interpolation.
The same macro which implements StableInterpolate
for all of the common types can be extend to implement FallibileInterpolate
without the possibility of failure. For something like Val
we can implement the trait thusly:
impl FallibleInterpolate for Val {
fn try_interpolate(&self, other: &Self, t: f32) -> Result<Self, InterpolationError> {
match (self, other) {
(Val::Px(a), Val::Px(b)) => Ok(Val::Px(a.interpolate_stable(b, t))),
(Val::Percent(a), Val::Percent(b)) => Ok(Val::Percent(a.interpolate_stable(b, t))),
(Val::Vw(a), Val::Vw(b)) => Ok(Val::Vw(a.interpolate_stable(b, t))),
(Val::Vh(a), Val::Vh(b)) => Ok(Val::Vh(a.interpolate_stable(b, t))),
(Val::VMin(a), Val::VMin(b)) => Ok(Val::VMin(a.interpolate_stable(b, t))),
(Val::VMax(a), Val::VMax(b)) => Ok(Val::VMax(a.interpolate_stable(b, t))),
(Val::Auto, Val::Auto) => Ok(Val::Auto),
_ => Err(InterpolationError::MismatchedUnits),
}
}
}
What alternative(s) have you considered?
Previously I wrote code that hard-coded the Val variant choice into the generic type of the transition, but this is better.
Additional context
This is part of the work on animated transitions.