pub mod store;
pub mod bitpack;
pub mod r#virtual;

/// 4-state logic value for a single bit.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Logic {
    Zero,
    One,
    X,
    Z,
}

/// A signal value at a given timestep.
#[derive(Clone, Debug, PartialEq)]
pub enum SignalValue {
    Scalar(u64),
    WideScalar(Vec<u64>),
    FourState(Vec<Logic>),
    Real(f64),
    Str(String),
    Unknown,
}

impl SignalValue {
    /// Returns true if this value is considered "truthy".
    pub fn is_truthy(&self) -> bool {
        match self {
            SignalValue::Scalar(v) => *v != 0,
            SignalValue::WideScalar(v) => v.iter().any(|&w| w != 0),
            SignalValue::FourState(bits) => bits.iter().any(|b| *b == Logic::One),
            SignalValue::Real(f) => *f != 0.0,
            SignalValue::Str(s) => !s.is_empty(),
            SignalValue::Unknown => false,
        }
    }

    /// Convert to u64 if possible.
    pub fn to_u64(&self) -> Option<u64> {
        match self {
            SignalValue::Scalar(v) => Some(*v),
            SignalValue::WideScalar(v) => v.first().copied(),
            SignalValue::FourState(bits) => {
                if bits.iter().any(|b| *b == Logic::X || *b == Logic::Z) {
                    return None;
                }
                let mut val: u64 = 0;
                for (i, b) in bits.iter().rev().enumerate() {
                    if i >= 64 {
                        break;
                    }
                    if *b == Logic::One {
                        val |= 1u64 << i;
                    }
                }
                Some(val)
            }
            SignalValue::Real(f) => Some(*f as u64),
            SignalValue::Str(s) => s.parse::<u64>().ok(),
            SignalValue::Unknown => None,
        }
    }

    /// Convert to i64 if possible.
    pub fn to_i64(&self) -> Option<i64> {
        self.to_u64().map(|v| v as i64)
    }
}
