use crate::assign::Assign;
use crate::{Arbi, Digit};
use core::ops::Shr;
macro_rules! impl_assign_from_primitive {
($(($signed:ty, $unsigned:ty)),*) => {
$(
impl Assign<$signed> for Arbi {
/// Assign a builtin integral type value to an `Arbi`.
fn assign(&mut self, value: $signed) {
type UnsignedT = $unsigned;
let mut uvalue: UnsignedT = match value {
0 => {
self.neg = false;
self.vec.clear();
return;
}
#[allow(unused_comparisons)]
x if x < 0 => {
self.neg = true;
(0 as UnsignedT).wrapping_sub(value as UnsignedT)
}
_ => {
self.neg = false;
value as UnsignedT
}
};
if <$signed>::BITS <= Digit::BITS {
self.vec.resize(1, 0);
self.vec[0] = uvalue as Digit;
} else {
let mut temp: UnsignedT = uvalue;
let mut n_digits: usize = 1;
loop {
temp = temp.shr(Digit::BITS); if temp == 0 {
break;
}
n_digits += 1;
}
self.vec.resize(n_digits, 0);
let mut i: usize = 0;
while uvalue != 0 {
self.vec[i] = uvalue as Digit;
uvalue = uvalue.shr(Digit::BITS); i += 1;
}
}
}
}
impl Assign<&$signed> for Arbi {
fn assign(&mut self, value: &$signed) {
self.assign(*value)
}
}
)*
};
}
impl_assign_from_primitive!(
(i8, u8),
(i16, u16),
(i32, u32),
(i64, u64),
(i128, u128),
(isize, usize),
(u8, u8),
(u16, u16),
(u32, u32),
(u64, u64),
(u128, u128),
(usize, usize)
);
#[cfg(test)]
mod tests {
use super::*;
use crate::{DDigit, QDigit};
#[test]
fn test_assign_from_primitive() {
let mut arbi = Arbi::new();
arbi.assign(i8::MIN);
assert_eq!(arbi, i8::MIN);
arbi.assign(i8::MAX);
assert_eq!(arbi, i8::MAX);
arbi.assign(i16::MIN);
assert_eq!(arbi, i16::MIN);
arbi.assign(i16::MAX);
assert_eq!(arbi, i16::MAX);
arbi.assign(i32::MIN);
assert_eq!(arbi, i32::MIN);
arbi.assign(i32::MAX);
assert_eq!(arbi, i32::MAX);
arbi.assign(i64::MIN);
assert_eq!(arbi, i64::MIN);
arbi.assign(i64::MAX);
assert_eq!(arbi, i64::MAX);
arbi.assign(i128::MIN);
assert_eq!(arbi, i128::MIN);
arbi.assign(i128::MAX);
assert_eq!(arbi, i128::MAX);
arbi.assign(isize::MIN);
assert_eq!(arbi, isize::MIN);
arbi.assign(isize::MAX);
assert_eq!(arbi, isize::MAX);
arbi.assign(u8::MAX);
assert_eq!(arbi, u8::MAX);
arbi.assign(u16::MAX);
assert_eq!(arbi, u16::MAX);
arbi.assign(u32::MAX);
assert_eq!(arbi, u32::MAX);
arbi.assign(u64::MAX);
assert_eq!(arbi, u64::MAX);
arbi.assign(u128::MAX);
assert_eq!(arbi, u128::MAX);
arbi.assign(usize::MAX);
assert_eq!(arbi, usize::MAX);
arbi.assign(0);
assert_eq!(arbi, 0);
}
#[test]
fn test_assign_from_primitive_digit_boundaries() {
let mut arbi = Arbi::new();
arbi.assign(Digit::MAX - 1);
assert_eq!(arbi, Digit::MAX - 1);
arbi.assign(Digit::MAX);
assert_eq!(arbi, Digit::MAX);
arbi.assign(Digit::MAX as DDigit + 1);
assert_eq!(arbi, Digit::MAX as DDigit + 1);
arbi.assign(DDigit::MAX - 1);
assert_eq!(arbi, DDigit::MAX - 1);
arbi.assign(DDigit::MAX);
assert_eq!(arbi, DDigit::MAX);
arbi.assign(DDigit::MAX as QDigit + 1);
assert_eq!(arbi, DDigit::MAX as QDigit + 1);
}
}
#[cfg(test)]
mod translation_tests {
use super::*;
use alloc::string::ToString;
fn test_integer_value<T>(value: T, expected_str: &str)
where
T: Into<Arbi> + Clone + core::fmt::Display + 'static,
Arbi: Assign<T>,
{
let mut x: Arbi = value.clone().into();
assert_eq!(x.to_string(), expected_str, "Failed for type: {}", value);
<Arbi as Assign<T>>::assign(&mut x, value.clone());
assert_eq!(x.to_string(), expected_str);
let mut y: Arbi = Arbi::new();
<Arbi as Assign<T>>::assign(&mut y, value.clone());
assert_eq!(y.to_string(), expected_str);
}
fn test_integer<T>()
where
T: Into<Arbi>
+ Clone
+ core::fmt::Display
+ core::cmp::PartialEq
+ MinMax
+ 'static,
Arbi: Assign<T>,
{
let min = T::min_value();
let max = T::max_value();
test_integer_value(min.clone(), &min.to_string());
test_integer_value(max.clone(), &max.to_string());
}
#[test]
fn test_integral_types() {
test_integer::<i8>();
test_integer::<i16>();
test_integer::<i32>();
test_integer::<i64>();
test_integer::<i128>();
test_integer::<isize>();
test_integer::<u8>();
test_integer::<u16>();
test_integer::<u32>();
test_integer::<u64>();
test_integer::<u128>();
test_integer::<usize>();
}
trait MinMax {
fn min_value() -> Self;
fn max_value() -> Self;
}
macro_rules! impl_min_max_for_primitive {
($($t:ty),*) => {
$(
impl MinMax for $t {
fn min_value() -> Self {
<$t>::MIN
}
fn max_value() -> Self {
<$t>::MAX
}
}
)*
};
}
impl_min_max_for_primitive!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
);
}