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