use std::fmt;
use std::ops::{BitXor, BitXorAssign, Not};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
pub struct Signal {
a: u32,
}
impl Signal {
pub fn zero() -> Signal {
Signal { a: 0 }
}
pub fn one() -> Signal {
Signal { a: 1 }
}
pub(crate) fn placeholder() -> Signal {
Signal { a: 0x8000_0000 }
}
pub fn from_var(v: u32) -> Signal {
Self::from_ind(v + 1)
}
pub fn from_input(v: u32) -> Signal {
Self::from_ind(!v)
}
pub(crate) fn from_ind(v: u32) -> Signal {
Signal { a: v << 1 }
}
pub fn var(&self) -> u32 {
assert!(self.is_var());
self.ind() - 1u32
}
pub fn input(&self) -> u32 {
assert!(self.is_input());
!self.ind() & !0x8000_0000
}
pub fn ind(&self) -> u32 {
self.a >> 1
}
pub fn is_constant(&self) -> bool {
self.ind() == 0
}
pub fn is_input(&self) -> bool {
self.a & 0x8000_0000 != 0
}
pub fn is_var(&self) -> bool {
!self.is_input() && !self.is_constant()
}
pub(crate) fn without_inversion(&self) -> Signal {
Signal { a: self.a & !1u32 }
}
pub fn is_inverted(&self) -> bool {
self.a & 1 != 0
}
pub fn raw(&self) -> u32 {
self.a
}
pub(crate) fn remap_order(&self, t: &[Signal]) -> Signal {
if !self.is_var() {
*self
} else {
t[self.var() as usize] ^ self.is_inverted()
}
}
}
impl From<bool> for Signal {
fn from(b: bool) -> Signal {
if b {
Signal::one()
} else {
Signal::zero()
}
}
}
impl Not for Signal {
type Output = Signal;
fn not(self) -> Signal {
Signal { a: self.a ^ 1u32 }
}
}
impl Not for &'_ Signal {
type Output = Signal;
fn not(self) -> Signal {
Signal { a: self.a ^ 1u32 }
}
}
impl BitXorAssign<bool> for Signal {
fn bitxor_assign(&mut self, rhs: bool) {
self.a ^= rhs as u32;
}
}
impl BitXor<bool> for Signal {
type Output = Signal;
fn bitxor(self, rhs: bool) -> Self::Output {
let mut l = self;
l ^= rhs;
l
}
}
impl BitXor<bool> for &'_ Signal {
type Output = Signal;
fn bitxor(self, rhs: bool) -> Self::Output {
let mut l = *self;
l ^= rhs;
l
}
}
impl BitXor<&bool> for Signal {
type Output = Signal;
fn bitxor(self, rhs: &bool) -> Self::Output {
self ^ *rhs
}
}
impl BitXor<&bool> for &'_ Signal {
type Output = Signal;
fn bitxor(self, rhs: &bool) -> Self::Output {
self ^ *rhs
}
}
impl fmt::Display for Signal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_constant() {
let a = self.a & 1;
write!(f, "{a}")
} else {
if self.is_inverted() {
write!(f, "!")?;
}
if *self == Signal::placeholder() {
write!(f, "##")
} else if self.is_input() {
let v = self.input();
write!(f, "i{v}")
} else {
let v = self.var();
write!(f, "x{v}")
}
}
}
}
impl fmt::Debug for Signal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constant() {
let l0 = Signal::zero();
let l1 = Signal::one();
assert_eq!(l0, !l1);
assert_eq!(l1, !l0);
assert!(!l0.is_inverted());
assert!(l1.is_inverted());
assert_eq!(format!("{l0}"), "0");
assert_eq!(format!("{l1}"), "1");
}
#[test]
fn test_var() {
for v in 0u32..10u32 {
let l = Signal::from_var(v);
assert!(l.is_var());
assert!(!l.is_constant());
assert!(!l.is_input());
assert_eq!(l.var(), v);
assert_eq!((!l).var(), v);
assert!(!l.is_inverted());
assert!((!l).is_inverted());
assert_eq!(l ^ false, l);
assert_eq!(l ^ true, !l);
assert_eq!(format!("{l}"), format!("x{v}"));
}
}
#[test]
fn test_input() {
for v in 0u32..10u32 {
let l = Signal::from_input(v);
assert!(!l.is_var());
assert!(!l.is_constant());
assert!(l.is_input());
assert_eq!(l.input(), v);
assert_eq!((!l).input(), v);
assert!(!l.is_inverted());
assert!((!l).is_inverted());
assert_eq!(l ^ false, l);
assert_eq!(l ^ true, !l);
assert_eq!(format!("{l}"), format!("i{v}"));
}
}
#[test]
fn test_placeholder() {
let s = Signal::placeholder();
assert!(s.is_input());
assert_eq!(s.input(), 0x3fff_ffff);
assert_eq!(format!("{s}"), "##");
}
#[test]
fn test_comparison() {
assert_eq!(Signal::from(false), Signal::zero());
assert_eq!(Signal::from(true), Signal::one());
assert_ne!(Signal::from(false), Signal::one());
assert_ne!(Signal::from(true), Signal::zero());
assert_ne!(Signal::from_var(0), Signal::one());
assert_ne!(Signal::from_var(0), Signal::zero());
assert_ne!(Signal::from_var(0), Signal::from_var(1));
assert_ne!(Signal::from_var(0), Signal::from_var(1));
assert_ne!(Signal::from_input(0), Signal::from_var(0));
assert_ne!(Signal::from_input(0), Signal::from_var(0));
assert_ne!(Signal::from_input(0), Signal::one());
assert_ne!(Signal::from_input(0), Signal::zero());
assert_eq!(Signal::zero() ^ false, Signal::zero());
assert_eq!(Signal::zero() ^ true, Signal::one());
assert_eq!(Signal::one() ^ false, Signal::one());
assert_eq!(Signal::one() ^ true, Signal::zero());
}
}