use super::{FixedUInt, MachineWord};
use crate::machineword::ConstMachineWord;
use const_num_traits::Nct;
use const_num_traits::{CheckedMul, CheckedPow, One};
c0nst::c0nst! {
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> CheckedPow for FixedUInt<T, N, Nct> {
fn checked_pow(self, exp: u32) -> Option<Self> {
if exp == 0 {
return Some(Self::one());
}
let mut result = Self::one();
let mut base = self;
let mut e = exp;
while e > 0 {
if (e & 1) == 1 {
result = match CheckedMul::checked_mul(result, base) {
Some(v) => v,
None => return None,
};
}
e >>= 1;
if e > 0 {
base = match CheckedMul::checked_mul(base, base) {
Some(v) => v,
None => return None,
};
}
}
Some(result)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> CheckedPow for &FixedUInt<T, N, Nct> {
fn checked_pow(self, exp: u32) -> Option<FixedUInt<T, N, Nct>> {
<FixedUInt<T, N, Nct> as CheckedPow>::checked_pow(*self, exp)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_checked_pow() {
type U16 = FixedUInt<u8, 2>;
assert_eq!(
CheckedPow::checked_pow(U16::from(2u8), 0),
Some(U16::from(1u8))
);
assert_eq!(
CheckedPow::checked_pow(U16::from(2u8), 1),
Some(U16::from(2u8))
);
assert_eq!(
CheckedPow::checked_pow(U16::from(2u8), 2),
Some(U16::from(4u8))
);
assert_eq!(
CheckedPow::checked_pow(U16::from(2u8), 8),
Some(U16::from(256u16))
);
assert_eq!(
CheckedPow::checked_pow(U16::from(3u8), 3),
Some(U16::from(27u8))
);
assert_eq!(
CheckedPow::checked_pow(U16::from(0u8), 0),
Some(U16::from(1u8))
);
assert_eq!(
CheckedPow::checked_pow(U16::from(0u8), 5),
Some(U16::from(0u8))
);
assert_eq!(
CheckedPow::checked_pow(U16::from(1u8), 100),
Some(U16::from(1u8))
);
assert_eq!(CheckedPow::checked_pow(U16::from(2u8), 16), None); assert_eq!(CheckedPow::checked_pow(U16::from(256u16), 2), None);
assert_eq!(
CheckedPow::checked_pow(U16::from(2u8), 15),
Some(U16::from(32768u16))
);
}
c0nst::c0nst! {
pub c0nst fn const_checked_pow<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
base: FixedUInt<T, N, Nct>,
exp: u32,
) -> Option<FixedUInt<T, N, Nct>> {
CheckedPow::checked_pow(base, exp)
}
}
#[test]
fn test_const_checked_pow() {
type U16 = FixedUInt<u8, 2>;
assert_eq!(
const_checked_pow(U16::from(2u8), 8),
Some(U16::from(256u16))
);
#[cfg(feature = "nightly")]
{
const BASE: U16 = FixedUInt::from_array([2, 0]);
const POW_RESULT: Option<U16> = const_checked_pow(BASE, 8);
assert_eq!(POW_RESULT, Some(FixedUInt::from_array([0, 1]))); }
}
}