use crate::{
bits::Boolean,
integers::uint::{UInt128, UInt16, UInt32, UInt64, UInt8},
traits::integers::Integer,
};
use std::fmt::Debug;
macro_rules! int_impl {
($name: ident, $type_: ty, $uname_: ty, $utype_: ty, $size: expr) => {
#[derive(Clone, Debug)]
pub struct $name {
pub bits: Vec<Boolean>,
pub value: Option<$type_>,
}
impl Integer for $name {
type IntegerType = $type_;
type UnsignedGadget = $uname_;
type UnsignedIntegerType = $utype_;
const SIZE: usize = $size;
fn constant(value: $type_) -> Self {
let mut bits = Vec::with_capacity($size);
for i in 0..$size {
let mask = 1 << i as $type_;
let result = value & mask;
if result == mask {
bits.push(Boolean::constant(true))
} else {
bits.push(Boolean::constant(false))
}
}
Self {
bits,
value: Some(value),
}
}
fn one() -> Self {
Self::constant(1 as $type_)
}
fn zero() -> Self {
Self::constant(0 as $type_)
}
fn new(bits: Vec<Boolean>, value: Option<Self::IntegerType>) -> Self {
Self { bits, value }
}
fn is_constant(&self) -> bool {
self.bits.iter().all(|bit| matches!(bit, Boolean::Constant(_)))
}
fn to_bits_le(&self) -> Vec<Boolean> {
self.bits.clone()
}
fn to_bits_be(&self) -> Vec<Boolean> {
debug_assert_eq!(self.bits.len(), $size);
let mut res = self.bits.clone();
res.reverse();
res
}
fn from_bits_le(bits: &[Boolean]) -> Self {
assert_eq!(bits.len(), $size);
let bits = bits.to_vec();
let mut value = Some(0 as $utype_);
for b in bits.iter().rev() {
value.as_mut().map(|v| *v <<= 1);
match *b {
Boolean::Constant(b) => {
if b {
value.as_mut().map(|v| *v |= 1);
}
}
Boolean::Is(ref b) => match b.get_value() {
Some(true) => {
value.as_mut().map(|v| *v |= 1);
}
Some(false) => {}
None => value = None,
},
Boolean::Not(ref b) => match b.get_value() {
Some(false) => {
value.as_mut().map(|v| *v |= 1);
}
Some(true) => {}
None => value = None,
},
}
}
Self {
value: value.map(|x| x as $type_),
bits,
}
}
fn get_value(&self) -> Option<String> {
self.value.map(|num| num.to_string())
}
}
};
}
int_impl!(Int8, i8, UInt8, u8, 8);
int_impl!(Int16, i16, UInt16, u16, 16);
int_impl!(Int32, i32, UInt32, u32, 32);
int_impl!(Int64, i64, UInt64, u64, 64);
int_impl!(Int128, i128, UInt128, u128, 128);