use crate::macros::for_all_ints_with_metadata;
use crate::Digit;
use core::ops::Shr;
#[derive(Debug, Clone, Copy)]
pub(crate) struct ArbiLikeArray<const N: usize> {
digits: [Digit; N],
length: usize,
is_neg: bool,
}
#[allow(dead_code)]
pub(crate) trait IntoArbiLikeArray<const N: usize> {
fn into_arbi_like_array(self) -> ArbiLikeArray<N>;
}
impl<const N: usize> ArbiLikeArray<N> {
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn digits(&self) -> &[Digit] {
&self.digits[..self.length]
}
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn length(&self) -> usize {
self.length
}
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn is_negative(&self) -> bool {
self.is_neg
}
}
macro_rules! impl_into_arbi_like_array {
($(($int:ty, $uint:ty, $max_size:expr)),*) => {
$(
impl IntoArbiLikeArray<$max_size> for $int {
#[allow(unused_comparisons)]
fn into_arbi_like_array(self) -> ArbiLikeArray<$max_size> {
if self == 0 {
return ArbiLikeArray {
digits: [0; $max_size],
length: 0,
is_neg: false,
};
}
let is_neg = self < 0;
let mut value = if is_neg {
(0 as $uint).wrapping_sub(self as $uint)
} else {
self as $uint
};
if Digit::BITS >= <$uint>::BITS {
ArbiLikeArray {
digits: [value as Digit; $max_size],
length: 1,
is_neg,
}
} else {
let mut digits = [0 as Digit; $max_size];
let mut length = 0;
while value != 0 {
digits[length] = (value & (Digit::MAX as $uint)) as Digit;
value = value.shr(Digit::BITS); length += 1;
}
ArbiLikeArray {
digits,
length,
is_neg,
}
}
}
}
)*
};
}
for_all_ints_with_metadata!(impl_into_arbi_like_array);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zero() {
let x: i32 = 0;
let stack = x.into_arbi_like_array();
assert_eq!(stack.length(), 0);
assert_eq!(stack.is_negative(), false);
assert!(stack.digits().is_empty());
}
#[test]
fn test_positive() {
let x: i32 = 42;
let stack = x.into_arbi_like_array();
assert_eq!(stack.length(), 1);
assert_eq!(stack.is_negative(), false);
assert_eq!(stack.digits(), &[42]);
}
#[test]
fn test_negative() {
let x: i32 = -42;
let stack = x.into_arbi_like_array();
assert_eq!(stack.length(), 1);
assert_eq!(stack.is_negative(), true);
assert_eq!(stack.digits(), &[42]);
}
#[test]
fn test_large_unsigned() {
let x: u64 = 0xFFFF_FFFF_0000_0000;
let stack = x.into_arbi_like_array();
assert_eq!(stack.length(), 2);
assert_eq!(stack.is_negative(), false);
assert_eq!(stack.digits(), &[0, 0xFFFF_FFFF]);
}
}
macro_rules! impl_from_int {
($(($int:ty, $uint:ty, $max_size:expr)),*) => {
$(
impl From<$int> for ArbiLikeArray<$max_size> {
fn from(value: $int) -> Self {
value.into_arbi_like_array()
}
}
)*
};
}
for_all_ints_with_metadata!(impl_from_int);