1use std::cell::RefCell;
2use std::collections::{HashMap, HashSet};
3
4use crate::block::{BlockId, BlockRelation};
5
6#[derive(Debug, Clone, Default)]
8pub struct BlockRelationMap {
9 relations: RefCell<HashMap<BlockId, HashMap<BlockRelation, Vec<BlockId>>>>,
11}
12
13impl BlockRelationMap {
14 pub fn add_relation_impl(&self, from: BlockId, relation: BlockRelation, to: BlockId) {
16 let mut relations = self.relations.borrow_mut();
17 relations
18 .entry(from)
19 .or_default()
20 .entry(relation)
21 .or_default()
22 .push(to);
23 }
24
25 pub fn add_relation_impls(&self, from: BlockId, relation: BlockRelation, targets: &[BlockId]) {
27 let mut relations = self.relations.borrow_mut();
28 let block_relations = relations.entry(from).or_default();
29 let relation_vec = block_relations.entry(relation).or_default();
30 relation_vec.extend_from_slice(targets);
31 }
32
33 pub fn remove_relation_impl(
35 &self,
36 from: BlockId,
37 relation: BlockRelation,
38 to: BlockId,
39 ) -> bool {
40 let mut relations = self.relations.borrow_mut();
41 if let Some(block_relations) = relations.get_mut(&from) {
42 if let Some(targets) = block_relations.get_mut(&relation) {
43 if let Some(pos) = targets.iter().position(|&x| x == to) {
44 targets.remove(pos);
45 if targets.is_empty() {
47 block_relations.remove(&relation);
48 if block_relations.is_empty() {
50 relations.remove(&from);
51 }
52 }
53 return true;
54 }
55 }
56 }
57 false
58 }
59
60 pub fn remove_all_relations(&self, from: BlockId, relation: BlockRelation) -> Vec<BlockId> {
62 let mut relations = self.relations.borrow_mut();
63 if let Some(block_relations) = relations.get_mut(&from) {
64 if let Some(targets) = block_relations.remove(&relation) {
65 if block_relations.is_empty() {
67 relations.remove(&from);
68 }
69 return targets;
70 }
71 }
72 Vec::new()
73 }
74
75 pub fn remove_block_relations(&self, block_id: BlockId) {
77 let mut relations = self.relations.borrow_mut();
78 relations.remove(&block_id);
79 }
80
81 pub fn get_related(&self, from: BlockId, relation: BlockRelation) -> Vec<BlockId> {
83 self.relations
84 .borrow()
85 .get(&from)
86 .and_then(|block_relations| block_relations.get(&relation))
87 .cloned()
88 .unwrap_or_default()
89 }
90
91 pub fn get_all_relations(&self, from: BlockId) -> HashMap<BlockRelation, Vec<BlockId>> {
93 self.relations
94 .borrow()
95 .get(&from)
96 .cloned()
97 .unwrap_or_default()
98 }
99
100 pub fn has_relation(&self, from: BlockId, relation: BlockRelation, to: BlockId) -> bool {
102 self.relations
103 .borrow()
104 .get(&from)
105 .and_then(|block_relations| block_relations.get(&relation))
106 .map(|targets| targets.contains(&to))
107 .unwrap_or(false)
108 }
109
110 pub fn add_relation_if_not_exists(&self, from: BlockId, relation: BlockRelation, to: BlockId) {
112 let mut relations = self.relations.borrow_mut();
113 let block_relations = relations.entry(from).or_default();
114 let targets = block_relations.entry(relation).or_default();
115 if !targets.contains(&to) {
116 targets.push(to);
117 }
118 }
119
120 pub fn add_bidirectional_if_not_exists(&self, caller: BlockId, callee: BlockId) {
122 let mut relations = self.relations.borrow_mut();
123
124 let caller_relations = relations.entry(caller).or_default();
126 let caller_targets = caller_relations
127 .entry(BlockRelation::DependsOn)
128 .or_default();
129 if !caller_targets.contains(&callee) {
130 caller_targets.push(callee);
131 }
132
133 let callee_relations = relations.entry(callee).or_default();
135 let callee_targets = callee_relations
136 .entry(BlockRelation::DependedBy)
137 .or_default();
138 if !callee_targets.contains(&caller) {
139 callee_targets.push(caller);
140 }
141 }
142
143 pub fn has_relation_type(&self, from: BlockId, relation: BlockRelation) -> bool {
145 self.relations
146 .borrow()
147 .get(&from)
148 .and_then(|block_relations| block_relations.get(&relation))
149 .map(|targets| !targets.is_empty())
150 .unwrap_or(false)
151 }
152
153 pub fn get_connected_blocks(&self) -> Vec<BlockId> {
155 self.relations.borrow().keys().copied().collect()
156 }
157
158 pub fn get_all_related_blocks(&self, from: BlockId) -> HashSet<BlockId> {
160 let mut result = HashSet::new();
161 if let Some(block_relations) = self.relations.borrow().get(&from) {
162 for targets in block_relations.values() {
163 result.extend(targets.iter().copied());
164 }
165 }
166 result
167 }
168
169 pub fn find_reverse_relations(&self, to: BlockId, relation: BlockRelation) -> Vec<BlockId> {
171 let mut result = Vec::new();
172 let relations = self.relations.borrow();
173
174 for (&from_block, block_relations) in relations.iter() {
175 if let Some(targets) = block_relations.get(&relation) {
176 if targets.contains(&to) {
177 result.push(from_block);
178 }
179 }
180 }
181 result
182 }
183
184 pub fn stats(&self) -> RelationStats {
186 let relations = self.relations.borrow();
187 let mut total_relations = 0;
188 let mut by_relation: HashMap<BlockRelation, usize> = HashMap::new();
189
190 for block_relations in relations.values() {
191 for (&relation, targets) in block_relations.iter() {
192 by_relation
193 .entry(relation)
194 .and_modify(|count| *count += targets.len())
195 .or_insert_with(|| targets.len());
196 total_relations += targets.len();
197 }
198 }
199
200 RelationStats {
201 total_blocks: relations.len(),
202 total_relations,
203 by_relation,
204 }
205 }
206
207 pub fn clear(&self) {
209 self.relations.borrow_mut().clear();
210 }
211
212 pub fn is_empty(&self) -> bool {
214 self.relations.borrow().is_empty()
215 }
216
217 pub fn len(&self) -> usize {
219 self.relations.borrow().len()
220 }
221}
222
223pub struct RelationBuilder<'a> {
225 map: &'a BlockRelationMap,
226 from: BlockId,
227}
228
229impl<'a> RelationBuilder<'a> {
230 fn new(map: &'a BlockRelationMap, from: BlockId) -> Self {
231 Self { map, from }
232 }
233
234 pub fn calls(self, to: BlockId) -> Self {
236 self.map
237 .add_relation_impl(self.from, BlockRelation::DependsOn, to);
238 self
239 }
240
241 pub fn called_by(self, to: BlockId) -> Self {
243 self.map
244 .add_relation_impl(self.from, BlockRelation::DependedBy, to);
245 self
246 }
247
248 pub fn contains(self, to: BlockId) -> Self {
250 self.map
251 .add_relation_impl(self.from, BlockRelation::Unknown, to);
252 self
253 }
254
255 pub fn contained_by(self, to: BlockId) -> Self {
257 self.map
258 .add_relation_impl(self.from, BlockRelation::Unknown, to);
259 self
260 }
261
262 pub fn relation(self, relation: BlockRelation, to: BlockId) -> Self {
264 self.map.add_relation_impl(self.from, relation, to);
265 self
266 }
267
268 pub fn relations(self, relation: BlockRelation, targets: &[BlockId]) -> Self {
270 self.map.add_relation_impls(self.from, relation, targets);
271 self
272 }
273}
274
275impl BlockRelationMap {
276 pub fn from_block(&self, from: BlockId) -> RelationBuilder<'_> {
278 RelationBuilder::new(self, from)
279 }
280}
281
282#[derive(Debug, Default, Clone)]
284pub struct RelationStats {
285 pub total_blocks: usize,
286 pub total_relations: usize,
287 pub by_relation: HashMap<BlockRelation, usize>,
288}
289
290impl std::fmt::Display for RelationStats {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 writeln!(f, "Relation Stats:")?;
293 writeln!(f, " Total blocks with relations: {}", self.total_blocks)?;
294 writeln!(f, " Total relationships: {}", self.total_relations)?;
295 writeln!(f, " By type:")?;
296 for (&relation, &count) in &self.by_relation {
297 writeln!(f, " {}: {}", relation, count)?;
298 }
299 Ok(())
300 }
301}
302
303impl BlockRelationMap {
305 pub fn add_relation(&self, caller: BlockId, callee: BlockId) {
307 self.add_relation_impl(caller, BlockRelation::DependsOn, callee);
308 self.add_relation_impl(callee, BlockRelation::DependedBy, caller);
309 }
310
311 pub fn remove_relation(&self, caller: BlockId, callee: BlockId) {
313 self.remove_relation_impl(caller, BlockRelation::DependsOn, callee);
314 self.remove_relation_impl(callee, BlockRelation::DependedBy, caller);
315 }
316
317 pub fn get_depended(&self, block: BlockId) -> Vec<BlockId> {
318 self.get_related(block, BlockRelation::DependedBy)
319 }
320
321 pub fn get_depends(&self, block: BlockId) -> Vec<BlockId> {
322 self.get_related(block, BlockRelation::DependsOn)
323 }
324
325 pub fn get_children(&self, block: BlockId) -> Vec<BlockId> {
327 self.get_related(block, BlockRelation::Unknown)
328 }
329
330 pub fn get_parent(&self, block: BlockId) -> Option<BlockId> {
332 self.find_reverse_relations(block, BlockRelation::Unknown)
333 .into_iter()
334 .next()
335 }
336
337 pub fn get_ancestors(&self, mut block: BlockId) -> Vec<BlockId> {
339 let mut ancestors = Vec::new();
340 let mut visited = HashSet::new();
341
342 while let Some(parent) = self.get_parent(block) {
343 if visited.contains(&parent) {
344 break;
346 }
347 visited.insert(parent);
348 ancestors.push(parent);
349 block = parent;
350 }
351
352 ancestors
353 }
354
355 pub fn get_descendants(&self, block: BlockId) -> Vec<BlockId> {
357 let mut descendants = Vec::new();
358 let mut visited = HashSet::new();
359 let mut queue = vec![block];
360
361 while let Some(current) = queue.pop() {
362 if visited.contains(¤t) {
363 continue;
364 }
365 visited.insert(current);
366
367 let children = self.get_children(current);
368 descendants.extend(&children);
369 queue.extend(children);
370 }
371
372 descendants
373 }
374}