diff options
Diffstat (limited to 'vendor/writeable/src/ops.rs')
-rw-r--r-- | vendor/writeable/src/ops.rs | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/vendor/writeable/src/ops.rs b/vendor/writeable/src/ops.rs new file mode 100644 index 000000000..3ed4406d7 --- /dev/null +++ b/vendor/writeable/src/ops.rs @@ -0,0 +1,291 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::LengthHint; + +impl core::ops::Add<LengthHint> for LengthHint { + type Output = Self; + + fn add(self, other: LengthHint) -> Self { + LengthHint( + self.0.saturating_add(other.0), + match (self.1, other.1) { + (Some(c), Some(d)) => c.checked_add(d), + _ => None, + }, + ) + } +} + +impl core::ops::AddAssign<LengthHint> for LengthHint { + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl core::iter::Sum<LengthHint> for LengthHint { + fn sum<I>(iter: I) -> Self + where + I: Iterator<Item = LengthHint>, + { + iter.fold(LengthHint::exact(0), core::ops::Add::add) + } +} + +impl core::ops::Add<usize> for LengthHint { + type Output = Self; + + fn add(self, other: usize) -> Self { + Self( + self.0.saturating_add(other), + self.1.and_then(|upper| upper.checked_add(other)), + ) + } +} + +impl core::ops::AddAssign<usize> for LengthHint { + fn add_assign(&mut self, other: usize) { + *self = *self + other; + } +} + +impl core::ops::Mul<usize> for LengthHint { + type Output = Self; + + fn mul(self, other: usize) -> Self { + Self( + self.0.saturating_mul(other), + self.1.and_then(|upper| upper.checked_mul(other)), + ) + } +} + +impl core::ops::MulAssign<usize> for LengthHint { + fn mul_assign(&mut self, other: usize) { + *self = *self * other; + } +} + +impl core::ops::BitOr<LengthHint> for LengthHint { + type Output = Self; + + /// Returns a new hint that is correct wherever `self` is correct, and wherever + /// `other` is correct. + /// + /// Example: + /// ``` + /// # use writeable::{LengthHint, Writeable}; + /// # use core::fmt; + /// # fn coin_flip() -> bool { true } + /// + /// struct NonDeterministicWriteable(String, String); + /// + /// impl Writeable for NonDeterministicWriteable { + /// fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result { + /// sink.write_str(if coin_flip() { &self.0 } else { &self.1 }) + /// } + /// + /// fn writeable_length_hint(&self) -> LengthHint { + /// LengthHint::exact(self.0.len()) | LengthHint::exact(self.1.len()) + /// } + /// } + /// + /// writeable::impl_display_with_writeable!(NonDeterministicWriteable); + /// ``` + fn bitor(self, other: LengthHint) -> Self { + LengthHint( + Ord::min(self.0, other.0), + match (self.1, other.1) { + (Some(c), Some(d)) => Some(Ord::max(c, d)), + _ => None, + }, + ) + } +} + +impl core::ops::BitOrAssign<LengthHint> for LengthHint { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl core::iter::Sum<usize> for LengthHint { + fn sum<I>(iter: I) -> Self + where + I: Iterator<Item = usize>, + { + LengthHint::exact(iter.sum::<usize>()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_add() { + assert_eq!(LengthHint::exact(3) + 2, LengthHint::exact(5)); + assert_eq!( + LengthHint::exact(3) + LengthHint::exact(2), + LengthHint::exact(5) + ); + assert_eq!( + LengthHint::exact(3) + LengthHint::undefined(), + LengthHint::at_least(3) + ); + + assert_eq!(LengthHint::undefined() + 2, LengthHint::at_least(2)); + assert_eq!( + LengthHint::undefined() + LengthHint::exact(2), + LengthHint::at_least(2) + ); + assert_eq!( + LengthHint::undefined() + LengthHint::undefined(), + LengthHint::undefined() + ); + + assert_eq!( + LengthHint::at_least(15) + LengthHint::exact(3), + LengthHint::at_least(18) + ); + + assert_eq!( + LengthHint::at_least(15) + LengthHint::at_most(3), + LengthHint::at_least(15) + ); + + assert_eq!(LengthHint::between(48, 92) + 5, LengthHint::between(53, 97)); + + let mut len = LengthHint::exact(5); + len += LengthHint::exact(3); + assert_eq!(len, LengthHint::exact(8)); + len += 2; + assert_eq!(len, LengthHint::exact(10)); + len += LengthHint::undefined(); + assert_eq!(len, LengthHint::at_least(10)); + + len += LengthHint::exact(3); + assert_eq!(len, LengthHint::at_least(13)); + len += 2; + assert_eq!(len, LengthHint::at_least(15)); + len += LengthHint::undefined(); + assert_eq!(len, LengthHint::at_least(15)); + + assert_eq!( + LengthHint::between(usize::MAX - 10, usize::MAX - 5) + LengthHint::exact(20), + LengthHint::at_least(usize::MAX) + ); + } + + #[test] + fn test_sum() { + let lens = vec![ + LengthHint::exact(4), + LengthHint::exact(1), + LengthHint::exact(1), + ]; + assert_eq!( + lens.iter().copied().sum::<LengthHint>(), + LengthHint::exact(6) + ); + + let lens = vec![ + LengthHint::exact(4), + LengthHint::undefined(), + LengthHint::at_least(1), + ]; + assert_eq!( + lens.iter().copied().sum::<LengthHint>(), + LengthHint::at_least(5) + ); + + let lens = vec![ + LengthHint::exact(4), + LengthHint::undefined(), + LengthHint::at_most(1), + ]; + assert_eq!( + lens.iter().copied().sum::<LengthHint>(), + LengthHint::at_least(4) + ); + + let lens = vec![4, 1, 1]; + assert_eq!( + lens.iter().copied().sum::<LengthHint>(), + LengthHint::exact(6) + ); + } + + #[test] + fn test_mul() { + assert_eq!(LengthHint::exact(3) * 2, LengthHint::exact(6)); + + assert_eq!(LengthHint::undefined() * 2, LengthHint::undefined()); + + assert_eq!( + LengthHint::between(48, 92) * 2, + LengthHint::between(96, 184) + ); + + let mut len = LengthHint::exact(5); + len *= 2; + assert_eq!(len, LengthHint::exact(10)); + + assert_eq!( + LengthHint::between(usize::MAX - 10, usize::MAX - 5) * 2, + LengthHint::at_least(usize::MAX) + ); + } + + #[test] + fn test_bitor() { + assert_eq!( + LengthHint::exact(3) | LengthHint::exact(2), + LengthHint::between(2, 3) + ); + assert_eq!( + LengthHint::exact(3) | LengthHint::undefined(), + LengthHint::undefined() + ); + + assert_eq!( + LengthHint::undefined() | LengthHint::undefined(), + LengthHint::undefined() + ); + + assert_eq!( + LengthHint::exact(10) | LengthHint::exact(10), + LengthHint::exact(10) + ); + + assert_eq!( + LengthHint::at_least(15) | LengthHint::exact(3), + LengthHint::at_least(3) + ); + + assert_eq!( + LengthHint::at_least(15) | LengthHint::at_most(18), + LengthHint::undefined() + ); + + assert_eq!( + LengthHint::at_least(15) | LengthHint::at_least(18), + LengthHint::at_least(15) + ); + + assert_eq!( + LengthHint::at_most(15) | LengthHint::at_most(18), + LengthHint::at_most(18) + ); + + assert_eq!( + LengthHint::between(5, 10) | LengthHint::at_most(3), + LengthHint::at_most(10) + ); + + let mut len = LengthHint::exact(5); + len |= LengthHint::exact(3); + assert_eq!(len, LengthHint::between(5, 3)); + } +} |