1use crate::Nothing;
2
3use super::guard::{Guard, PortComp};
4use super::{Port, RRC};
5
6#[derive(Debug, Copy, Clone)]
7pub struct GuardRef(u32);
8
9impl GuardRef {
10 pub fn is_true(&self) -> bool {
13 self.0 == 0
14 }
15
16 pub fn index(&self) -> u32 {
19 self.0
20 }
21}
22
23#[derive(Debug, Clone)]
24pub enum FlatGuard {
25 Or(GuardRef, GuardRef),
26 And(GuardRef, GuardRef),
27 Not(GuardRef),
28 True,
29 CompOp(PortComp, RRC<Port>, RRC<Port>),
30 Port(RRC<Port>),
31}
32
33impl FlatGuard {
34 pub fn is_true(&self) -> bool {
35 match self {
36 FlatGuard::True => true,
37 FlatGuard::Port(p) => p.borrow().is_constant(1, 1),
38 _ => false,
39 }
40 }
41}
42
43pub struct GuardPool(Vec<FlatGuard>);
54
55impl GuardPool {
56 pub fn new() -> Self {
57 let mut vec = Vec::<FlatGuard>::with_capacity(1024);
58 vec.push(FlatGuard::True);
59 Self(vec)
60 }
61
62 fn add(&mut self, guard: FlatGuard) -> GuardRef {
63 if guard.is_true() {
65 return GuardRef(0);
66 }
67
68 self.0.push(guard);
69 GuardRef(
70 (self.0.len() - 1)
71 .try_into()
72 .expect("too many guards in the pool"),
73 )
74 }
75
76 pub fn flatten(&mut self, old: &Guard<Nothing>) -> GuardRef {
77 match old {
78 Guard::Or(l, r) => {
79 let flat_l = self.flatten(l);
80 let flat_r = self.flatten(r);
81 self.add(FlatGuard::Or(flat_l, flat_r))
82 }
83 Guard::And(l, r) => {
84 let flat_l = self.flatten(l);
85 let flat_r = self.flatten(r);
86 self.add(FlatGuard::And(flat_l, flat_r))
87 }
88 Guard::Not(g) => {
89 let flat_g = self.flatten(g);
90 self.add(FlatGuard::Not(flat_g))
91 }
92 Guard::True => self.add(FlatGuard::True),
93 Guard::CompOp(op, l, r) => {
94 self.add(FlatGuard::CompOp(op.clone(), l.clone(), r.clone()))
95 }
96 Guard::Port(p) => self.add(FlatGuard::Port(p.clone())),
97 Guard::Info(_) => {
98 panic!("flat guard sees info, think about this more")
99 }
100 }
101 }
102
103 pub fn get(&self, guard: GuardRef) -> &FlatGuard {
104 &self.0[guard.0 as usize]
105 }
106
107 #[cfg(debug_assertions)]
108 pub fn display(&self, guard: &FlatGuard) -> String {
109 match guard {
110 FlatGuard::Or(l, r) => format!(
111 "({} | {})",
112 self.display(self.get(*l)),
113 self.display(self.get(*r))
114 ),
115 FlatGuard::And(l, r) => format!(
116 "({} & {})",
117 self.display(self.get(*l)),
118 self.display(self.get(*r))
119 ),
120 FlatGuard::Not(g) => format!("!{}", self.display(self.get(*g))),
121 FlatGuard::True => "true".to_string(),
122 FlatGuard::CompOp(op, l, r) => {
123 let op_str = match op {
124 PortComp::Eq => "==",
125 PortComp::Neq => "!=",
126 PortComp::Lt => "<",
127 PortComp::Leq => "<=",
128 PortComp::Gt => ">",
129 PortComp::Geq => ">=",
130 };
131 format!(
132 "({} {} {})",
133 l.borrow().canonical(),
134 op_str,
135 r.borrow().canonical()
136 )
137 }
138 FlatGuard::Port(p) => format!("{}", p.borrow().canonical()),
139 }
140 }
141
142 pub fn iter(&self) -> impl Iterator<Item = (GuardRef, &FlatGuard)> {
144 self.0
145 .iter()
146 .enumerate()
147 .map(|(i, g)| (GuardRef(i.try_into().unwrap()), g))
148 }
149}
150
151impl Default for GuardPool {
152 fn default() -> Self {
153 Self::new()
154 }
155}