use num_traits::{One, Zero};
pub trait CheckedCeilDiv: Sized {
fn checked_ceil_div(&self, rhs: Self) -> Option<Self>;
}
macro_rules! checked_impl {
($t:ty) => {
impl CheckedCeilDiv for $t {
#[track_caller]
#[inline]
fn checked_ceil_div(&self, rhs: $t) -> Option<$t> {
let quotient = self.checked_div(rhs)?;
let remainder = self.checked_rem(rhs)?;
if remainder != <$t>::zero() && (remainder > <$t>::zero()) == (rhs > <$t>::zero()) {
quotient.checked_add(<$t>::one())
} else {
Some(quotient)
}
}
}
};
}
checked_impl!(u128);
checked_impl!(u64);
checked_impl!(u32);
checked_impl!(u16);
checked_impl!(u8);
checked_impl!(i128);
checked_impl!(i64);
checked_impl!(i32);
checked_impl!(i16);
checked_impl!(i8);
#[cfg(test)]
mod test {
use crate::math::ceil_div::CheckedCeilDiv;
#[test]
fn test_positive_dividend_positive_divisor() {
assert_eq!(4_i128.checked_ceil_div(2), Some(2));
assert_eq!(6_i128.checked_ceil_div(3), Some(2));
assert_eq!(5_i128.checked_ceil_div(2), Some(3)); assert_eq!(7_i128.checked_ceil_div(3), Some(3)); assert_eq!(1_i128.checked_ceil_div(2), Some(1)); }
#[test]
fn test_negative_dividend_positive_divisor() {
assert_eq!((-4_i128).checked_ceil_div(2), Some(-2));
assert_eq!((-6_i128).checked_ceil_div(3), Some(-2));
assert_eq!((-5_i128).checked_ceil_div(2), Some(-2)); assert_eq!((-7_i128).checked_ceil_div(3), Some(-2)); assert_eq!((-1_i128).checked_ceil_div(2), Some(0)); }
#[test]
fn test_positive_dividend_negative_divisor() {
assert_eq!(4_i128.checked_ceil_div(-2), Some(-2));
assert_eq!(6_i128.checked_ceil_div(-3), Some(-2));
assert_eq!(5_i128.checked_ceil_div(-2), Some(-2)); assert_eq!(7_i128.checked_ceil_div(-3), Some(-2)); assert_eq!(1_i128.checked_ceil_div(-2), Some(0)); }
#[test]
fn test_negative_dividend_negative_divisor() {
assert_eq!((-4_i128).checked_ceil_div(-2), Some(2));
assert_eq!((-6_i128).checked_ceil_div(-3), Some(2));
assert_eq!((-5_i128).checked_ceil_div(-2), Some(3)); assert_eq!((-7_i128).checked_ceil_div(-3), Some(3)); assert_eq!((-1_i128).checked_ceil_div(-2), Some(1)); }
#[test]
fn test_unsigned_types() {
assert_eq!(5_u32.checked_ceil_div(2), Some(3)); assert_eq!(4_u32.checked_ceil_div(2), Some(2)); assert_eq!(1_u32.checked_ceil_div(2), Some(1)); }
}