use crate::num::basic::unsigneds::PrimitiveUnsigned;
use crate::num::conversion::traits::{PowerOf2Digits, WrappingFrom};
use alloc::vec::Vec;
fn to_power_of_2_digits_asc<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<T>>(
x: &T,
log_base: u64,
) -> Vec<U> {
assert_ne!(log_base, 0);
assert!(
log_base <= U::WIDTH,
"type {:?} is too small for a digit of width {}",
U::NAME,
log_base
);
let mut digits = Vec::new();
if *x == T::ZERO {
} else if x.significant_bits() <= log_base {
digits.push(U::wrapping_from(*x));
} else {
let mut x = *x;
let mask = U::low_mask(log_base);
while x != T::ZERO {
digits.push(U::wrapping_from(x) & mask);
x >>= log_base;
}
}
digits
}
fn to_power_of_2_digits_desc<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<T>>(
x: &T,
log_base: u64,
) -> Vec<U> {
let mut digits = to_power_of_2_digits_asc(x, log_base);
digits.reverse();
digits
}
fn from_power_of_2_digits_asc<
T: TryFrom<U> + PrimitiveUnsigned + WrappingFrom<U>,
U: PrimitiveUnsigned,
I: Iterator<Item = U>,
>(
log_base: u64,
digits: I,
) -> Option<T> {
assert_ne!(log_base, 0);
assert!(
log_base <= U::WIDTH,
"type {:?} is too small for a digit of width {}",
U::NAME,
log_base
);
let mut n = T::ZERO;
let mut shift = 0;
for digit in digits {
if digit.significant_bits() > log_base {
return None;
}
n |= T::try_from(digit)
.ok()
.and_then(|d| d.arithmetic_checked_shl(shift))?;
shift += log_base;
}
Some(n)
}
fn from_power_of_2_digits_desc<
T: PrimitiveUnsigned + WrappingFrom<U>,
U: PrimitiveUnsigned,
I: Iterator<Item = U>,
>(
log_base: u64,
digits: I,
) -> Option<T> {
assert_ne!(log_base, 0);
assert!(
log_base <= U::WIDTH,
"type {:?} is too small for a digit of width {}",
U::NAME,
log_base
);
let mut n = T::ZERO;
for digit in digits {
if digit.significant_bits() > log_base {
return None;
}
let shifted = n.arithmetic_checked_shl(log_base)?;
n = shifted | T::wrapping_from(digit);
}
Some(n)
}
macro_rules! impl_power_of_2_digits {
($t:ident) => {
macro_rules! impl_power_of_2_digits_inner {
($u:ident) => {
impl PowerOf2Digits<$u> for $t {
#[inline]
fn to_power_of_2_digits_asc(&self, log_base: u64) -> Vec<$u> {
to_power_of_2_digits_asc(self, log_base)
}
#[inline]
fn to_power_of_2_digits_desc(&self, log_base: u64) -> Vec<$u> {
to_power_of_2_digits_desc(self, log_base)
}
#[inline]
fn from_power_of_2_digits_asc<I: Iterator<Item = $u>>(
log_base: u64,
digits: I,
) -> Option<$t> {
from_power_of_2_digits_asc(log_base, digits)
}
fn from_power_of_2_digits_desc<I: Iterator<Item = $u>>(
log_base: u64,
digits: I,
) -> Option<$t> {
from_power_of_2_digits_desc(log_base, digits)
}
}
};
}
apply_to_unsigneds!(impl_power_of_2_digits_inner);
};
}
apply_to_unsigneds!(impl_power_of_2_digits);