use core::{ops::{Add, Sub, Mul, Rem, Shl, Shr, BitOr, BitAnd, BitOrAssign}, fmt::Debug};
#[cfg(feature = "rand")]
use rand_core::CryptoRngCore;
pub trait Digit:
Add<Output = Self> + Sub<Output = Self> +
Mul<Output = Self> + Rem<Output = Self> +
Shl<usize, Output = Self> + Shr<usize, Output = Self> +
BitOr<Output = Self> + BitOrAssign + BitAnd<Output = Self> +
PartialEq + Ord +
Copy + Default + Debug
{
const BYTE_LEN: usize;
const ONE: Self;
const ZERO: Self;
fn nlz(self) -> usize;
fn bit(&self, idx: usize) -> bool;
fn size() -> usize;
fn is_zero(self) -> bool;
fn is_odd(self) -> bool;
fn carry_add(self, rhs: Self, carry: bool) -> (Self, bool);
fn overflow_add(self, rhs: Self) -> (Self, bool);
fn borrow_sub(self, rhs: Self, carry: bool) -> (Self, bool);
fn overflow_sub(self, rhs: Self) -> (Self, bool);
fn carry_mul(self, rhs: Self, carry: Self) -> (Self, Self);
fn widen_mul(self, rhs: Self) -> (Self, Self);
fn overflow_mul(self, rhs: Self) -> (Self, bool);
fn from_bool(b: bool) -> Self;
fn set_bit(self, idx: usize, b: bool) -> Self;
#[cfg(feature = "rand")]
fn rand(rng: &mut impl CryptoRngCore) -> Self;
}
impl Digit for u64 {
const ONE: Self = 1;
const ZERO: Self = 0;
const BYTE_LEN: usize = core::mem::size_of::<u64>();
fn nlz(self) -> usize {
u64::leading_zeros(self) as usize
}
fn size() -> usize {
core::mem::size_of::<u64>()
}
fn is_zero(self) -> bool {
self == 0
}
fn is_odd(self) -> bool {
self & 1 != 0
}
fn bit(&self, idx: usize) -> bool {
self & (1 << idx) != 0
}
fn carry_add(self, rhs: Self, carry: bool) -> (Self, bool) {
self.carrying_add(rhs, carry)
}
fn overflow_add(self, rhs: Self) -> (Self, bool) {
self.overflowing_add(rhs)
}
fn borrow_sub(self, rhs: Self, carry: bool) -> (Self, bool) {
self.borrowing_sub(rhs, carry)
}
fn overflow_sub(self, rhs: Self) -> (Self, bool) {
self.overflowing_sub(rhs)
}
fn carry_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
self.carrying_mul(rhs, carry)
}
fn widen_mul(self, rhs: Self) -> (Self, Self) {
self.widening_mul(rhs)
}
fn overflow_mul(self, rhs: Self) -> (Self, bool) {
self.overflowing_mul(rhs)
}
fn from_bool(b: bool) -> Self {
b as u64
}
fn set_bit(self, idx: usize, b: bool) -> Self {
let mask = 1 << idx;
if b {
self | mask
} else {
self & !mask
}
}
#[cfg(feature = "rand")]
fn rand(rng: &mut impl CryptoRngCore) -> Self {
rng.next_u64()
}
}
macro_rules! impl_digit {
(@all $($t:ty),*) => {
$(impl_digit!($t);)*
};
($t:ty) => {
impl Digit for $t {
const ONE: Self = 1;
const ZERO: Self = 0;
const BYTE_LEN: usize = core::mem::size_of::<$t>();
fn nlz(self) -> usize {
<$t>::leading_zeros(self) as usize
}
fn size() -> usize {
core::mem::size_of::<$t>()
}
fn is_zero(self) -> bool {
self == 0
}
fn is_odd(self) -> bool {
self & 1 != 0
}
fn bit(&self, idx: usize) -> bool {
self & (1 << idx) != 0
}
fn carry_add(self, rhs: Self, carry: bool) -> (Self, bool) {
<$t>::carrying_add(self, rhs, carry)
}
fn overflow_add(self, rhs: Self) -> (Self, bool) {
<$t>::overflowing_add(self, rhs)
}
fn borrow_sub(self, rhs: Self, carry: bool) -> (Self, bool) {
self.borrowing_sub(rhs, carry)
}
fn overflow_sub(self, rhs: Self) -> (Self, bool) {
self.overflowing_sub(rhs)
}
fn carry_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
self.carrying_mul(rhs, carry)
}
fn overflow_mul(self, rhs: Self) -> (Self, bool) {
self.overflowing_mul(rhs)
}
fn from_bool(b: bool) -> Self {
b as $t
}
fn widen_mul(self, rhs: Self) -> (Self, Self) {
self.widening_mul(rhs)
}
fn set_bit(self, idx: usize, b: bool) -> Self {
let mask = 1 << idx;
if b {
self | mask
} else {
self & !mask
}
}
#[cfg(feature = "rand")]
fn rand(rng: &mut impl CryptoRngCore) -> Self {
rng.next_u64() as $t
}
}
};
}
impl_digit!(@all u8, u16, u32);