diff options
Diffstat (limited to 'servo/components/style/values/distance.rs')
-rw-r--r-- | servo/components/style/values/distance.rs | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/servo/components/style/values/distance.rs b/servo/components/style/values/distance.rs new file mode 100644 index 0000000000..fef376cf5f --- /dev/null +++ b/servo/components/style/values/distance.rs @@ -0,0 +1,138 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Machinery to compute distances between animatable values. + +use app_units::Au; +use euclid::default::Size2D; +use std::iter::Sum; +use std::ops::Add; + +/// A trait to compute squared distances between two animatable values. +/// +/// This trait is derivable with `#[derive(ComputeSquaredDistance)]`. The derived +/// implementation uses a `match` expression with identical patterns for both +/// `self` and `other`, calling `ComputeSquaredDistance::compute_squared_distance` +/// on each fields of the values. +/// +/// If a variant is annotated with `#[animation(error)]`, the corresponding +/// `match` arm returns an error. +/// +/// Trait bounds for type parameter `Foo` can be opted out of with +/// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for +/// fields can be opted into with `#[distance(field_bound)]` on the field. +pub trait ComputeSquaredDistance { + /// Computes the squared distance between two animatable values. + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>; +} + +/// A distance between two animatable values. +#[derive(Add, Clone, Copy, Debug, From)] +pub struct SquaredDistance { + value: f64, +} + +impl SquaredDistance { + /// Returns a squared distance from its square root. + #[inline] + pub fn from_sqrt(sqrt: f64) -> Self { + Self { value: sqrt * sqrt } + } +} + +impl ComputeSquaredDistance for u16 { + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + Ok(SquaredDistance::from_sqrt( + ((*self as f64) - (*other as f64)).abs(), + )) + } +} + +impl ComputeSquaredDistance for i16 { + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) + } +} + +impl ComputeSquaredDistance for i32 { + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) + } +} + +impl ComputeSquaredDistance for f32 { + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) + } +} + +impl ComputeSquaredDistance for f64 { + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + Ok(SquaredDistance::from_sqrt((*self - *other).abs())) + } +} + +impl ComputeSquaredDistance for Au { + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + self.0.compute_squared_distance(&other.0) + } +} + +impl<T> ComputeSquaredDistance for Box<T> +where + T: ComputeSquaredDistance, +{ + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + (**self).compute_squared_distance(&**other) + } +} + +impl<T> ComputeSquaredDistance for Option<T> +where + T: ComputeSquaredDistance, +{ + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + match (self.as_ref(), other.as_ref()) { + (Some(this), Some(other)) => this.compute_squared_distance(other), + (None, None) => Ok(SquaredDistance::from_sqrt(0.)), + _ => Err(()), + } + } +} + +impl<T> ComputeSquaredDistance for Size2D<T> +where + T: ComputeSquaredDistance, +{ + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { + Ok(self.width.compute_squared_distance(&other.width)? + + self.height.compute_squared_distance(&other.height)?) + } +} + +impl SquaredDistance { + /// Returns the square root of this squared distance. + #[inline] + pub fn sqrt(self) -> f64 { + self.value.sqrt() + } +} + +impl Sum for SquaredDistance { + fn sum<I>(iter: I) -> Self + where + I: Iterator<Item = Self>, + { + iter.fold(SquaredDistance::from_sqrt(0.), Add::add) + } +} |