use std::{
fmt::Debug,
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub},
};
use mck::{
concr::{self, IntoMck},
misc::{CBound, PANIC_MSG_DIV_BY_ZERO, PANIC_MSG_REM_BY_ZERO},
};
use crate::{traits::Ext, Bitvector, Unsigned};
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct Signed<const W: u32>(pub(super) concr::SignedBitvector<CBound<W>>);
impl<const W: u32> Signed<W> {
pub fn new(value: i64) -> Self {
Self(concr::SignedBitvector::new(value, CBound))
}
}
impl<const W: u32> Not for Signed<W> {
type Output = Self;
fn not(self) -> Self::Output {
Self(!self.0)
}
}
impl<const W: u32> BitAnd<Signed<W>> for Signed<W> {
type Output = Self;
fn bitand(self, rhs: Signed<W>) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl<const W: u32> BitOr<Signed<W>> for Signed<W> {
type Output = Self;
fn bitor(self, rhs: Signed<W>) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl<const W: u32> BitXor<Signed<W>> for Signed<W> {
type Output = Self;
fn bitxor(self, rhs: Signed<W>) -> Self::Output {
Self(self.0 ^ rhs.0)
}
}
impl<const W: u32> Add<Signed<W>> for Signed<W> {
type Output = Self;
fn add(self, rhs: Signed<W>) -> Self::Output {
Self(self.0.add(rhs.0))
}
}
impl<const W: u32> Sub<Signed<W>> for Signed<W> {
type Output = Self;
fn sub(self, rhs: Signed<W>) -> Self::Output {
Self(self.0.sub(rhs.0))
}
}
impl<const W: u32> Mul<Signed<W>> for Signed<W> {
type Output = Self;
fn mul(self, rhs: Signed<W>) -> Self::Output {
Self(self.0.mul(rhs.0))
}
}
impl<const W: u32> Div<Signed<W>> for Signed<W> {
type Output = Self;
fn div(self, rhs: Signed<W>) -> Self::Output {
let panic_result = self.0.div(rhs.0);
if panic_result.panic.is_nonzero() {
panic!("{}", PANIC_MSG_DIV_BY_ZERO)
}
Self(panic_result.result)
}
}
impl<const W: u32> Rem<Signed<W>> for Signed<W> {
type Output = Self;
fn rem(self, rhs: Signed<W>) -> Self::Output {
let panic_result = self.0.rem(rhs.0);
if panic_result.panic.is_nonzero() {
panic!("{}", PANIC_MSG_REM_BY_ZERO)
}
Self(panic_result.result)
}
}
impl<const W: u32> Shl<Signed<W>> for Signed<W> {
type Output = Self;
fn shl(self, rhs: Signed<W>) -> Self::Output {
Self(self.0.shl(rhs.0))
}
}
impl<const W: u32> Shr<Signed<W>> for Signed<W> {
type Output = Self;
fn shr(self, rhs: Signed<W>) -> Self::Output {
Self(self.0.shr(rhs.0))
}
}
impl<const W: u32, const X: u32> Ext<X> for Signed<W> {
type Output = Signed<X>;
fn ext(self) -> Self::Output {
Signed(self.0.ext(CBound::<X>))
}
}
impl<const W: u32> PartialOrd for Signed<W> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<const W: u32> Ord for Signed<W> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<const W: u32> From<Unsigned<W>> for Signed<W> {
fn from(value: Unsigned<W>) -> Self {
Self(value.0.cast_bitvector().as_signed())
}
}
impl<const W: u32> From<Bitvector<W>> for Signed<W> {
fn from(value: Bitvector<W>) -> Self {
Self(value.0.as_signed())
}
}
impl<const W: u32> Debug for Signed<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.0, f)
}
}
#[doc(hidden)]
impl<const W: u32> IntoMck for Signed<W> {
type Type = mck::concr::Bitvector<W>;
fn into_mck(self) -> Self::Type {
self.0.cast_bitvector()
}
}