logical 0.2.1

Library for simulating digital circuit networks.
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))
    }
}