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
5use crate::LengthHint;
6
7impl 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
21impl core::ops::AddAssign<LengthHint> for LengthHint {
22 fn add_assign(&mut self, other: Self) {
23 *self = *self + other;
24 }
25}
26
27impl 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
36impl 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
47impl core::ops::AddAssign<usize> for LengthHint {
48 fn add_assign(&mut self, other: usize) {
49 *self = *self + other;
50 }
51}
52
53impl 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
64impl core::ops::MulAssign<usize> for LengthHint {
65 fn mul_assign(&mut self, other: usize) {
66 *self = *self * other;
67 }
68}
69
70impl 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
110impl core::ops::BitOrAssign<LengthHint> for LengthHint {
111 fn bitor_assign(&mut self, other: Self) {
112 *self = *self | other;
113 }
114}
115
116impl 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)]
126mod 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