1use std::fmt;
6
7use crate::ValueError;
8
9#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
11pub enum Logic {
12 Zero,
13 One,
14 X,
15 Z,
16}
17
18impl Logic {
19 pub fn from_char(c: char) -> Logic {
20 match c {
21 '0' => Logic::Zero,
22 '1' => Logic::One,
23 'z' | 'Z' => Logic::Z,
24 _ => Logic::X,
25 }
26 }
27 pub fn to_char(self) -> char {
28 match self {
29 Logic::Zero => '0',
30 Logic::One => '1',
31 Logic::X => 'x',
32 Logic::Z => 'z',
33 }
34 }
35 pub fn is_resolvable(self) -> bool {
36 matches!(self, Logic::Zero | Logic::One)
37 }
38}
39
40impl From<bool> for Logic {
41 fn from(b: bool) -> Logic {
42 if b { Logic::One } else { Logic::Zero }
43 }
44}
45
46impl fmt::Display for Logic {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 write!(f, "{}", self.to_char())
49 }
50}
51
52#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct LogicArray {
55 bits: Vec<Logic>,
56}
57
58impl LogicArray {
59 pub fn from_binstr(s: &str) -> LogicArray {
60 LogicArray { bits: s.chars().map(Logic::from_char).collect() }
61 }
62
63 pub fn from_u64(v: u64, width: usize) -> LogicArray {
64 let mut bits = Vec::with_capacity(width);
65 for i in (0..width).rev() {
66 bits.push(Logic::from((v >> i) & 1 == 1));
67 }
68 LogicArray { bits }
69 }
70
71 pub fn to_binstr(&self) -> String {
72 self.bits.iter().map(|b| b.to_char()).collect()
73 }
74
75 pub fn len(&self) -> usize {
76 self.bits.len()
77 }
78 pub fn is_empty(&self) -> bool {
79 self.bits.is_empty()
80 }
81
82 pub fn is_resolvable(&self) -> bool {
83 self.bits.iter().all(|b| b.is_resolvable())
84 }
85
86 pub fn bit(&self, i: usize) -> Option<Logic> {
88 self.bits.get(i).copied()
89 }
90
91 pub fn to_u64(&self) -> Result<u64, ValueError> {
92 let mut v: u64 = 0;
93 for b in &self.bits {
94 match b {
95 Logic::Zero => v <<= 1,
96 Logic::One => v = (v << 1) | 1,
97 _ => return Err(ValueError::FourState(self.to_binstr())),
98 }
99 }
100 Ok(v)
101 }
102}
103
104impl TryFrom<&LogicArray> for u64 {
105 type Error = ValueError;
106 fn try_from(v: &LogicArray) -> Result<u64, ValueError> {
107 v.to_u64()
108 }
109}
110
111impl fmt::Display for LogicArray {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(f, "{}", self.to_binstr())
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn roundtrip_u64() {
123 let v = LogicArray::from_u64(0xA5, 8);
124 assert_eq!(v.to_binstr(), "10100101");
125 assert_eq!(v.to_u64().unwrap(), 0xA5);
126 }
127
128 #[test]
129 fn four_state_rejected() {
130 let v = LogicArray::from_binstr("1x0z");
131 assert!(v.to_u64().is_err());
132 assert!(!v.is_resolvable());
133 }
134}