use core::fmt;
use core::ops::*;
use num_traits::cast::ToPrimitive;
mod bigint;
use bigint::*;
use super::abstraction::*;
#[cfg(feature = "macros")]
pub use hax_lib_macros::int;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct Int(BigInt);
impl fmt::Display for Int {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.get())
}
}
impl Int {
fn new(x: impl Into<num_bigint::BigInt>) -> Self {
Int(BigInt::new(&x.into()))
}
fn get(self) -> num_bigint::BigInt {
self.0.get()
}
}
impl Add for Int {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self::new(self.get() + other.get())
}
}
impl Neg for Int {
type Output = Self;
fn neg(self) -> Self::Output {
Self::new(-self.get())
}
}
impl Sub for Int {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self::new(self.get() - other.get())
}
}
impl Mul for Int {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
Self::new(self.get() * other.get())
}
}
impl Div for Int {
type Output = Self;
fn div(self, other: Self) -> Self::Output {
Self::new(self.get() / other.get())
}
}
impl Int {
pub fn pow2(self) -> Self {
let exponent = self.get().to_u32().expect("Exponent doesn't fit in a u32");
Self::new(num_bigint::BigInt::from(2u8).pow(exponent))
}
pub fn _unsafe_from_str(s: &str) -> Self {
use core::str::FromStr;
Self::new(num_bigint::BigInt::from_str(s).unwrap())
}
pub fn rem_euclid(&self, v: Self) -> Self {
use num_traits::Euclid;
Self::new(self.get().rem_euclid(&v.get()))
}
}
#[cfg(feature = "macros")]
pub trait ToInt {
fn to_int(self) -> Int;
}
macro_rules! implement_abstraction {
($ty:ident) => {
impl Abstraction for $ty {
type AbstractType = Int;
fn lift(self) -> Self::AbstractType {
Int::new(num_bigint::BigInt::from(self))
}
}
impl ToInt for $ty {
fn to_int(self) -> Int {
self.lift()
}
}
};
($($ty:ident)*) => {
$(implement_abstraction!($ty);)*
};
}
implement_abstraction!(u8 u16 u32 u64 u128 usize);
implement_abstraction!(i8 i16 i32 i64 i128 isize);
macro_rules! implement_concretize {
($ty:ident $method:ident) => {
impl Concretization<$ty> for Int {
fn concretize(self) -> $ty {
let concretized = self.get().$method();
debug_assert!(concretized.is_some());
concretized.unwrap().into()
}
}
impl Int {
pub fn $method(self) -> $ty {
self.concretize()
}
}
};
($ty:ident $method:ident, $($tt:tt)*) => {
implement_concretize!($ty $method);
implement_concretize!($($tt)*);
};
() => {};
}
implement_concretize!(
u8 to_u8,
u16 to_u16,
u32 to_u32,
u64 to_u64,
u128 to_u128,
usize to_usize,
i8 to_i8,
i16 to_i16,
i32 to_i32,
i64 to_i64,
i128 to_i128,
isize to_isize,
);