use super::{FixedUInt, MachineWord, const_div, const_is_zero};
use crate::machineword::ConstMachineWord;
use const_num_traits::Nct;
use const_num_traits::{CheckedAdd, DivCeil, One};
c0nst::c0nst! {
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> DivCeil for FixedUInt<T, N, Nct> {
type Output = FixedUInt<T, N, Nct>;
fn div_ceil(self, rhs: Self) -> Self {
match checked_div_ceil_impl(self, rhs) {
Some(v) => v,
None => panic!("div_ceil: division by zero or overflow"),
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> DivCeil for &FixedUInt<T, N, Nct> {
type Output = FixedUInt<T, N, Nct>;
fn div_ceil(self, rhs: Self) -> FixedUInt<T, N, Nct> {
<FixedUInt<T, N, Nct> as DivCeil>::div_ceil(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array))
}
}
}
c0nst::c0nst! {
pub(crate) c0nst fn checked_div_ceil_impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
a: FixedUInt<T, N, Nct>, rhs: FixedUInt<T, N, Nct>,
) -> Option<FixedUInt<T, N, Nct>> {
if const_is_zero(&rhs.array) {
return None;
}
let mut quotient = a.array;
let remainder = const_div(&mut quotient, &rhs.array);
if const_is_zero(&remainder) {
Some(FixedUInt::from_array(quotient))
} else {
<FixedUInt<T, N, Nct> as CheckedAdd>::checked_add(
FixedUInt::from_array(quotient),
<FixedUInt<T, N, Nct> as One>::one(),
)
}
}
}
impl<T: ConstMachineWord + MachineWord, const N: usize> FixedUInt<T, N, Nct> {
pub fn checked_div_ceil(self, rhs: Self) -> Option<Self> {
checked_div_ceil_impl(self, rhs)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_div_ceil() {
type U16 = FixedUInt<u8, 2>;
assert_eq!(
DivCeil::div_ceil(U16::from(10u8), U16::from(5u8)),
U16::from(2u8)
);
assert_eq!(
DivCeil::div_ceil(U16::from(10u8), U16::from(2u8)),
U16::from(5u8)
);
assert_eq!(
DivCeil::div_ceil(U16::from(10u8), U16::from(3u8)),
U16::from(4u8)
); assert_eq!(
DivCeil::div_ceil(U16::from(11u8), U16::from(3u8)),
U16::from(4u8)
); assert_eq!(
DivCeil::div_ceil(U16::from(12u8), U16::from(3u8)),
U16::from(4u8)
);
assert_eq!(
DivCeil::div_ceil(U16::from(0u8), U16::from(5u8)),
U16::from(0u8)
);
assert_eq!(
DivCeil::div_ceil(U16::from(1u8), U16::from(5u8)),
U16::from(1u8)
); assert_eq!(
DivCeil::div_ceil(U16::from(1u8), U16::from(1u8)),
U16::from(1u8)
);
}
#[test]
fn test_checked_div_ceil() {
type U16 = FixedUInt<u8, 2>;
assert_eq!(
FixedUInt::checked_div_ceil(U16::from(10u8), U16::from(3u8)),
Some(U16::from(4u8))
);
assert_eq!(
FixedUInt::checked_div_ceil(U16::from(10u8), U16::from(0u8)),
None
);
assert_eq!(
FixedUInt::checked_div_ceil(U16::from(65535u16), U16::from(2u16)),
Some(U16::from(32768u16))
);
assert_eq!(
FixedUInt::checked_div_ceil(U16::from(65535u16), U16::from(1u16)),
Some(U16::from(65535u16))
);
}
c0nst::c0nst! {
pub c0nst fn const_div_ceil<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
a: FixedUInt<T, N, Nct>,
b: FixedUInt<T, N, Nct>,
) -> FixedUInt<T, N, Nct> {
DivCeil::div_ceil(a, b)
}
pub c0nst fn const_checked_div_ceil<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
a: FixedUInt<T, N, Nct>,
b: FixedUInt<T, N, Nct>,
) -> Option<FixedUInt<T, N, Nct>> {
super::checked_div_ceil_impl(a, b)
}
}
#[test]
fn test_const_div_ceil() {
type U16 = FixedUInt<u8, 2>;
assert_eq!(
const_div_ceil(U16::from(10u8), U16::from(3u8)),
U16::from(4u8)
);
assert_eq!(
const_checked_div_ceil(U16::from(10u8), U16::from(3u8)),
Some(U16::from(4u8))
);
assert_eq!(
const_checked_div_ceil(U16::from(10u8), U16::from(0u8)),
None
);
#[cfg(feature = "nightly")]
{
const TEN: U16 = FixedUInt::from_array([10, 0]);
const THREE: U16 = FixedUInt::from_array([3, 0]);
const ZERO: U16 = FixedUInt::from_array([0, 0]);
const RESULT: U16 = const_div_ceil(TEN, THREE);
const CHECKED_OK: Option<U16> = const_checked_div_ceil(TEN, THREE);
const CHECKED_ZERO: Option<U16> = const_checked_div_ceil(TEN, ZERO);
assert_eq!(RESULT, FixedUInt::from_array([4, 0]));
assert!(CHECKED_OK.is_some());
assert!(CHECKED_ZERO.is_none());
}
}
}