1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Machinery to compute distances between animatable values. 6 7 use app_units::Au; 8 use euclid::default::Size2D; 9 use std::iter::Sum; 10 use std::ops::Add; 11 12 /// A trait to compute squared distances between two animatable values. 13 /// 14 /// This trait is derivable with `#[derive(ComputeSquaredDistance)]`. The derived 15 /// implementation uses a `match` expression with identical patterns for both 16 /// `self` and `other`, calling `ComputeSquaredDistance::compute_squared_distance` 17 /// on each fields of the values. 18 /// 19 /// If a variant is annotated with `#[animation(error)]`, the corresponding 20 /// `match` arm returns an error. 21 /// 22 /// Trait bounds for type parameter `Foo` can be opted out of with 23 /// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for 24 /// fields can be opted into with `#[distance(field_bound)]` on the field. 25 pub trait ComputeSquaredDistance { 26 /// Computes the squared distance between two animatable values. compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>27 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>; 28 } 29 30 /// A distance between two animatable values. 31 #[derive(Add, Clone, Copy, Debug, From)] 32 pub struct SquaredDistance { 33 value: f64, 34 } 35 36 impl SquaredDistance { 37 /// Returns a squared distance from its square root. 38 #[inline] from_sqrt(sqrt: f64) -> Self39 pub fn from_sqrt(sqrt: f64) -> Self { 40 Self { value: sqrt * sqrt } 41 } 42 } 43 44 impl ComputeSquaredDistance for u16 { 45 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>46 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 47 Ok(SquaredDistance::from_sqrt( 48 ((*self as f64) - (*other as f64)).abs(), 49 )) 50 } 51 } 52 53 impl ComputeSquaredDistance for i32 { 54 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>55 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 56 Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) 57 } 58 } 59 60 impl ComputeSquaredDistance for f32 { 61 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>62 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 63 Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) 64 } 65 } 66 67 impl ComputeSquaredDistance for f64 { 68 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>69 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 70 Ok(SquaredDistance::from_sqrt((*self - *other).abs())) 71 } 72 } 73 74 impl ComputeSquaredDistance for Au { 75 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>76 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 77 self.0.compute_squared_distance(&other.0) 78 } 79 } 80 81 impl<T> ComputeSquaredDistance for Box<T> 82 where 83 T: ComputeSquaredDistance, 84 { 85 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>86 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 87 (**self).compute_squared_distance(&**other) 88 } 89 } 90 91 impl<T> ComputeSquaredDistance for Option<T> 92 where 93 T: ComputeSquaredDistance, 94 { 95 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>96 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 97 match (self.as_ref(), other.as_ref()) { 98 (Some(this), Some(other)) => this.compute_squared_distance(other), 99 (None, None) => Ok(SquaredDistance::from_sqrt(0.)), 100 _ => Err(()), 101 } 102 } 103 } 104 105 impl<T> ComputeSquaredDistance for Size2D<T> 106 where 107 T: ComputeSquaredDistance, 108 { 109 #[inline] compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>110 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 111 Ok(self.width.compute_squared_distance(&other.width)? + 112 self.height.compute_squared_distance(&other.height)?) 113 } 114 } 115 116 impl SquaredDistance { 117 /// Returns the square root of this squared distance. 118 #[inline] sqrt(self) -> f64119 pub fn sqrt(self) -> f64 { 120 self.value.sqrt() 121 } 122 } 123 124 impl Sum for SquaredDistance { sum<I>(iter: I) -> Self where I: Iterator<Item = Self>,125 fn sum<I>(iter: I) -> Self 126 where 127 I: Iterator<Item = Self>, 128 { 129 iter.fold(SquaredDistance::from_sqrt(0.), Add::add) 130 } 131 } 132