use super::{FixedUInt, MachineWord, const_shl_ct, const_shl_impl, const_shr_ct, const_shr_impl};
use crate::machineword::ConstMachineWord;
use const_num_traits::{
CheckedShl, CheckedShr, ConstZero, OverflowingShl, OverflowingShr, UnboundedShl, UnboundedShr,
WrappingShl, WrappingShr,
};
use const_num_traits::{Nct, Personality, PersonalityTag};
c0nst::c0nst! {
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Not for FixedUInt<T, N, P> {
type Output = Self;
fn not(self) -> Self::Output {
let mut ret = <Self as ConstZero>::ZERO;
let mut i = 0;
while i < N {
ret.array[i] = !self.array[i];
i += 1;
}
ret
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
let mut i = 0;
while i < N {
ret.array[i] = self.array[i] & other.array[i];
i += 1;
}
ret
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd for FixedUInt<T, N, P> {
type Output = Self;
fn bitand(self, other: Self) -> Self::Output {
(&self).bitand(&other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
type Output = Self;
fn bitand(self, other: &FixedUInt<T, N, P>) -> Self::Output {
(&self).bitand(other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAnd<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn bitand(self, other: FixedUInt<T, N, P>) -> Self::Output {
self.bitand(&other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitAndAssign for FixedUInt<T, N, P> {
fn bitand_assign(&mut self, other: Self) {
let mut i = 0;
while i < N {
self.array[i] &= other.array[i];
i += 1;
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
let mut i = 0;
while i < N {
ret.array[i] = self.array[i] | other.array[i];
i += 1;
}
ret
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr for FixedUInt<T, N, P> {
type Output = Self;
fn bitor(self, other: Self) -> Self::Output {
(&self).bitor(&other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
type Output = Self;
fn bitor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
(&self).bitor(other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOr<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn bitor(self, other: FixedUInt<T, N, P>) -> Self::Output {
self.bitor(&other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitOrAssign for FixedUInt<T, N, P> {
fn bitor_assign(&mut self, other: Self) {
let mut i = 0;
while i < N {
self.array[i] |= other.array[i];
i += 1;
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
let mut ret = <FixedUInt<T, N, P> as ConstZero>::ZERO;
let mut i = 0;
while i < N {
ret.array[i] = self.array[i] ^ other.array[i];
i += 1;
}
ret
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor for FixedUInt<T, N, P> {
type Output = Self;
fn bitxor(self, other: Self) -> Self::Output {
(&self).bitxor(&other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<&FixedUInt<T, N, P>> for FixedUInt<T, N, P> {
type Output = Self;
fn bitxor(self, other: &FixedUInt<T, N, P>) -> Self::Output {
(&self).bitxor(other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXor<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn bitxor(self, other: FixedUInt<T, N, P>) -> Self::Output {
self.bitxor(&other)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::BitXorAssign for FixedUInt<T, N, P> {
fn bitxor_assign(&mut self, other: Self) {
let mut i = 0;
while i < N {
self.array[i] ^= other.array[i];
i += 1;
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<usize> for FixedUInt<T, N, P> {
type Output = Self;
fn shl(self, bits: usize) -> Self::Output {
let mut result = self;
match P::TAG {
PersonalityTag::Nct => const_shl_impl(&mut result, bits),
PersonalityTag::Ct => const_shl_ct(&mut result, bits),
}
result
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<usize> for FixedUInt<T, N, P> {
type Output = Self;
fn shr(self, bits: usize) -> Self::Output {
let mut result = self;
match P::TAG {
PersonalityTag::Nct => const_shr_impl(&mut result, bits),
PersonalityTag::Ct => const_shr_ct(&mut result, bits),
}
result
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<u32> for FixedUInt<T, N, P> {
type Output = Self;
fn shl(self, bits: u32) -> Self::Output {
const_unbounded_shl_u32(self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<u32> for FixedUInt<T, N, P> {
type Output = Self;
fn shr(self, bits: u32) -> Self::Output {
const_unbounded_shr_u32(self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for FixedUInt<T, N, P> {
type Output = Self;
fn shl(self, bits: &usize) -> Self::Output {
self.shl(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for FixedUInt<T, N, P> {
type Output = Self;
fn shr(self, bits: &usize) -> Self::Output {
self.shr(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for FixedUInt<T, N, P> {
type Output = Self;
fn shl(self, bits: &u32) -> Self::Output {
self.shl(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for FixedUInt<T, N, P> {
type Output = Self;
fn shr(self, bits: &u32) -> Self::Output {
self.shr(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<usize> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shl(self, bits: usize) -> Self::Output {
(*self).shl(bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<usize> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shr(self, bits: usize) -> Self::Output {
(*self).shr(bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<u32> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shl(self, bits: u32) -> Self::Output {
(*self).shl(bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<u32> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shr(self, bits: u32) -> Self::Output {
(*self).shr(bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&usize> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shl(self, bits: &usize) -> Self::Output {
(*self).shl(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&usize> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shr(self, bits: &usize) -> Self::Output {
(*self).shr(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shl<&u32> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shl(self, bits: &u32) -> Self::Output {
(*self).shl(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Shr<&u32> for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn shr(self, bits: &u32) -> Self::Output {
(*self).shr(*bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<usize> for FixedUInt<T, N, P> {
fn shl_assign(&mut self, bits: usize) {
match P::TAG {
PersonalityTag::Nct => const_shl_impl(self, bits),
PersonalityTag::Ct => const_shl_ct(self, bits),
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<usize> for FixedUInt<T, N, P> {
fn shr_assign(&mut self, bits: usize) {
match P::TAG {
PersonalityTag::Nct => const_shr_impl(self, bits),
PersonalityTag::Ct => const_shr_ct(self, bits),
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShlAssign<&usize> for FixedUInt<T, N, P> {
fn shl_assign(&mut self, bits: &usize) {
match P::TAG {
PersonalityTag::Nct => const_shl_impl(self, *bits),
PersonalityTag::Ct => const_shl_ct(self, *bits),
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::ShrAssign<&usize> for FixedUInt<T, N, P> {
fn shr_assign(&mut self, bits: &usize) {
match P::TAG {
PersonalityTag::Nct => const_shr_impl(self, *bits),
PersonalityTag::Ct => const_shr_ct(self, *bits),
}
}
}
pub(crate) c0nst fn const_unbounded_shl_u32<
T: [c0nst] ConstMachineWord + MachineWord,
const N: usize,
P: Personality,
>(
target: FixedUInt<T, N, P>,
bits: u32,
) -> FixedUInt<T, N, P> {
match P::TAG {
PersonalityTag::Nct => {
let (shift, overflow) =
normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
if overflow {
<FixedUInt<T, N, P> as ConstZero>::ZERO
} else {
target << shift
}
}
PersonalityTag::Ct => {
let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
let capped = const_ct_min_u32(bits, bit_size_u32);
target << (capped as usize)
}
}
}
pub(crate) c0nst fn const_unbounded_shr_u32<
T: [c0nst] ConstMachineWord + MachineWord,
const N: usize,
P: Personality,
>(
target: FixedUInt<T, N, P>,
bits: u32,
) -> FixedUInt<T, N, P> {
match P::TAG {
PersonalityTag::Nct => {
let (shift, overflow) =
normalize_shift_amount(bits, FixedUInt::<T, N, P>::BIT_SIZE);
if overflow {
<FixedUInt<T, N, P> as ConstZero>::ZERO
} else {
target >> shift
}
}
PersonalityTag::Ct => {
let bit_size_u32 = FixedUInt::<T, N, P>::BIT_SIZE as u32;
let capped = const_ct_min_u32(bits, bit_size_u32);
target >> (capped as usize)
}
}
}
c0nst fn const_ct_min_u32(bits: u32, cap: u32) -> u32 {
let diff = cap.wrapping_sub(bits);
let too_big_bit = (diff >> 31) & 1;
let too_big_mask = core::hint::black_box(too_big_bit.wrapping_neg());
bits ^ (too_big_mask & (bits ^ cap))
}
c0nst fn normalize_shift_amount(bits: u32, bit_size: usize) -> (usize, bool) {
let bit_size_u32 = bit_size as u32;
if bit_size == 0 {
(0, true)
} else if bit_size_u32 == 0 {
(bits as usize, false)
} else if bits >= bit_size_u32 {
((bits % bit_size_u32) as usize, true)
} else {
(bits as usize, false)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShl for FixedUInt<T, N, P> {
fn overflowing_shl(self, bits: u32) -> (Self, bool) {
let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
let res = core::ops::Shl::<usize>::shl(self, shift);
(res, overflow)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for FixedUInt<T, N, P> {
fn overflowing_shr(self, bits: u32) -> (Self, bool) {
let (shift, overflow) = normalize_shift_amount(bits, Self::BIT_SIZE);
let res = core::ops::Shr::<usize>::shr(self, shift);
(res, overflow)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for FixedUInt<T, N, P> {
fn wrapping_shl(self, bits: u32) -> Self {
OverflowingShl::overflowing_shl(self, bits).0
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for FixedUInt<T, N, P> {
fn wrapping_shr(self, bits: u32) -> Self {
OverflowingShr::overflowing_shr(self, bits).0
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for FixedUInt<T, N, P> {
fn checked_shl(self, bits: u32) -> Option<Self> {
let (res, overflow) = OverflowingShl::overflowing_shl(self, bits);
if overflow { None } else { Some(res) }
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShr for FixedUInt<T, N, P> {
fn checked_shr(self, bits: u32) -> Option<Self> {
let (res, overflow) = OverflowingShr::overflowing_shr(self, bits);
if overflow { None } else { Some(res) }
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for FixedUInt<T, N, P> {
fn unbounded_shl(self, rhs: u32) -> Self {
const_unbounded_shl_u32(self, rhs)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for FixedUInt<T, N, P> {
fn unbounded_shr(self, rhs: u32) -> Self {
const_unbounded_shr_u32(self, rhs)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShl for &FixedUInt<T, N, P> {
fn overflowing_shl(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
<FixedUInt<T, N, P> as OverflowingShl>::overflowing_shl(*self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingShr for &FixedUInt<T, N, P> {
fn overflowing_shr(self, bits: u32) -> (FixedUInt<T, N, P>, bool) {
<FixedUInt<T, N, P> as OverflowingShr>::overflowing_shr(*self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShl for &FixedUInt<T, N, P> {
fn wrapping_shl(self, bits: u32) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as WrappingShl>::wrapping_shl(*self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingShr for &FixedUInt<T, N, P> {
fn wrapping_shr(self, bits: u32) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as WrappingShr>::wrapping_shr(*self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShl for &FixedUInt<T, N, P> {
fn checked_shl(self, bits: u32) -> Option<FixedUInt<T, N, P>> {
<FixedUInt<T, N, P> as CheckedShl>::checked_shl(*self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedShr for &FixedUInt<T, N, P> {
fn checked_shr(self, bits: u32) -> Option<FixedUInt<T, N, P>> {
<FixedUInt<T, N, P> as CheckedShr>::checked_shr(*self, bits)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShl for &FixedUInt<T, N, P> {
fn unbounded_shl(self, rhs: u32) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as UnboundedShl>::unbounded_shl(*self, rhs)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> UnboundedShr for &FixedUInt<T, N, P> {
fn unbounded_shr(self, rhs: u32) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as UnboundedShr>::unbounded_shr(*self, rhs)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for FixedUInt<T, N, P> {
fn highest_one(self) -> Option<u32> {
let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
if lz as usize == Self::BIT_SIZE {
None
} else {
Some(Self::BIT_SIZE as u32 - 1 - lz)
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for FixedUInt<T, N, P> {
fn lowest_one(self) -> Option<u32> {
let tz = <Self as const_num_traits::PrimBits>::trailing_zeros(self);
if tz as usize == Self::BIT_SIZE {
None
} else {
Some(tz)
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::HighestOne for &FixedUInt<T, N, P> {
fn highest_one(self) -> Option<u32> {
<FixedUInt<T, N, P> as const_num_traits::HighestOne>::highest_one(*self)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::LowestOne for &FixedUInt<T, N, P> {
fn lowest_one(self) -> Option<u32> {
<FixedUInt<T, N, P> as const_num_traits::LowestOne>::lowest_one(*self)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for FixedUInt<T, N, P> {
fn bit_width(self) -> u32 {
Self::BIT_SIZE as u32 - <Self as const_num_traits::PrimBits>::leading_zeros(self)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::BitWidth for &FixedUInt<T, N, P> {
fn bit_width(self) -> u32 {
<FixedUInt<T, N, P> as const_num_traits::BitWidth>::bit_width(*self)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for FixedUInt<T, N, P> {
type Output = Self;
fn isolate_highest_one(self) -> Self {
let lz = <Self as const_num_traits::PrimBits>::leading_zeros(self);
if lz as usize == Self::BIT_SIZE {
<Self as const_num_traits::ConstZero>::ZERO
} else {
let pos = Self::BIT_SIZE as u32 - 1 - lz;
<Self as const_num_traits::ConstOne>::ONE << (pos as usize)
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for FixedUInt<T, N, P> {
type Output = Self;
fn isolate_lowest_one(self) -> Self {
let neg = <Self as const_num_traits::WrappingSub>::wrapping_sub(
<Self as const_num_traits::ConstZero>::ZERO,
self,
);
self & neg
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateHighestOne for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn isolate_highest_one(self) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as const_num_traits::IsolateHighestOne>::isolate_highest_one(*self)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::IsolateLowestOne for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn isolate_lowest_one(self) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as const_num_traits::IsolateLowestOne>::isolate_lowest_one(*self)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for FixedUInt<T, N, P> {
fn shl_exact(self, rhs: u32) -> Option<Self> {
if (rhs as usize) < Self::BIT_SIZE
&& rhs <= <Self as const_num_traits::PrimBits>::leading_zeros(self)
{
Some(self << (rhs as usize))
} else {
None
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for FixedUInt<T, N, P> {
fn shr_exact(self, rhs: u32) -> Option<Self> {
if (rhs as usize) < Self::BIT_SIZE
&& rhs <= <Self as const_num_traits::PrimBits>::trailing_zeros(self)
{
Some(self >> (rhs as usize))
} else {
None
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShlExact for &FixedUInt<T, N, P> {
fn shl_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
<FixedUInt<T, N, P> as const_num_traits::ShlExact>::shl_exact(*self, rhs)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::ShrExact for &FixedUInt<T, N, P> {
fn shr_exact(self, rhs: u32) -> Option<FixedUInt<T, N, P>> {
<FixedUInt<T, N, P> as const_num_traits::ShrExact>::shr_exact(*self, rhs)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for FixedUInt<T, N, P> {
type Output = Self;
fn funnel_shl(self, rhs: Self, n: u32) -> Self {
assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shl: n out of range");
if n == 0 {
self
} else {
let lo_shift = Self::BIT_SIZE as u32 - n;
(self << (n as usize)) | (rhs >> (lo_shift as usize))
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for FixedUInt<T, N, P> {
type Output = Self;
fn funnel_shr(self, rhs: Self, n: u32) -> Self {
assert!((n as usize) < Self::BIT_SIZE, "FixedUInt::funnel_shr: n out of range");
if n == 0 {
rhs
} else {
let hi_shift = Self::BIT_SIZE as u32 - n;
(rhs >> (n as usize)) | (self << (hi_shift as usize))
}
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShl for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn funnel_shl(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as const_num_traits::FunnelShl>::funnel_shl(*self, *rhs, n)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> const_num_traits::FunnelShr for &FixedUInt<T, N, P> {
type Output = FixedUInt<T, N, P>;
fn funnel_shr(self, rhs: Self, n: u32) -> FixedUInt<T, N, P> {
<FixedUInt<T, N, P> as const_num_traits::FunnelShr>::funnel_shr(*self, *rhs, n)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for FixedUInt<T, N, Nct> {
type Output = Self;
fn deposit_bits(self, mask: Self) -> Self {
let mut result = <Self as const_num_traits::ConstZero>::ZERO;
let mut remaining = mask;
let mut bb = <Self as const_num_traits::ConstOne>::ONE;
while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
if !<Self as const_num_traits::Zero>::is_zero(&(self & bb)) {
result |= lowest;
}
remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
remaining,
<Self as const_num_traits::ConstOne>::ONE,
);
bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
}
result
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for FixedUInt<T, N, Nct> {
type Output = Self;
fn extract_bits(self, mask: Self) -> Self {
let mut result = <Self as const_num_traits::ConstZero>::ZERO;
let mut remaining = mask;
let mut bb = <Self as const_num_traits::ConstOne>::ONE;
while !<Self as const_num_traits::Zero>::is_zero(&remaining) {
let lowest = <Self as const_num_traits::IsolateLowestOne>::isolate_lowest_one(remaining);
if !<Self as const_num_traits::Zero>::is_zero(&(self & lowest)) {
result |= bb;
}
remaining = remaining & <Self as const_num_traits::WrappingSub>::wrapping_sub(
remaining,
<Self as const_num_traits::ConstOne>::ONE,
);
bb = <Self as const_num_traits::WrappingShl>::wrapping_shl(bb, 1);
}
result
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::DepositBits for &FixedUInt<T, N, Nct> {
type Output = FixedUInt<T, N, Nct>;
fn deposit_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
<FixedUInt<T, N, Nct> as const_num_traits::DepositBits>::deposit_bits(*self, *mask)
}
}
c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> const_num_traits::ExtractBits for &FixedUInt<T, N, Nct> {
type Output = FixedUInt<T, N, Nct>;
fn extract_bits(self, mask: Self) -> FixedUInt<T, N, Nct> {
<FixedUInt<T, N, Nct> as const_num_traits::ExtractBits>::extract_bits(*self, *mask)
}
}
}
#[cfg(feature = "num-traits")]
impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShl
for FixedUInt<T, N, P>
{
fn wrapping_shl(&self, bits: u32) -> Self {
WrappingShl::wrapping_shl(*self, bits)
}
}
#[cfg(feature = "num-traits")]
impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingShr
for FixedUInt<T, N, P>
{
fn wrapping_shr(&self, bits: u32) -> Self {
WrappingShr::wrapping_shr(*self, bits)
}
}
#[cfg(feature = "num-traits")]
impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShl for FixedUInt<T, N, P> {
fn checked_shl(&self, bits: u32) -> Option<Self> {
CheckedShl::checked_shl(*self, bits)
}
}
#[cfg(feature = "num-traits")]
impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedShr for FixedUInt<T, N, P> {
fn checked_shr(&self, bits: u32) -> Option<Self> {
CheckedShr::checked_shr(*self, bits)
}
}
#[cfg(test)]
#[allow(clippy::op_ref)]
mod tests {
use super::*;
#[test]
fn test_bitand_combinations() {
let a = FixedUInt::<u8, 2>::from(12u8); let b = FixedUInt::<u8, 2>::from(10u8); let expected = FixedUInt::<u8, 2>::from(8u8);
assert_eq!(a & b, expected);
assert_eq!(a & &b, expected);
assert_eq!(&a & b, expected);
assert_eq!(&a & &b, expected);
}
#[test]
fn test_bitor_combinations() {
let a = FixedUInt::<u8, 2>::from(12u8); let b = FixedUInt::<u8, 2>::from(10u8); let expected = FixedUInt::<u8, 2>::from(14u8);
assert_eq!(a | b, expected);
assert_eq!(a | &b, expected);
assert_eq!(&a | b, expected);
assert_eq!(&a | &b, expected);
}
#[test]
fn test_bitxor_combinations() {
let a = FixedUInt::<u8, 2>::from(12u8); let b = FixedUInt::<u8, 2>::from(10u8); let expected = FixedUInt::<u8, 2>::from(6u8);
assert_eq!(a ^ b, expected);
assert_eq!(a ^ &b, expected);
assert_eq!(&a ^ b, expected);
assert_eq!(&a ^ &b, expected);
}
#[test]
fn test_shl_combinations() {
let a = FixedUInt::<u8, 2>::from(2u8); let shift: usize = 2;
let expected = FixedUInt::<u8, 2>::from(8u8);
assert_eq!(a << shift, expected);
assert_eq!(a << &shift, expected);
assert_eq!(&a << shift, expected);
assert_eq!(&a << &shift, expected);
let shift32: u32 = 2;
assert_eq!(a << shift32, expected);
assert_eq!(a << &shift32, expected);
assert_eq!(&a << shift32, expected);
assert_eq!(&a << &shift32, expected);
}
#[test]
fn test_shr_combinations() {
let a = FixedUInt::<u8, 2>::from(8u8); let shift: usize = 2;
let expected = FixedUInt::<u8, 2>::from(2u8);
assert_eq!(a >> shift, expected);
assert_eq!(a >> &shift, expected);
assert_eq!(&a >> shift, expected);
assert_eq!(&a >> &shift, expected);
let shift32: u32 = 2;
assert_eq!(a >> shift32, expected);
assert_eq!(a >> &shift32, expected);
assert_eq!(&a >> shift32, expected);
assert_eq!(&a >> &shift32, expected);
}
#[test]
fn test_const_bitops() {
type TestInt = FixedUInt<u8, 2>;
let a = TestInt::from(0b11001100u8);
let b = TestInt::from(0b10101010u8);
let not_a = !a;
assert_eq!(not_a.array[0], 0b00110011);
assert_eq!(not_a.array[1], 0xFF);
assert_eq!(a & b, TestInt::from(0b10001000u8));
assert_eq!(a | b, TestInt::from(0b11101110u8));
assert_eq!(a ^ b, TestInt::from(0b01100110u8));
assert_eq!(TestInt::from(1u8) << 4usize, TestInt::from(16u8));
assert_eq!(TestInt::from(16u8) >> 2usize, TestInt::from(4u8));
#[cfg(feature = "nightly")]
{
const A: TestInt = FixedUInt::from_array([0b11001100, 0]);
const B: TestInt = FixedUInt::from_array([0b10101010, 0]);
const NOT_A: TestInt = !A;
const AND_AB: TestInt = A & B;
const OR_AB: TestInt = A | B;
const XOR_AB: TestInt = A ^ B;
const SHL_1: TestInt = FixedUInt::from_array([1u8, 0]) << 4usize;
const SHR_16: TestInt = FixedUInt::from_array([16u8, 0]) >> 2usize;
assert_eq!(NOT_A.array[0], 0b00110011);
assert_eq!(AND_AB.array[0], 0b10001000);
assert_eq!(OR_AB.array[0], 0b11101110);
assert_eq!(XOR_AB.array[0], 0b01100110);
assert_eq!(SHL_1.array[0], 16);
assert_eq!(SHR_16.array[0], 4);
}
}
#[test]
fn test_const_shift_traits() {
type TestInt = FixedUInt<u8, 2>;
let a = TestInt::from(0x80u8); let (res, overflow) = OverflowingShl::overflowing_shl(a, 8);
assert_eq!(res.array, [0, 0x80]); assert!(!overflow);
let (res, overflow) = OverflowingShl::overflowing_shl(a, 16);
assert_eq!(res.array, [0x80, 0]); assert!(overflow);
let (res, overflow) = OverflowingShl::overflowing_shl(a, 9);
assert_eq!(res.array, [0, 0]); assert!(!overflow);
let b = TestInt::from(0x0100u16); let (res, overflow) = OverflowingShr::overflowing_shr(b, 8);
assert_eq!(res.array, [1, 0]); assert!(!overflow);
let (res, overflow) = OverflowingShr::overflowing_shr(b, 16);
assert_eq!(res.array, [0, 1]); assert!(overflow);
let c = TestInt::from(1u8);
assert_eq!(WrappingShl::wrapping_shl(c, 4).array, [16, 0]);
assert_eq!(WrappingShl::wrapping_shl(c, 16).array, [1, 0]); assert_eq!(WrappingShl::wrapping_shl(c, 17).array, [2, 0]);
let d = TestInt::from(0x8000u16);
assert_eq!(WrappingShr::wrapping_shr(d, 4).array, [0, 0x08]);
assert_eq!(WrappingShr::wrapping_shr(d, 16).array, [0, 0x80]); assert_eq!(WrappingShr::wrapping_shr(d, 17).array, [0, 0x40]);
let e = TestInt::from(1u8);
assert_eq!(CheckedShl::checked_shl(e, 4), Some(TestInt::from(16u8)));
assert_eq!(
CheckedShl::checked_shl(e, 15),
Some(TestInt::from(0x8000u16))
);
assert_eq!(CheckedShl::checked_shl(e, 16), None);
let f = TestInt::from(0x8000u16);
assert_eq!(CheckedShr::checked_shr(f, 15), Some(TestInt::from(1u8)));
assert_eq!(CheckedShr::checked_shr(f, 16), None);
let g = TestInt::from(42u8);
assert_eq!(OverflowingShl::overflowing_shl(g, 0), (g, false));
assert_eq!(OverflowingShr::overflowing_shr(g, 0), (g, false));
assert_eq!(WrappingShl::wrapping_shl(g, 0), g);
assert_eq!(WrappingShr::wrapping_shr(g, 0), g);
assert_eq!(CheckedShl::checked_shl(g, 0), Some(g));
assert_eq!(CheckedShr::checked_shr(g, 0), Some(g));
}
#[test]
fn test_const_shift_traits_n0() {
type ZeroInt = FixedUInt<u8, 0>;
let z = ZeroInt::from_array([]);
assert_eq!(OverflowingShl::overflowing_shl(z, 0), (z, true));
assert_eq!(OverflowingShr::overflowing_shr(z, 0), (z, true));
assert_eq!(WrappingShl::wrapping_shl(z, 0), z);
assert_eq!(WrappingShr::wrapping_shr(z, 0), z);
assert_eq!(CheckedShl::checked_shl(z, 0), None);
assert_eq!(CheckedShr::checked_shr(z, 0), None);
}
#[test]
#[cfg(feature = "num-traits")]
fn test_num_traits_shift_wrappers() {
use num_traits::{CheckedShl, CheckedShr, WrappingShl, WrappingShr};
type TestInt = FixedUInt<u8, 2>;
let a = TestInt::from(1u8);
assert_eq!(WrappingShl::wrapping_shl(&a, 4), TestInt::from(16u8));
assert_eq!(WrappingShl::wrapping_shl(&a, 16), a);
let b = TestInt::from(16u8);
assert_eq!(WrappingShr::wrapping_shr(&b, 4), TestInt::from(1u8));
assert_eq!(CheckedShl::checked_shl(&a, 4), Some(TestInt::from(16u8)));
assert_eq!(CheckedShl::checked_shl(&a, 16), None);
assert_eq!(CheckedShr::checked_shr(&b, 4), Some(TestInt::from(1u8)));
assert_eq!(CheckedShr::checked_shr(&b, 16), None);
}
#[test]
fn test_unbounded_shift() {
type U16 = FixedUInt<u8, 2>;
let one = U16::from(1u8);
assert_eq!(UnboundedShl::unbounded_shl(one, 0), one);
assert_eq!(UnboundedShl::unbounded_shl(one, 4), U16::from(16u8));
assert_eq!(UnboundedShl::unbounded_shl(one, 15), U16::from(0x8000u16));
assert_eq!(UnboundedShr::unbounded_shr(U16::from(0x8000u16), 15), one);
assert_eq!(UnboundedShr::unbounded_shr(U16::from(16u8), 4), one);
assert_eq!(UnboundedShl::unbounded_shl(one, 16), U16::from(0u8));
assert_eq!(
UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 16),
U16::from(0u8)
);
assert_eq!(
UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 17),
U16::from(0u8)
);
assert_eq!(
UnboundedShl::unbounded_shl(U16::from(0xFFFFu16), 100),
U16::from(0u8)
);
assert_eq!(
UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 17),
U16::from(0u8)
);
assert_eq!(
UnboundedShr::unbounded_shr(U16::from(0xFFFFu16), 100),
U16::from(0u8)
);
type U32 = FixedUInt<u8, 4>;
let one32 = U32::from(1u8);
assert_eq!(
UnboundedShl::unbounded_shl(one32, 31),
U32::from(0x80000000u32)
);
assert_eq!(UnboundedShl::unbounded_shl(one32, 32), U32::from(0u8));
assert_eq!(
UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 31),
one32
);
assert_eq!(
UnboundedShr::unbounded_shr(U32::from(0x80000000u32), 32),
U32::from(0u8)
);
}
#[test]
fn test_unbounded_shift_polymorphic() {
fn test_unbounded<T>(val: T, shift: u32, expected_shl: T, expected_shr: T)
where
T: UnboundedShl<Output = T>
+ UnboundedShr<Output = T>
+ core::ops::Shl<u32, Output = T>
+ core::ops::Shr<u32, Output = T>
+ Eq
+ core::fmt::Debug
+ Copy,
{
assert_eq!(UnboundedShl::unbounded_shl(val, shift), expected_shl);
assert_eq!(UnboundedShr::unbounded_shr(val, shift), expected_shr);
}
type U8x2 = FixedUInt<u8, 2>;
type U8x4 = FixedUInt<u8, 4>;
type U16x2 = FixedUInt<u16, 2>;
test_unbounded(U8x2::from(1u8), 4, U8x2::from(16u8), U8x2::from(0u8));
test_unbounded(U8x4::from(1u8), 4, U8x4::from(16u8), U8x4::from(0u8));
test_unbounded(U16x2::from(1u8), 4, U16x2::from(16u8), U16x2::from(0u8));
test_unbounded(1u8, 4, 16u8, 0u8);
test_unbounded(1u16, 4, 16u16, 0u16);
test_unbounded(1u32, 4, 16u32, 0u32);
test_unbounded(1u8, 8, 0u8, 0u8);
test_unbounded(U8x2::from(1u8), 16, U8x2::from(0u8), U8x2::from(0u8));
}
#[test]
fn test_bit_width() {
use const_num_traits::BitWidth;
type U16 = FixedUInt<u8, 2>;
assert_eq!(BitWidth::bit_width(U16::from(0u8)), 0);
assert_eq!(BitWidth::bit_width(U16::from(1u8)), 1);
assert_eq!(BitWidth::bit_width(U16::from(2u8)), 2);
assert_eq!(BitWidth::bit_width(U16::from(3u8)), 2);
assert_eq!(BitWidth::bit_width(U16::from(255u8)), 8);
assert_eq!(BitWidth::bit_width(U16::from(256u16)), 9);
assert_eq!(BitWidth::bit_width(U16::from(0xFFFFu16)), 16);
}
#[test]
fn test_highest_lowest_one() {
use const_num_traits::{HighestOne, LowestOne};
type U16 = FixedUInt<u8, 2>;
assert_eq!(HighestOne::highest_one(U16::from(0u8)), None);
assert_eq!(HighestOne::highest_one(U16::from(1u8)), Some(0));
assert_eq!(HighestOne::highest_one(U16::from(0b1010_0000u8)), Some(7));
assert_eq!(HighestOne::highest_one(U16::from(0x8000u16)), Some(15));
assert_eq!(LowestOne::lowest_one(U16::from(0u8)), None);
assert_eq!(LowestOne::lowest_one(U16::from(1u8)), Some(0));
assert_eq!(LowestOne::lowest_one(U16::from(0b0010_1000u8)), Some(3));
assert_eq!(LowestOne::lowest_one(U16::from(0x8000u16)), Some(15));
}
#[test]
fn test_isolate_highest_lowest_one() {
use const_num_traits::{IsolateHighestOne, IsolateLowestOne};
type U16 = FixedUInt<u8, 2>;
assert_eq!(
IsolateHighestOne::isolate_highest_one(U16::from(0u8)),
U16::from(0u8)
);
assert_eq!(
IsolateLowestOne::isolate_lowest_one(U16::from(0u8)),
U16::from(0u8)
);
assert_eq!(
IsolateHighestOne::isolate_highest_one(U16::from(0b1010_0000u8)),
U16::from(0b1000_0000u8)
);
assert_eq!(
IsolateLowestOne::isolate_lowest_one(U16::from(0b1010_1000u8)),
U16::from(0b0000_1000u8)
);
let p: U16 = U16::from(0x0100u16);
assert_eq!(IsolateHighestOne::isolate_highest_one(p), p);
assert_eq!(IsolateLowestOne::isolate_lowest_one(p), p);
}
#[test]
fn test_shl_shr_exact() {
use const_num_traits::{ShlExact, ShrExact};
type U16 = FixedUInt<u8, 2>;
assert_eq!(
ShlExact::shl_exact(U16::from(1u8), 4),
Some(U16::from(16u8))
);
assert_eq!(ShlExact::shl_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
assert_eq!(ShlExact::shl_exact(U16::from(0x8000u16), 1), None);
assert_eq!(ShlExact::shl_exact(U16::from(1u8), 16), None);
assert_eq!(
ShrExact::shr_exact(U16::from(16u8), 4),
Some(U16::from(1u8))
);
assert_eq!(ShrExact::shr_exact(U16::from(0u8), 8), Some(U16::from(0u8)));
assert_eq!(ShrExact::shr_exact(U16::from(0b0001u8), 1), None);
assert_eq!(ShrExact::shr_exact(U16::from(0b0011u8), 1), None);
assert_eq!(ShrExact::shr_exact(U16::from(1u8), 16), None);
}
#[test]
#[allow(clippy::needless_borrows_for_generic_args)]
fn test_ref_receivers_compile_through() {
use const_num_traits::{BitWidth, IsolateHighestOne, IsolateLowestOne, ShlExact, ShrExact};
type U16 = FixedUInt<u8, 2>;
let v = U16::from(0b0010_1000u8);
assert_eq!(BitWidth::bit_width(&v), 6);
assert_eq!(
IsolateHighestOne::isolate_highest_one(&v),
U16::from(0b0010_0000u8)
);
assert_eq!(
IsolateLowestOne::isolate_lowest_one(&v),
U16::from(0b0000_1000u8)
);
assert_eq!(ShlExact::shl_exact(&v, 2), Some(U16::from(0b1010_0000u8)));
assert_eq!(ShrExact::shr_exact(&v, 3), Some(U16::from(0b0000_0101u8)));
}
#[test]
fn test_funnel_shifts() {
use const_num_traits::{FunnelShl, FunnelShr};
type U16 = FixedUInt<u8, 2>;
assert_eq!(
FunnelShl::funnel_shl(U16::from(0x0001u16), U16::from(0x8000u16), 1),
U16::from(0x0003u16),
);
assert_eq!(
FunnelShl::funnel_shl(U16::from(0xABCDu16), U16::from(0xFFFFu16), 0),
U16::from(0xABCDu16),
);
assert_eq!(
FunnelShr::funnel_shr(U16::from(0x0001u16), U16::from(0x8000u16), 1),
U16::from(0xC000u16),
);
assert_eq!(
FunnelShr::funnel_shr(U16::from(0xABCDu16), U16::from(0x1234u16), 0),
U16::from(0x1234u16),
);
let hi = U16::from(0x0001u16);
let lo = U16::from(0x8000u16);
assert_eq!(FunnelShl::funnel_shl(&hi, &lo, 1), U16::from(0x0003u16));
assert_eq!(FunnelShr::funnel_shr(&hi, &lo, 1), U16::from(0xC000u16));
}
#[test]
#[should_panic(expected = "funnel_shl: n out of range")]
fn test_funnel_shl_panics_at_bit_size() {
use const_num_traits::FunnelShl;
type U16 = FixedUInt<u8, 2>;
let _ = FunnelShl::funnel_shl(U16::from(1u8), U16::from(0u8), 16);
}
#[test]
fn test_deposit_extract_bits() {
use const_num_traits::Nct;
use const_num_traits::{DepositBits, ExtractBits};
type U16 = FixedUInt<u8, 2, Nct>;
assert_eq!(
DepositBits::deposit_bits(U16::from(0b101u8), U16::from(0b1111_0000u8)),
U16::from(0b0101_0000u8),
);
assert_eq!(
ExtractBits::extract_bits(U16::from(0b0101_0011u8), U16::from(0b1111_0000u8)),
U16::from(0b101u8),
);
assert_eq!(
DepositBits::deposit_bits(U16::from(0xFFFFu16), U16::from(0u8)),
U16::from(0u8),
);
assert_eq!(
ExtractBits::extract_bits(U16::from(0xFFFFu16), U16::from(0u8)),
U16::from(0u8),
);
assert_eq!(
DepositBits::deposit_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
U16::from(0xABCDu16),
);
assert_eq!(
ExtractBits::extract_bits(U16::from(0xABCDu16), U16::from(0xFFFFu16)),
U16::from(0xABCDu16),
);
let mask = U16::from(0b1010_1010u8);
let v = U16::from(0b1111_1111u8);
let extracted = ExtractBits::extract_bits(v, mask);
let redeposited = DepositBits::deposit_bits(extracted, mask);
assert_eq!(redeposited, v & mask);
let v_ref = U16::from(0b0110_0110u8);
let m_ref = U16::from(0b1111_0000u8);
assert_eq!(
ExtractBits::extract_bits(&v_ref, &m_ref),
U16::from(0b0110u8),
);
assert_eq!(
DepositBits::deposit_bits(&U16::from(0b101u8), &m_ref),
U16::from(0b0101_0000u8),
);
}
c0nst::c0nst! {
pub c0nst fn const_overflowing_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> (FixedUInt<T, N, P>, bool) {
OverflowingShl::overflowing_shl(v, bits)
}
pub c0nst fn const_overflowing_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> (FixedUInt<T, N, P>, bool) {
OverflowingShr::overflowing_shr(v, bits)
}
pub c0nst fn const_wrapping_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
WrappingShl::wrapping_shl(v, bits)
}
pub c0nst fn const_wrapping_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
WrappingShr::wrapping_shr(v, bits)
}
pub c0nst fn const_checked_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
CheckedShl::checked_shl(v, bits)
}
pub c0nst fn const_checked_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
CheckedShr::checked_shr(v, bits)
}
pub c0nst fn const_unbounded_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
UnboundedShl::unbounded_shl(v, bits)
}
pub c0nst fn const_unbounded_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> FixedUInt<T, N, P> {
UnboundedShr::unbounded_shr(v, bits)
}
pub c0nst fn const_highest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
const_num_traits::HighestOne::highest_one(v)
}
pub c0nst fn const_lowest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> Option<u32> {
const_num_traits::LowestOne::lowest_one(v)
}
pub c0nst fn const_bit_width<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> u32 {
const_num_traits::BitWidth::bit_width(v)
}
pub c0nst fn const_isolate_highest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
const_num_traits::IsolateHighestOne::isolate_highest_one(v)
}
pub c0nst fn const_isolate_lowest_one<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>) -> FixedUInt<T, N, P> {
const_num_traits::IsolateLowestOne::isolate_lowest_one(v)
}
pub c0nst fn const_shl_exact<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
const_num_traits::ShlExact::shl_exact(v, bits)
}
pub c0nst fn const_shr_exact<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(v: FixedUInt<T, N, P>, bits: u32) -> Option<FixedUInt<T, N, P>> {
const_num_traits::ShrExact::shr_exact(v, bits)
}
pub c0nst fn const_funnel_shl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(hi: FixedUInt<T, N, P>, lo: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
const_num_traits::FunnelShl::funnel_shl(hi, lo, n)
}
pub c0nst fn const_funnel_shr<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(hi: FixedUInt<T, N, P>, lo: FixedUInt<T, N, P>, n: u32) -> FixedUInt<T, N, P> {
const_num_traits::FunnelShr::funnel_shr(hi, lo, n)
}
pub c0nst fn const_deposit_bits<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(v: FixedUInt<T, N, Nct>, mask: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
const_num_traits::DepositBits::deposit_bits(v, mask)
}
pub c0nst fn const_extract_bits<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(v: FixedUInt<T, N, Nct>, mask: FixedUInt<T, N, Nct>) -> FixedUInt<T, N, Nct> {
const_num_traits::ExtractBits::extract_bits(v, mask)
}
}
#[test]
fn nightly_const_eval_bit_traits() {
type U16 = FixedUInt<u8, 2>;
let v = U16::from(1u8);
assert_eq!(const_overflowing_shl(v, 4), (U16::from(16u8), false));
assert_eq!(const_wrapping_shl(v, 4), U16::from(16u8));
assert_eq!(const_checked_shl(v, 16), None);
assert_eq!(const_bit_width(U16::from(0xFFu8)), 8);
#[cfg(feature = "nightly")]
{
const V: U16 = FixedUInt::from_array([1, 0]);
const V_FF: U16 = FixedUInt::from_array([0xFF, 0]);
const V_MASK: U16 = FixedUInt::from_array([0b1010_1000, 0]);
const HI: U16 = FixedUInt::from_array([1, 0]);
const LO: U16 = FixedUInt::from_array([0, 0x80]);
const OSHL: (U16, bool) = const_overflowing_shl(V, 4);
const OSHR: (U16, bool) = const_overflowing_shr(V_FF, 4);
const WSHL: U16 = const_wrapping_shl(V, 4);
const WSHR: U16 = const_wrapping_shr(V_FF, 4);
const CSHL: Option<U16> = const_checked_shl(V, 16);
const CSHR: Option<U16> = const_checked_shr(V, 4);
const USHL: U16 = const_unbounded_shl(V, 8);
const USHR: U16 = const_unbounded_shr(V_FF, 4);
const HI_ONE: Option<u32> = const_highest_one(V_FF);
const LO_ONE: Option<u32> = const_lowest_one(V_MASK);
const BW: u32 = const_bit_width(V_FF);
const IH: U16 = const_isolate_highest_one(V_MASK);
const IL: U16 = const_isolate_lowest_one(V_MASK);
const SHLEX: Option<U16> = const_shl_exact(V, 4);
const SHREX: Option<U16> = const_shr_exact(FixedUInt::from_array([16, 0]), 4);
const FSHL: U16 = const_funnel_shl(HI, LO, 1);
const FSHR: U16 = const_funnel_shr(HI, LO, 1);
const DEP: U16 = const_deposit_bits(
FixedUInt::from_array([0b101, 0]),
FixedUInt::from_array([0b1111_0000, 0]),
);
const EXT: U16 = const_extract_bits(
FixedUInt::from_array([0b0101_0011, 0]),
FixedUInt::from_array([0b1111_0000, 0]),
);
assert_eq!(OSHL.0.array, [16, 0]);
assert!(!OSHL.1);
assert_eq!(OSHR.0.array, [0x0F, 0]);
assert!(!OSHR.1);
assert_eq!(WSHL.array, [16, 0]);
assert_eq!(WSHR.array, [0x0F, 0]);
assert!(CSHL.is_none());
assert!(CSHR.is_some());
assert_eq!(USHL.array, [0, 1]);
assert_eq!(USHR.array, [0x0F, 0]);
assert_eq!(HI_ONE, Some(7));
assert_eq!(LO_ONE, Some(3));
assert_eq!(BW, 8);
assert_eq!(IH.array, [0b1000_0000, 0]);
assert_eq!(IL.array, [0b0000_1000, 0]);
assert!(SHLEX.is_some());
assert!(SHREX.is_some());
assert_eq!(FSHL.array, [0x03, 0]);
assert_eq!(FSHR.array, [0x00, 0xC0]);
assert_eq!(DEP.array, [0b0101_0000, 0]);
assert_eq!(EXT.array, [0b101, 0]);
}
}
}