1use crate::token::{BoolOp, Source};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Node {
12 pub id: u16,
14 pub op: BoolOp,
16 pub left: Source,
18 pub right: Source,
20}
21
22impl Node {
23 pub fn new(id: u16, op: BoolOp, left: Source, right: Source) -> Self {
25 Self {
26 id,
27 op,
28 left,
29 right,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Default, PartialEq, Eq)]
44pub struct Graph {
45 pub inputs: Vec<u16>,
47 pub nodes: Vec<Node>,
49 pub outputs: Vec<u16>,
51}
52
53impl Graph {
54 pub fn new() -> Self {
56 Self::default()
57 }
58
59 pub fn node_count(&self) -> usize {
61 self.nodes.len()
62 }
63
64 pub fn input_count(&self) -> usize {
66 self.inputs.len()
67 }
68
69 pub fn output_count(&self) -> usize {
71 self.outputs.len()
72 }
73
74 pub fn depth(&self) -> usize {
80 if self.nodes.is_empty() {
81 return 0;
82 }
83
84 let mut depths = std::collections::HashMap::new();
88
89 for &id in &self.inputs {
91 depths.insert(id, 0usize);
92 }
93
94 for node in &self.nodes {
96 let left_depth = self.source_depth(&node.left, &depths);
97 let right_depth = self.source_depth(&node.right, &depths);
98 let node_depth = 1 + left_depth.max(right_depth);
99 depths.insert(node.id, node_depth);
100 }
101
102 self.outputs
104 .iter()
105 .filter_map(|id| depths.get(id).copied())
106 .max()
107 .unwrap_or(0)
108 }
109
110 fn source_depth(
112 &self,
113 source: &Source,
114 depths: &std::collections::HashMap<u16, usize>,
115 ) -> usize {
116 match source {
117 Source::Id(id) => depths.get(id).copied().unwrap_or(0),
118 Source::True | Source::False => 0,
119 }
120 }
121
122 pub fn is_input(&self, id: u16) -> bool {
124 self.inputs.contains(&id)
125 }
126
127 pub fn get_node(&self, id: u16) -> Option<&Node> {
129 self.nodes.iter().find(|n| n.id == id)
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn test_empty_graph_depth() {
139 let graph = Graph::new();
140 assert_eq!(graph.depth(), 0);
141 }
142
143 #[test]
144 fn test_single_node_depth() {
145 let graph = Graph {
146 inputs: vec![0, 1],
147 nodes: vec![Node::new(2, BoolOp::Or, Source::Id(0), Source::Id(1))],
148 outputs: vec![2],
149 };
150 assert_eq!(graph.depth(), 1);
151 }
152
153 #[test]
154 fn test_chain_depth() {
155 let graph = Graph {
157 inputs: vec![0],
158 nodes: vec![
159 Node::new(1, BoolOp::Or, Source::Id(0), Source::True),
160 Node::new(2, BoolOp::Or, Source::Id(1), Source::False),
161 ],
162 outputs: vec![2],
163 };
164 assert_eq!(graph.depth(), 2);
165 }
166
167 #[test]
168 fn test_parallel_depth() {
169 let graph = Graph {
171 inputs: vec![0, 1],
172 nodes: vec![
173 Node::new(2, BoolOp::Or, Source::Id(0), Source::True),
174 Node::new(3, BoolOp::Or, Source::Id(1), Source::False),
175 ],
176 outputs: vec![2, 3],
177 };
178 assert_eq!(graph.depth(), 1);
179 }
180}