1 | // This file is part of ICU4X. For terms of use, please see the file |
2 | // called LICENSE at the top level of the ICU4X source tree |
3 | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | |
5 | use crate::LengthHint; |
6 | |
7 | impl core::ops::Add<LengthHint> for LengthHint { |
8 | type Output = Self; |
9 | |
10 | fn add(self, other: LengthHint) -> Self { |
11 | LengthHint( |
12 | self.0.saturating_add(other.0), |
13 | match (self.1, other.1) { |
14 | (Some(c: usize), Some(d: usize)) => c.checked_add(d), |
15 | _ => None, |
16 | }, |
17 | ) |
18 | } |
19 | } |
20 | |
21 | impl core::ops::AddAssign<LengthHint> for LengthHint { |
22 | fn add_assign(&mut self, other: Self) { |
23 | *self = *self + other; |
24 | } |
25 | } |
26 | |
27 | impl core::iter::Sum<LengthHint> for LengthHint { |
28 | fn sum<I>(iter: I) -> Self |
29 | where |
30 | I: Iterator<Item = LengthHint>, |
31 | { |
32 | iter.fold(init:LengthHint::exact(0), f:core::ops::Add::add) |
33 | } |
34 | } |
35 | |
36 | impl core::ops::Add<usize> for LengthHint { |
37 | type Output = Self; |
38 | |
39 | fn add(self, other: usize) -> Self { |
40 | Self( |
41 | self.0.saturating_add(other), |
42 | self.1.and_then(|upper: usize| upper.checked_add(other)), |
43 | ) |
44 | } |
45 | } |
46 | |
47 | impl core::ops::AddAssign<usize> for LengthHint { |
48 | fn add_assign(&mut self, other: usize) { |
49 | *self = *self + other; |
50 | } |
51 | } |
52 | |
53 | impl core::ops::Mul<usize> for LengthHint { |
54 | type Output = Self; |
55 | |
56 | fn mul(self, other: usize) -> Self { |
57 | Self( |
58 | self.0.saturating_mul(other), |
59 | self.1.and_then(|upper: usize| upper.checked_mul(other)), |
60 | ) |
61 | } |
62 | } |
63 | |
64 | impl core::ops::MulAssign<usize> for LengthHint { |
65 | fn mul_assign(&mut self, other: usize) { |
66 | *self = *self * other; |
67 | } |
68 | } |
69 | |
70 | impl core::ops::BitOr<LengthHint> for LengthHint { |
71 | type Output = Self; |
72 | |
73 | /// Returns a new hint that is correct wherever `self` is correct, and wherever |
74 | /// `other` is correct. |
75 | /// |
76 | /// Example: |
77 | /// ``` |
78 | /// # use writeable::{LengthHint, Writeable}; |
79 | /// # use core::fmt; |
80 | /// # fn coin_flip() -> bool { true } |
81 | /// |
82 | /// struct NonDeterministicWriteable(String, String); |
83 | /// |
84 | /// impl Writeable for NonDeterministicWriteable { |
85 | /// fn write_to<W: fmt::Write + ?Sized>( |
86 | /// &self, |
87 | /// sink: &mut W, |
88 | /// ) -> fmt::Result { |
89 | /// sink.write_str(if coin_flip() { &self.0 } else { &self.1 }) |
90 | /// } |
91 | /// |
92 | /// fn writeable_length_hint(&self) -> LengthHint { |
93 | /// LengthHint::exact(self.0.len()) | LengthHint::exact(self.1.len()) |
94 | /// } |
95 | /// } |
96 | /// |
97 | /// writeable::impl_display_with_writeable!(NonDeterministicWriteable); |
98 | /// ``` |
99 | fn bitor(self, other: LengthHint) -> Self { |
100 | LengthHint( |
101 | Ord::min(self.0, other.0), |
102 | match (self.1, other.1) { |
103 | (Some(c), Some(d)) => Some(Ord::max(c, d)), |
104 | _ => None, |
105 | }, |
106 | ) |
107 | } |
108 | } |
109 | |
110 | impl core::ops::BitOrAssign<LengthHint> for LengthHint { |
111 | fn bitor_assign(&mut self, other: Self) { |
112 | *self = *self | other; |
113 | } |
114 | } |
115 | |
116 | impl core::iter::Sum<usize> for LengthHint { |
117 | fn sum<I>(iter: I) -> Self |
118 | where |
119 | I: Iterator<Item = usize>, |
120 | { |
121 | LengthHint::exact(iter.sum::<usize>()) |
122 | } |
123 | } |
124 | |
125 | #[cfg (test)] |
126 | mod tests { |
127 | use super::*; |
128 | |
129 | #[test ] |
130 | fn test_add() { |
131 | assert_eq!(LengthHint::exact(3) + 2, LengthHint::exact(5)); |
132 | assert_eq!( |
133 | LengthHint::exact(3) + LengthHint::exact(2), |
134 | LengthHint::exact(5) |
135 | ); |
136 | assert_eq!( |
137 | LengthHint::exact(3) + LengthHint::undefined(), |
138 | LengthHint::at_least(3) |
139 | ); |
140 | |
141 | assert_eq!(LengthHint::undefined() + 2, LengthHint::at_least(2)); |
142 | assert_eq!( |
143 | LengthHint::undefined() + LengthHint::exact(2), |
144 | LengthHint::at_least(2) |
145 | ); |
146 | assert_eq!( |
147 | LengthHint::undefined() + LengthHint::undefined(), |
148 | LengthHint::undefined() |
149 | ); |
150 | |
151 | assert_eq!( |
152 | LengthHint::at_least(15) + LengthHint::exact(3), |
153 | LengthHint::at_least(18) |
154 | ); |
155 | |
156 | assert_eq!( |
157 | LengthHint::at_least(15) + LengthHint::at_most(3), |
158 | LengthHint::at_least(15) |
159 | ); |
160 | |
161 | assert_eq!(LengthHint::between(48, 92) + 5, LengthHint::between(53, 97)); |
162 | |
163 | let mut len = LengthHint::exact(5); |
164 | len += LengthHint::exact(3); |
165 | assert_eq!(len, LengthHint::exact(8)); |
166 | len += 2; |
167 | assert_eq!(len, LengthHint::exact(10)); |
168 | len += LengthHint::undefined(); |
169 | assert_eq!(len, LengthHint::at_least(10)); |
170 | |
171 | len += LengthHint::exact(3); |
172 | assert_eq!(len, LengthHint::at_least(13)); |
173 | len += 2; |
174 | assert_eq!(len, LengthHint::at_least(15)); |
175 | len += LengthHint::undefined(); |
176 | assert_eq!(len, LengthHint::at_least(15)); |
177 | |
178 | assert_eq!( |
179 | LengthHint::between(usize::MAX - 10, usize::MAX - 5) + LengthHint::exact(20), |
180 | LengthHint::at_least(usize::MAX) |
181 | ); |
182 | } |
183 | |
184 | #[test ] |
185 | fn test_sum() { |
186 | let lens = [ |
187 | LengthHint::exact(4), |
188 | LengthHint::exact(1), |
189 | LengthHint::exact(1), |
190 | ]; |
191 | assert_eq!( |
192 | lens.iter().copied().sum::<LengthHint>(), |
193 | LengthHint::exact(6) |
194 | ); |
195 | |
196 | let lens = [ |
197 | LengthHint::exact(4), |
198 | LengthHint::undefined(), |
199 | LengthHint::at_least(1), |
200 | ]; |
201 | assert_eq!( |
202 | lens.iter().copied().sum::<LengthHint>(), |
203 | LengthHint::at_least(5) |
204 | ); |
205 | |
206 | let lens = [ |
207 | LengthHint::exact(4), |
208 | LengthHint::undefined(), |
209 | LengthHint::at_most(1), |
210 | ]; |
211 | assert_eq!( |
212 | lens.iter().copied().sum::<LengthHint>(), |
213 | LengthHint::at_least(4) |
214 | ); |
215 | |
216 | let lens = [4, 1, 1]; |
217 | assert_eq!( |
218 | lens.iter().copied().sum::<LengthHint>(), |
219 | LengthHint::exact(6) |
220 | ); |
221 | } |
222 | |
223 | #[test ] |
224 | fn test_mul() { |
225 | assert_eq!(LengthHint::exact(3) * 2, LengthHint::exact(6)); |
226 | |
227 | assert_eq!(LengthHint::undefined() * 2, LengthHint::undefined()); |
228 | |
229 | assert_eq!( |
230 | LengthHint::between(48, 92) * 2, |
231 | LengthHint::between(96, 184) |
232 | ); |
233 | |
234 | let mut len = LengthHint::exact(5); |
235 | len *= 2; |
236 | assert_eq!(len, LengthHint::exact(10)); |
237 | |
238 | assert_eq!( |
239 | LengthHint::between(usize::MAX - 10, usize::MAX - 5) * 2, |
240 | LengthHint::at_least(usize::MAX) |
241 | ); |
242 | } |
243 | |
244 | #[test ] |
245 | fn test_bitor() { |
246 | assert_eq!( |
247 | LengthHint::exact(3) | LengthHint::exact(2), |
248 | LengthHint::between(2, 3) |
249 | ); |
250 | assert_eq!( |
251 | LengthHint::exact(3) | LengthHint::undefined(), |
252 | LengthHint::undefined() |
253 | ); |
254 | |
255 | assert_eq!( |
256 | LengthHint::undefined() | LengthHint::undefined(), |
257 | LengthHint::undefined() |
258 | ); |
259 | |
260 | assert_eq!( |
261 | LengthHint::exact(10) | LengthHint::exact(10), |
262 | LengthHint::exact(10) |
263 | ); |
264 | |
265 | assert_eq!( |
266 | LengthHint::at_least(15) | LengthHint::exact(3), |
267 | LengthHint::at_least(3) |
268 | ); |
269 | |
270 | assert_eq!( |
271 | LengthHint::at_least(15) | LengthHint::at_most(18), |
272 | LengthHint::undefined() |
273 | ); |
274 | |
275 | assert_eq!( |
276 | LengthHint::at_least(15) | LengthHint::at_least(18), |
277 | LengthHint::at_least(15) |
278 | ); |
279 | |
280 | assert_eq!( |
281 | LengthHint::at_most(15) | LengthHint::at_most(18), |
282 | LengthHint::at_most(18) |
283 | ); |
284 | |
285 | assert_eq!( |
286 | LengthHint::between(5, 10) | LengthHint::at_most(3), |
287 | LengthHint::at_most(10) |
288 | ); |
289 | |
290 | let mut len = LengthHint::exact(5); |
291 | len |= LengthHint::exact(3); |
292 | assert_eq!(len, LengthHint::between(5, 3)); |
293 | } |
294 | } |
295 | |