blob: a4c1ffd759781d3257101a28f684989835757461 [file] [log] [blame]
// 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 = [
LengthHint::exact(4),
LengthHint::exact(1),
LengthHint::exact(1),
];
assert_eq!(
lens.iter().copied().sum::<LengthHint>(),
LengthHint::exact(6)
);
let lens = [
LengthHint::exact(4),
LengthHint::undefined(),
LengthHint::at_least(1),
];
assert_eq!(
lens.iter().copied().sum::<LengthHint>(),
LengthHint::at_least(5)
);
let lens = [
LengthHint::exact(4),
LengthHint::undefined(),
LengthHint::at_most(1),
];
assert_eq!(
lens.iter().copied().sum::<LengthHint>(),
LengthHint::at_least(4)
);
let lens = [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));
}
}