use super::{AssertCapFits, HeaplessBigInt, zero};
use crate::MachineWord;
use const_num_traits::{Bounded, ConstOne, ConstZero, One, Personality, PersonalityTag, Zero};
use core::marker::PhantomData;
impl<T: MachineWord, const CAP: usize, P: Personality> Zero for HeaplessBigInt<T, CAP, P> {
#[inline]
fn zero() -> Self {
Self::const_zero()
}
#[inline]
fn is_zero(&self) -> bool {
let n = self.len as usize;
match P::TAG {
PersonalityTag::Nct => {
let mut i = 0;
while i < n {
if !super::is_zero(&self.limbs[i]) {
return false;
}
i += 1;
}
true
}
PersonalityTag::Ct => {
let mut acc = zero::<T>();
let mut i = 0;
while i < n {
acc |= self.limbs[i];
i += 1;
}
super::is_zero(&acc)
}
}
}
#[inline]
fn set_zero(&mut self) {
*self = <Self as Zero>::zero();
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> One for HeaplessBigInt<T, CAP, P> {
#[inline]
fn one() -> Self {
let () = <Self as AssertCapFits>::CHECK;
Self::const_one()
}
#[inline]
fn set_one(&mut self) {
*self = <Self as One>::one();
}
#[inline]
fn is_one(&self) -> bool {
let n = self.len as usize;
if n == 0 {
return false;
}
match P::TAG {
PersonalityTag::Nct => {
if !<T as const_num_traits::One>::is_one(&self.limbs[0]) {
return false;
}
let mut i = 1;
while i < n {
if !super::is_zero(&self.limbs[i]) {
return false;
}
i += 1;
}
true
}
PersonalityTag::Ct => const_is_one_ct(&self.limbs, n),
}
}
}
#[inline(never)]
pub(crate) fn const_is_one_ct<T: MachineWord, const CAP: usize>(
limbs: &[T; CAP],
n: usize,
) -> bool {
let mut acc = limbs[0] ^ <T as ConstOne>::ONE;
let mut i = 1;
while i < n {
acc |= limbs[i];
i += 1;
}
super::is_zero(&acc)
}
impl<T: MachineWord, const CAP: usize, P: Personality> Default for HeaplessBigInt<T, CAP, P> {
#[inline]
fn default() -> Self {
<Self as Zero>::zero()
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
#[inline]
const fn const_zero() -> Self {
Self {
limbs: [<T as ConstZero>::ZERO; CAP],
len: 0,
_p: PhantomData,
}
}
#[inline]
const fn const_one() -> Self {
assert!(CAP >= 1, "HeaplessBigInt::ONE requires CAP >= 1");
let mut limbs = [<T as ConstZero>::ZERO; CAP];
limbs[0] = <T as ConstOne>::ONE;
Self {
limbs,
len: 1,
_p: PhantomData,
}
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> ConstZero for HeaplessBigInt<T, CAP, P> {
const ZERO: Self = Self::const_zero();
}
impl<T: MachineWord, const CAP: usize, P: Personality> ConstOne for HeaplessBigInt<T, CAP, P> {
const ONE: Self = Self::const_one();
}
#[cfg(test)]
mod tests {
use super::*;
use const_num_traits::Ct;
type Hc = HeaplessBigInt<u8, 4, Ct>;
#[test]
fn ct_is_one() {
assert!(<Hc as One>::is_one(&<Hc as One>::one()));
assert!(!<Hc as One>::is_one(&<Hc as Zero>::zero()));
assert!(!<Hc as One>::is_one(&Hc::from_limbs([2, 0, 0, 0], 1)));
assert!(!<Hc as One>::is_one(&Hc::from_limbs([0, 1, 0, 0], 2)));
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> Bounded for HeaplessBigInt<T, CAP, P> {
#[inline]
fn min_value() -> Self {
<Self as ConstZero>::ZERO
}
#[inline]
fn max_value() -> Self {
let () = <Self as AssertCapFits>::CHECK;
Self {
limbs: [<T as Bounded>::max_value(); CAP],
len: CAP as u16,
_p: PhantomData,
}
}
}