writeable/
ops.rs

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), Some(d)) => 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(LengthHint::exact(0), 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| 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| 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}