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