use big_int_proc::BigIntTraits;
use crate::prelude::*;
use std::{collections::VecDeque, vec};
macro_rules! loose_definition {
(
$data_type:ty;
$(#[$denormal_meta:meta])*
$denormal_name:ident;
$(#[$type_meta:meta])*
$name:ident;
$(#[$builder_meta:meta])*
$builder_name:ident;
) => {
$(#[$denormal_meta])*
pub type $denormal_name<const BASE: usize> = Denormal<BASE, $name<BASE>>;
$(#[$type_meta])*
#[derive(Clone, Debug, BigIntTraits)]
pub struct $name<const BASE: usize> {
sign: Sign,
digits: Vec<$data_type>,
}
impl<const BASE: usize> $name<BASE> {
pub unsafe fn from_raw_parts(digits: Vec<Digit>) -> Self {
let sign = Positive;
let digits = digits.into_iter().map(|digit| digit as $data_type).collect();
$name { sign, digits }
}
}
impl<const BASE: usize> BigInt<BASE> for $name<BASE> {
type Builder = $builder_name<{ BASE }>;
type Denormal = Denormal<BASE, Self>;
fn len(&self) -> usize {
self.digits.len()
}
fn get_digit(&self, digit: usize) -> Option<Digit> {
self.digits.get(digit).map(|digit| *digit as Digit)
}
fn set_digit(&mut self, digit: usize, value: Digit) {
if let Some(digit) = self.digits.get_mut(digit) {
*digit = value as $data_type;
}
}
fn zero() -> Self {
let sign = Positive;
let digits = vec![0];
$name { sign, digits }
}
fn with_sign(self, sign: Sign) -> Self {
$name { sign, ..self }
}
fn normalized(self) -> Self {
match self.digits.iter().position(|digit| *digit != 0) {
None => Self::zero(),
Some(pos @ 1..) => $name {
digits: self.digits[pos..].to_vec(),
..self
},
_ => self,
}
}
fn sign(&self) -> Sign {
self.sign
}
fn set_sign(&mut self, sign: Sign) {
self.sign = sign;
}
fn push_back(&mut self, digit: crate::Digit) {
self.digits.push(digit as $data_type);
}
unsafe fn push_front(&mut self, digit: crate::Digit) {
self.digits.insert(0, digit as $data_type);
}
unsafe fn shr_assign_inner(&mut self, amount: usize) {
self.digits =
self.digits[..self.digits.len().checked_sub(amount).unwrap_or_default()].to_vec();
}
unsafe fn shl_assign_inner(&mut self, amount: usize) {
self.digits.extend(vec![0; amount]);
}
unsafe fn pop_back(&mut self) -> Option<Digit> {
self.digits.pop().map(|digit| digit as Digit)
}
unsafe fn pop_front(&mut self) -> Option<Digit> {
(!self.digits.is_empty()).then(|| self.digits.remove(0) as Digit)
}
}
$(#[$builder_meta])*
#[derive(Debug)]
pub struct $builder_name<const BASE: usize> {
sign: Sign,
digits: VecDeque<$data_type>,
}
impl<const BASE: usize> BigIntBuilder<BASE> for $builder_name<BASE> {
fn new() -> Self {
$builder_name {
sign: Positive,
digits: VecDeque::new(),
}
}
fn push_front(&mut self, digit: Digit) {
self.digits.push_front(digit as $data_type);
}
fn push_back(&mut self, digit: Digit) {
self.digits.push_back(digit as $data_type);
}
fn with_sign(self, sign: Sign) -> Self {
$builder_name { sign, ..self }
}
fn is_empty(&self) -> bool {
self.digits.is_empty()
}
}
impl<const BASE: usize> From<$builder_name<BASE>> for Denormal<BASE, $name<BASE>> {
fn from(value: $builder_name<BASE>) -> Self {
let sign = value.sign;
let digits = value.digits.into();
Denormal($name { sign, digits })
}
}
impl<const BASE: usize> From<$builder_name<BASE>> for $name<BASE> {
fn from(value: $builder_name<BASE>) -> Self {
let denormal: <Self as BigInt<BASE>>::Denormal = value.into();
denormal.unwrap()
}
}
};
}
loose_definition!(
u8;
DenormalLooseBytes;
LooseBytes;
LooseBytesBuilder;
);
loose_definition!(
u16;
DenormalLooseShorts;
LooseShorts;
LooseShortsBuilder;
);
loose_definition!(
u32;
DenormalLooseWords;
LooseWords;
LooseWordsBuilder;
);
loose_definition!(
u64;
DenormalLoose;
Loose;
LooseBuilder;
);