use std::convert::TryInto;
use std::ops::{BitAnd, BitOr, BitXor, Index, IndexMut};
use crate::{Ieee1164, Ieee1164Value};
macro_rules! expand_op_logicvector {
($func_name:ident, $trait_name:ident, $fn_name:ident) => {
expand_op!(
$func_name,
$trait_name,
$fn_name,
LogicVector,
LogicVector,
Option<LogicVector>
);
};
}
#[derive(Debug, Clone)]
pub struct LogicVector {
inner: Vec<Ieee1164>,
}
impl LogicVector {
pub fn new_with_width(n: usize) -> Self {
LogicVector {
inner: vec![Ieee1164::default(); n],
}
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn set_len(&mut self, new_len: usize) {
self.inner.resize(new_len, Ieee1164::default());
}
}
impl Index<usize> for LogicVector {
type Output = Ieee1164;
fn index(&self, index: usize) -> &<Self as Index<usize>>::Output {
&self.inner[index]
}
}
impl IndexMut<usize> for LogicVector {
fn index_mut(&mut self, index: usize) -> &mut <Self as Index<usize>>::Output {
&mut self.inner[index]
}
}
fn and(lhs: &LogicVector, rhs: &LogicVector) -> Option<LogicVector> {
if lhs.len() != rhs.len() {
return None;
}
Some(
lhs.inner
.iter()
.zip(rhs.inner.iter())
.map(|(l, r)| l & r)
.collect::<Vec<_>>()
.into(),
)
}
expand_op_logicvector!(and, BitAnd, bitand);
fn or(lhs: &LogicVector, rhs: &LogicVector) -> Option<LogicVector> {
if lhs.len() != rhs.len() {
return None;
}
Some(
lhs.inner
.iter()
.zip(rhs.inner.iter())
.map(|(l, r)| l | r)
.collect::<Vec<_>>()
.into(),
)
}
expand_op_logicvector!(or, BitOr, bitor);
fn xor(lhs: &LogicVector, rhs: &LogicVector) -> Option<LogicVector> {
if lhs.len() != rhs.len() {
return None;
}
Some(
lhs.inner
.iter()
.zip(rhs.inner.iter())
.map(|(l, r)| l ^ r)
.collect::<Vec<_>>()
.into(),
)
}
expand_op_logicvector!(xor, BitXor, bitxor);
impl TryInto<LogicVector> for &str {
type Error = ();
fn try_into(self) -> Result<LogicVector, ()> {
if let Some(v) = self.chars().try_fold(vec![], |mut v, c| {
v.push(c.try_into().ok()?);
Some(v)
}) {
Ok(v.into())
} else {
Err(())
}
}
}
impl Into<LogicVector> for Vec<Ieee1164> {
fn into(self) -> LogicVector {
LogicVector { inner: self }
}
}
impl PartialEq for LogicVector {
fn eq(&self, other: &LogicVector) -> bool {
self.inner.iter().zip(other.inner.iter()).all(|(a, b)| a == b)
}
}
impl Eq for LogicVector {}
#[allow(non_snake_case)]
impl LogicVector {
pub fn has_U(&self) -> bool {
self.inner.contains(&Ieee1164::Uninitialized)
}
pub fn has_X(&self) -> bool {
self.inner.contains(&Ieee1164::Strong(Ieee1164Value::Unknown))
}
pub fn has_0(&self) -> bool {
self.inner.contains(&Ieee1164::Strong(Ieee1164Value::Zero))
}
pub fn has_1(&self) -> bool {
self.inner.contains(&Ieee1164::Strong(Ieee1164Value::One))
}
pub fn has_Z(&self) -> bool {
self.inner.contains(&Ieee1164::HighImpedance)
}
pub fn has_W(&self) -> bool {
self.inner.contains(&Ieee1164::Weak(Ieee1164Value::Unknown))
}
pub fn has_D(&self) -> bool {
self.inner.contains(&Ieee1164::DontCare)
}
pub fn has_L(&self) -> bool {
self.inner.contains(&Ieee1164::Weak(Ieee1164Value::Zero))
}
pub fn has_H(&self) -> bool {
self.inner.contains(&Ieee1164::Weak(Ieee1164Value::One))
}
}