tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 231Rust 8TOML 3CSS 1317 Definiciones

⎇ d35459ebdd9de19801aace1f8d83aafe436aaf33 src/math.rs Rust · 248 líneas · 7.5 KB Historia Quién tocó qué crudo

Add unit tests for `MaybeMath` (#162) d35459ebd · TimJentzsch ·

1//! Contains numerical helper traits and functions
2
3/// A trait to conveniently calculate minimums and maximums when some data may not be defined
4///
5/// If the left-hand value is [`None`], these operations return [`None`].
6/// If the right-hand value is [`None`], it is treated as zero.
7pub(crate) trait MaybeMath<In, Out> {
8    /// Returns the minimum of `self` and `rhs`
9    fn maybe_min(self, rhs: In) -> Out;
10
11    /// Returns the maximum of `self` and `rhs`
12    fn maybe_max(self, rhs: In) -> Out;
13
14    /// Adds `self` and `rhs`.
15    fn maybe_add(self, rhs: In) -> Out;
16
17    /// Subtracts rhs from `self`, treating [`None`] values as default
18    fn maybe_sub(self, rhs: In) -> Out;
19}
20
21impl MaybeMath<Option<f32>, Option<f32>> for Option<f32> {
22    fn maybe_min(self, rhs: Option<f32>) -> Option<f32> {
23        match (self, rhs) {
24            (Some(l), Some(r)) => Some(l.min(r)),
25            (Some(_l), None) => self,
26            (None, Some(_r)) => None,
27            (None, None) => None,
28        }
29    }
30
31    fn maybe_max(self, rhs: Option<f32>) -> Option<f32> {
32        match (self, rhs) {
33            (Some(l), Some(r)) => Some(l.max(r)),
34            (Some(_l), None) => self,
35            (None, Some(_r)) => None,
36            (None, None) => None,
37        }
38    }
39
40    fn maybe_add(self, rhs: Option<f32>) -> Option<f32> {
41        match (self, rhs) {
42            (Some(l), Some(r)) => Some(l + r),
43            (Some(_l), None) => self,
44            (None, Some(_r)) => None,
45            (None, None) => None,
46        }
47    }
48
49    fn maybe_sub(self, rhs: Option<f32>) -> Option<f32> {
50        match (self, rhs) {
51            (Some(l), Some(r)) => Some(l - r),
52            (Some(_l), None) => self,
53            (None, Some(_r)) => None,
54            (None, None) => None,
55        }
56    }
57}
58
59impl MaybeMath<f32, Option<f32>> for Option<f32> {
60    // The logic here is subtle and critical;
61    // explicit match statements make it more clear what's going on
62    #[allow(clippy::manual_map)]
63    fn maybe_min(self, rhs: f32) -> Option<f32> {
64        match self {
65            Some(val) => Some(val.min(rhs)),
66            None => None,
67        }
68    }
69
70    #[allow(clippy::manual_map)]
71    fn maybe_max(self, rhs: f32) -> Option<f32> {
72        match self {
73            Some(val) => Some(val.max(rhs)),
74            None => None,
75        }
76    }
77
78    #[allow(clippy::manual_map)]
79    fn maybe_add(self, rhs: f32) -> Option<f32> {
80        match self {
81            Some(val) => Some(val + rhs),
82            None => None,
83        }
84    }
85
86    #[allow(clippy::manual_map)]
87    fn maybe_sub(self, rhs: f32) -> Option<f32> {
88        match self {
89            Some(val) => Some(val - rhs),
90            None => None,
91        }
92    }
93}
94
95impl MaybeMath<Option<f32>, f32> for f32 {
96    fn maybe_min(self, rhs: Option<f32>) -> f32 {
97        match rhs {
98            Some(val) => self.min(val),
99            None => self,
100        }
101    }
102
103    fn maybe_max(self, rhs: Option<f32>) -> f32 {
104        match rhs {
105            Some(val) => self.max(val),
106            None => self,
107        }
108    }
109
110    fn maybe_add(self, rhs: Option<f32>) -> f32 {
111        match rhs {
112            Some(val) => self + val,
113            None => self,
114        }
115    }
116
117    fn maybe_sub(self, rhs: Option<f32>) -> f32 {
118        match rhs {
119            Some(val) => self - val,
120            None => self,
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    mod lhs_option_f32_rhs_option_f32 {
128
129        use crate::math::MaybeMath;
130        use rstest::rstest;
131
132        #[rstest]
133        #[case(Some(3.0), Some(5.0), Some(3.0))]
134        #[case(Some(5.0), Some(3.0), Some(3.0))]
135        #[case(Some(3.0), None, Some(3.0))]
136        #[case(None, Some(3.0), None)]
137        #[case(None, None, None)]
138        fn test_maybe_min(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
139            assert_eq!(lhs.maybe_min(rhs), expected);
140        }
141
142        #[rstest]
143        #[case(Some(3.0), Some(5.0), Some(5.0))]
144        #[case(Some(5.0), Some(3.0), Some(5.0))]
145        #[case(Some(3.0), None, Some(3.0))]
146        #[case(None, Some(3.0), None)]
147        #[case(None, None, None)]
148        fn test_maybe_max(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
149            assert_eq!(lhs.maybe_max(rhs), expected);
150        }
151
152        #[rstest]
153        #[case(Some(3.0), Some(5.0), Some(8.0))]
154        #[case(Some(5.0), Some(3.0), Some(8.0))]
155        #[case(Some(3.0), None, Some(3.0))]
156        #[case(None, Some(3.0), None)]
157        #[case(None, None, None)]
158        fn test_maybe_add(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
159            assert_eq!(lhs.maybe_add(rhs), expected);
160        }
161
162        #[rstest]
163        #[case(Some(3.0), Some(5.0), Some(-2.0))]
164        #[case(Some(5.0), Some(3.0), Some(2.0))]
165        #[case(Some(3.0), None, Some(3.0))]
166        #[case(None, Some(3.0), None)]
167        #[case(None, None, None)]
168        fn test_maybe_sub(#[case] lhs: Option<f32>, #[case] rhs: Option<f32>, #[case] expected: Option<f32>) {
169            assert_eq!(lhs.maybe_sub(rhs), expected);
170        }
171    }
172
173    mod lhs_option_f32_rhs_f32 {
174
175        use crate::math::MaybeMath;
176        use rstest::rstest;
177
178        #[rstest]
179        #[case(Some(3.0), 5.0, Some(3.0))]
180        #[case(Some(5.0), 3.0, Some(3.0))]
181        #[case(None, 3.0, None)]
182        fn test_maybe_min(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
183            assert_eq!(lhs.maybe_min(rhs), expected);
184        }
185
186        #[rstest]
187        #[case(Some(3.0), 5.0, Some(5.0))]
188        #[case(Some(5.0), 3.0, Some(5.0))]
189        #[case(None, 3.0, None)]
190        fn test_maybe_max(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
191            assert_eq!(lhs.maybe_max(rhs), expected);
192        }
193
194        #[rstest]
195        #[case(Some(3.0), 5.0, Some(8.0))]
196        #[case(Some(5.0), 3.0, Some(8.0))]
197        #[case(None, 3.0, None)]
198        fn test_maybe_add(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
199            assert_eq!(lhs.maybe_add(rhs), expected);
200        }
201
202        #[rstest]
203        #[case(Some(3.0), 5.0, Some(-2.0))]
204        #[case(Some(5.0), 3.0, Some(2.0))]
205        #[case(None, 3.0, None)]
206        fn test_maybe_sub(#[case] lhs: Option<f32>, #[case] rhs: f32, #[case] expected: Option<f32>) {
207            assert_eq!(lhs.maybe_sub(rhs), expected);
208        }
209    }
210
211    mod lhs_f32_rhs_option_f32 {
212
213        use crate::math::MaybeMath;
214        use rstest::rstest;
215
216        #[rstest]
217        #[case(3.0, Some(5.0), 3.0)]
218        #[case(5.0, Some(3.0), 3.0)]
219        #[case(3.0, None, 3.0)]
220        fn test_maybe_min(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
221            assert_eq!(lhs.maybe_min(rhs), expected);
222        }
223
224        #[rstest]
225        #[case(3.0, Some(5.0), 5.0)]
226        #[case(5.0, Some(3.0), 5.0)]
227        #[case(3.0, None, 3.0)]
228        fn test_maybe_max(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
229            assert_eq!(lhs.maybe_max(rhs), expected);
230        }
231
232        #[rstest]
233        #[case(3.0, Some(5.0), 8.0)]
234        #[case(5.0, Some(3.0), 8.0)]
235        #[case(3.0, None, 3.0)]
236        fn test_maybe_add(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
237            assert_eq!(lhs.maybe_add(rhs), expected);
238        }
239
240        #[rstest]
241        #[case(3.0, Some(5.0), -2.0)]
242        #[case(5.0, Some(3.0), 2.0)]
243        #[case(3.0, None, 3.0)]
244        fn test_maybe_sub(#[case] lhs: f32, #[case] rhs: Option<f32>, #[case] expected: f32) {
245            assert_eq!(lhs.maybe_sub(rhs), expected);
246        }
247    }
248}