use super::HeaplessBigInt;
use crate::MachineWord;
use const_num_traits::{
DepositBits, ExtractBits, IsolateLowestOne, Nct, One, WrappingShl, WrappingSub, Zero,
};
impl<T, const CAP: usize> DepositBits for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord,
{
type Output = Self;
fn deposit_bits(self, mask: Self) -> Self {
let width = core::cmp::max(self.len(), mask.len());
let mut result = Self::new_zero_with_len(width);
if <Self as Zero>::is_zero(&mask) {
return result;
}
let one = <Self as One>::one();
let mut remaining = mask;
let mut bb = one.widened(width);
while !<Self as Zero>::is_zero(&remaining) {
let lowest = IsolateLowestOne::isolate_lowest_one(remaining);
if !<Self as Zero>::is_zero(&(self & bb)) {
result |= lowest;
}
remaining &= WrappingSub::wrapping_sub(remaining, one);
bb = WrappingShl::wrapping_shl(bb, 1);
}
result
}
}
impl<T, const CAP: usize> ExtractBits for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord,
{
type Output = Self;
fn extract_bits(self, mask: Self) -> Self {
let width = core::cmp::max(self.len(), mask.len());
let mut result = Self::new_zero_with_len(width);
if <Self as Zero>::is_zero(&mask) {
return result;
}
let one = <Self as One>::one();
let mut remaining = mask;
let mut bb = one.widened(width);
while !<Self as Zero>::is_zero(&remaining) {
let lowest = IsolateLowestOne::isolate_lowest_one(remaining);
if !<Self as Zero>::is_zero(&(self & lowest)) {
result |= bb;
}
remaining &= WrappingSub::wrapping_sub(remaining, one);
bb = WrappingShl::wrapping_shl(bb, 1);
}
result
}
}
impl<T, const CAP: usize> DepositBits for &HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord,
{
type Output = HeaplessBigInt<T, CAP, Nct>;
fn deposit_bits(self, mask: Self) -> HeaplessBigInt<T, CAP, Nct> {
<HeaplessBigInt<T, CAP, Nct> as DepositBits>::deposit_bits(*self, *mask)
}
}
impl<T, const CAP: usize> ExtractBits for &HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord,
{
type Output = HeaplessBigInt<T, CAP, Nct>;
fn extract_bits(self, mask: Self) -> HeaplessBigInt<T, CAP, Nct> {
<HeaplessBigInt<T, CAP, Nct> as ExtractBits>::extract_bits(*self, *mask)
}
}
#[cfg(test)]
mod tests {
use super::HeaplessBigInt;
use const_num_traits::{DepositBits, ExtractBits};
type H = HeaplessBigInt<u8, 4>;
#[test]
fn deposit_extract_roundtrip() {
let mask = H::from(0b0101_0101u8).widened(4);
let src = H::from(0b1011u8).widened(4);
let dep = DepositBits::deposit_bits(src, mask);
assert_eq!(dep, H::from(0b0100_0101u8));
assert_eq!(dep.len(), 4);
let ext = ExtractBits::extract_bits(dep, mask);
assert_eq!(ext, H::from(0b1011u8));
assert_eq!(ext.len(), 4);
}
#[test]
fn deposit_full_mask_is_identity() {
let mask = H::from(0xFFFF_FFFFu32);
let v = H::from(0x1234_5678u32);
assert_eq!(DepositBits::deposit_bits(v, mask), v);
assert_eq!(ExtractBits::extract_bits(v, mask), v);
}
#[test]
fn zero_mask_returns_zero_without_panic() {
let src = H::from(0x1234_5678u32);
let zero_mask = H::new_zero_with_len(4);
assert_eq!(DepositBits::deposit_bits(src, zero_mask), H::from(0u8));
assert_eq!(ExtractBits::extract_bits(src, zero_mask), H::from(0u8));
let z0 = H::new_zero_with_len(0);
assert_eq!(DepositBits::deposit_bits(z0, z0).len(), 0);
assert_eq!(ExtractBits::extract_bits(z0, z0).len(), 0);
}
#[test]
fn by_ref_matches_value() {
let mask = H::from(0b0101_0101u8).widened(4);
let src = H::from(0b1011u8).widened(4);
assert_eq!(
DepositBits::deposit_bits(&src, &mask),
DepositBits::deposit_bits(src, mask)
);
assert_eq!(
ExtractBits::extract_bits(&src, &mask),
ExtractBits::extract_bits(src, mask)
);
}
}