gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81412 Definiciones

⎇ 0.2.x src/math.rs Rust · 374 líneas · 13.2 KB Historia Quién tocó qué crudo

Min values should override max values (#262) b952c2b38 · George Atkinson ·

1//! Contains numerical helper traits and functions
2#![allow(clippy::manual_clamp)]
3
4use crate::geometry::Size;
5use crate::layout::AvailableSpace;
6
7/// A trait to conveniently calculate minimums and maximums when some data may not be defined
8///
9/// If the left-hand value is [`None`], these operations return [`None`].
10/// If the right-hand value is [`None`], it is treated as zero.
11pub(crate) trait MaybeMath<In, Out> {
12    /// Returns the minimum of `self` and `rhs`
13    fn maybe_min(self, rhs: In) -> Out;
14
15    /// Returns the maximum of `self` and `rhs`
16    fn maybe_max(self, rhs: In) -> Out;
17
18    /// Returns `self` clamped between `min` and `max`
19    fn maybe_clamp(self, min: In, max: In) -> Out;
20
21    /// Adds `self` and `rhs`.
22    fn maybe_add(self, rhs: In) -> Out;
23
24    /// Subtracts rhs from `self`, treating [`None`] values as default
25    fn maybe_sub(self, rhs: In) -> Out;
26}
27
28impl MaybeMath<Option<f32>, Option<f32>> for Option<f32> {
29    fn maybe_min(self, rhs: Option<f32>) -> Option<f32> {
30        match (self, rhs) {
31            (Some(l), Some(r)) => Some(l.min(r)),
32            (Some(_l), None) => self,
33            (None, Some(_r)) => None,
34            (None, None) => None,
35        }
36    }
37
38    fn maybe_max(self, rhs: Option<f32>) -> Option<f32> {
39        match (self, rhs) {
40            (Some(l), Some(r)) => Some(l.max(r)),
41            (Some(_l), None) => self,
42            (None, Some(_r)) => None,
43            (None, None) => None,
44        }
45    }
46
47    fn maybe_clamp(self, min: Option<f32>, max: Option<f32>) -> Option<f32> {
48        match (self, min, max) {
49            (Some(base), Some(min), Some(max)) => Some(base.min(max).max(min)),
50            (Some(base), None, Some(max)) => Some(base.min(max)),
51            (Some(base), Some(min), None) => Some(base.max(min)),
52            (Some(_), None, None) => self,
53            (None, _, _) => None,
54        }
55    }
56
57    fn maybe_add(self, rhs: Option<f32>) -> Option<f32> {
58        match (self, rhs) {
59            (Some(l), Some(r)) => Some(l + r),
60            (Some(_l), None) => self,
61            (None, Some(_r)) => None,
62            (None, None) => None,
63        }
64    }
65
66    fn maybe_sub(self, rhs: Option<f32>) -> Option<f32> {
67        match (self, rhs) {
68            (Some(l), Some(r)) => Some(l - r),
69            (Some(_l), None) => self,
70            (None, Some(_r)) => None,
71            (None, None) => None,
72        }
73    }
74}
75
76impl MaybeMath<f32, Option<f32>> for Option<f32> {
77    fn maybe_min(self, rhs: f32) -> Option<f32> {
78        self.map(|val| val.min(rhs))
79    }
80
81    fn maybe_max(self, rhs: f32) -> Option<f32> {
82        self.map(|val| val.max(rhs))
83    }
84
85    fn maybe_clamp(self, min: f32, max: f32) -> Option<f32> {
86        self.map(|val| val.min(max).max(min))
87    }
88
89    fn maybe_add(self, rhs: f32) -> Option<f32> {
90        self.map(|val| val + rhs)
91    }
92
93    fn maybe_sub(self, rhs: f32) -> Option<f32> {
94        self.map(|val| val - rhs)
95    }
96}
97
98impl MaybeMath<Option<f32>, f32> for f32 {
99    fn maybe_min(self, rhs: Option<f32>) -> f32 {
100        match rhs {
101            Some(val) => self.min(val),
102            None => self,
103        }
104    }
105
106    fn maybe_max(self, rhs: Option<f32>) -> f32 {
107        match rhs {
108            Some(val) => self.max(val),
109            None => self,
110        }
111    }
112
113    fn maybe_clamp(self, min: Option<f32>, max: Option<f32>) -> f32 {
114        match (min, max) {
115            (Some(min), Some(max)) => self.min(max).max(min),
116            (None, Some(max)) => self.min(max),
117            (Some(min), None) => self.max(min),
118            (None, None) => self,
119        }
120    }
121
122    fn maybe_add(self, rhs: Option<f32>) -> f32 {
123        match rhs {
124            Some(val) => self + val,
125            None => self,
126        }
127    }
128
129    fn maybe_sub(self, rhs: Option<f32>) -> f32 {
130        match rhs {
131            Some(val) => self - val,
132            None => self,
133        }
134    }
135}
136
137impl MaybeMath<f32, AvailableSpace> for AvailableSpace {
138    fn maybe_min(self, rhs: f32) -> AvailableSpace {
139        match self {
140            AvailableSpace::Definite(val) => AvailableSpace::Definite(val.min(rhs)),
141            AvailableSpace::MinContent => AvailableSpace::Definite(rhs),
142            AvailableSpace::MaxContent => AvailableSpace::Definite(rhs),
143        }
144    }
145    fn maybe_max(self, rhs: f32) -> AvailableSpace {
146        match self {
147            AvailableSpace::Definite(val) => AvailableSpace::Definite(val.max(rhs)),
148            AvailableSpace::MinContent => AvailableSpace::MinContent,
149            AvailableSpace::MaxContent => AvailableSpace::MaxContent,
150        }
151    }
152
153    fn maybe_clamp(self, min: f32, max: f32) -> AvailableSpace {
154        match self {
155            AvailableSpace::Definite(val) => AvailableSpace::Definite(val.min(max).max(min)),
156            AvailableSpace::MinContent => AvailableSpace::MinContent,
157            AvailableSpace::MaxContent => AvailableSpace::MaxContent,
158        }
159    }
160
161    fn maybe_add(self, rhs: f32) -> AvailableSpace {
162        match self {
163            AvailableSpace::Definite(val) => AvailableSpace::Definite(val + rhs),
164            AvailableSpace::MinContent => AvailableSpace::MinContent,
165            AvailableSpace::MaxContent => AvailableSpace::MaxContent,
166        }
167    }
168    fn maybe_sub(self, rhs: f32) -> AvailableSpace {
169        match self {
170            AvailableSpace::Definite(val) => AvailableSpace::Definite(val - rhs),
171            AvailableSpace::MinContent => AvailableSpace::MinContent,
172            AvailableSpace::MaxContent => AvailableSpace::MaxContent,
173        }
174    }
175}
176
177impl MaybeMath<Option<f32>, AvailableSpace> for AvailableSpace {
178    fn maybe_min(self, rhs: Option<f32>) -> AvailableSpace {
179        match (self, rhs) {
180            (AvailableSpace::Definite(val), Some(rhs)) => AvailableSpace::Definite(val.min(rhs)),
181            (AvailableSpace::Definite(val), None) => AvailableSpace::Definite(val),
182            (AvailableSpace::MinContent, Some(rhs)) => AvailableSpace::Definite(rhs),
183            (AvailableSpace::MinContent, None) => AvailableSpace::MinContent,
184            (AvailableSpace::MaxContent, Some(rhs)) => AvailableSpace::Definite(rhs),
185            (AvailableSpace::MaxContent, None) => AvailableSpace::MaxContent,
186        }
187    }
188    fn maybe_max(self, rhs: Option<f32>) -> AvailableSpace {
189        match (self, rhs) {
190            (AvailableSpace::Definite(val), Some(rhs)) => AvailableSpace::Definite(val.max(rhs)),
191            (AvailableSpace::Definite(val), None) => AvailableSpace::Definite(val),
192            (AvailableSpace::MinContent, _) => AvailableSpace::MinContent,
193            (AvailableSpace::MaxContent, _) => AvailableSpace::MaxContent,
194        }
195    }
196
197    fn maybe_clamp(self, min: Option<f32>, max: Option<f32>) -> AvailableSpace {
198        match (self, min, max) {
199            (AvailableSpace::Definite(val), Some(min), Some(max)) => AvailableSpace::Definite(val.min(max).max(min)),
200            (AvailableSpace::Definite(val), None, Some(max)) => AvailableSpace::Definite(val.min(max)),
201            (AvailableSpace::Definite(val), Some(min), None) => AvailableSpace::Definite(val.max(min)),
202            (AvailableSpace::Definite(val), None, None) => AvailableSpace::Definite(val),
203            (AvailableSpace::MinContent, _, _) => AvailableSpace::MinContent,
204            (AvailableSpace::MaxContent, _, _) => AvailableSpace::MaxContent,
205        }
206    }
207
208    fn maybe_add(self, rhs: Option<f32>) -> AvailableSpace {
209        match (self, rhs) {
210            (AvailableSpace::Definite(val), Some(rhs)) => AvailableSpace::Definite(val + rhs),
211            (AvailableSpace::Definite(val), None) => AvailableSpace::Definite(val),
212            (AvailableSpace::MinContent, _) => AvailableSpace::MinContent,
213            (AvailableSpace::MaxContent, _) => AvailableSpace::MaxContent,
214        }
215    }
216    fn maybe_sub(self, rhs: Option<f32>) -> AvailableSpace {
217        match (self, rhs) {
218            (AvailableSpace::Definite(val), Some(rhs)) => AvailableSpace::Definite(val - rhs),
219            (AvailableSpace::Definite(val), None) => AvailableSpace::Definite(val),
220            (AvailableSpace::MinContent, _) => AvailableSpace::MinContent,
221            (AvailableSpace::MaxContent, _) => AvailableSpace::MaxContent,
222        }
223    }
224}
225
226impl<In, Out, T: MaybeMath<In, Out>> MaybeMath<Size<In>, Size<Out>> for Size<T> {
227    fn maybe_min(self, rhs: Size<In>) -> Size<Out> {
228        Size { width: self.width.maybe_min(rhs.width), height: self.height.maybe_min(rhs.height) }
229    }
230
231    fn maybe_max(self, rhs: Size<In>) -> Size<Out> {
232        Size { width: self.width.maybe_max(rhs.width), height: self.height.maybe_max(rhs.height) }
233    }
234
235    fn maybe_clamp(self, min: Size<In>, max: Size<In>) -> Size<Out> {
236        Size {
237            width: self.width.maybe_clamp(min.width, max.width),
238            height: self.height.maybe_clamp(min.height, max.height),
239        }
240    }
241
242    fn maybe_add(self, rhs: Size<In>) -> Size<Out> {
243        Size { width: self.width.maybe_add(rhs.width), height: self.height.maybe_add(rhs.height) }
244    }
245
246    fn maybe_sub(self, rhs: Size<In>) -> Size<Out> {
247        Size { width: self.width.maybe_sub(rhs.width), height: self.height.maybe_sub(rhs.height) }
248    }
249}
250
251#[cfg(test)]
252mod tests {
253    mod lhs_option_f32_rhs_option_f32 {
254
255        use crate::math::MaybeMath;
256        use rstest::rstest;
257
258        #[rstest]
259        #[case(Some(3.0), Some(5.0), Some(3.0))]
260        #[case(Some(5.0), Some(3.0), Some(3.0))]
261        #[case(Some(3.0), None, Some(3.0))]
262        #[case(None, Some(3.0), None)]
263        #[case(None, None, None)]
264        fn test_maybe_min(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
265            assert_eq!(lhs.maybe_min(rhs), expected);
266        }
267
268        #[rstest]
269        #[case(Some(3.0), Some(5.0), Some(5.0))]
270        #[case(Some(5.0), Some(3.0), Some(5.0))]
271        #[case(Some(3.0), None, Some(3.0))]
272        #[case(None, Some(3.0), None)]
273        #[case(None, None, None)]
274        fn test_maybe_max(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
275            assert_eq!(lhs.maybe_max(rhs), expected);
276        }
277
278        #[rstest]
279        #[case(Some(3.0), Some(5.0), Some(8.0))]
280        #[case(Some(5.0), Some(3.0), Some(8.0))]
281        #[case(Some(3.0), None, Some(3.0))]
282        #[case(None, Some(3.0), None)]
283        #[case(None, None, None)]
284        fn test_maybe_add(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
285            assert_eq!(lhs.maybe_add(rhs), expected);
286        }
287
288        #[rstest]
289        #[case(Some(3.0), Some(5.0), Some(-2.0))]
290        #[case(Some(5.0), Some(3.0), Some(2.0))]
291        #[case(Some(3.0), None, Some(3.0))]
292        #[case(None, Some(3.0), None)]
293        #[case(None, None, None)]
294        fn test_maybe_sub(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
295            assert_eq!(lhs.maybe_sub(rhs), expected);
296        }
297    }
298
299    mod lhs_option_f32_rhs_f32 {
300
301        use crate::math::MaybeMath;
302        use rstest::rstest;
303
304        #[rstest]
305        #[case(Some(3.0), 5.0, Some(3.0))]
306        #[case(Some(5.0), 3.0, Some(3.0))]
307        #[case(None, 3.0, None)]
308        fn test_maybe_min(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
309            assert_eq!(lhs.maybe_min(rhs), expected);
310        }
311
312        #[rstest]
313        #[case(Some(3.0), 5.0, Some(5.0))]
314        #[case(Some(5.0), 3.0, Some(5.0))]
315        #[case(None, 3.0, None)]
316        fn test_maybe_max(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
317            assert_eq!(lhs.maybe_max(rhs), expected);
318        }
319
320        #[rstest]
321        #[case(Some(3.0), 5.0, Some(8.0))]
322        #[case(Some(5.0), 3.0, Some(8.0))]
323        #[case(None, 3.0, None)]
324        fn test_maybe_add(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
325            assert_eq!(lhs.maybe_add(rhs), expected);
326        }
327
328        #[rstest]
329        #[case(Some(3.0), 5.0, Some(-2.0))]
330        #[case(Some(5.0), 3.0, Some(2.0))]
331        #[case(None, 3.0, None)]
332        fn test_maybe_sub(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
333            assert_eq!(lhs.maybe_sub(rhs), expected);
334        }
335    }
336
337    mod lhs_f32_rhs_option_f32 {
338
339        use crate::math::MaybeMath;
340        use rstest::rstest;
341
342        #[rstest]
343        #[case(3.0, Some(5.0), 3.0)]
344        #[case(5.0, Some(3.0), 3.0)]
345        #[case(3.0, None, 3.0)]
346        fn test_maybe_min(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
347            assert_eq!(lhs.maybe_min(rhs), expected);
348        }
349
350        #[rstest]
351        #[case(3.0, Some(5.0), 5.0)]
352        #[case(5.0, Some(3.0), 5.0)]
353        #[case(3.0, None, 3.0)]
354        fn test_maybe_max(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
355            assert_eq!(lhs.maybe_max(rhs), expected);
356        }
357
358        #[rstest]
359        #[case(3.0, Some(5.0), 8.0)]
360        #[case(5.0, Some(3.0), 8.0)]
361        #[case(3.0, None, 3.0)]
362        fn test_maybe_add(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
363            assert_eq!(lhs.maybe_add(rhs), expected);
364        }
365
366        #[rstest]
367        #[case(3.0, Some(5.0), -2.0)]
368        #[case(5.0, Some(3.0), 2.0)]
369        #[case(3.0, None, 3.0)]
370        fn test_maybe_sub(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
371            assert_eq!(lhs.maybe_sub(rhs), expected);
372        }
373    }
374}