_diffctx/edges/structural/
containment.rs1use std::path::Path;
2
3use rustc_hash::FxHashMap;
4
5use crate::config::weights::EDGE_WEIGHTS;
6use crate::types::Fragment;
7
8use super::super::EdgeDict;
9use super::super::base::{EdgeBuilder, add_edge};
10
11pub struct ContainmentEdgeBuilder;
12
13impl EdgeBuilder for ContainmentEdgeBuilder {
14 fn build(&self, fragments: &[Fragment], _repo_root: Option<&Path>) -> EdgeDict {
15 let weight = EDGE_WEIGHTS["containment"].forward;
16 let reverse_factor = EDGE_WEIGHTS["containment"].reverse_factor;
17
18 let mut by_path: FxHashMap<&str, Vec<&Fragment>> = FxHashMap::default();
19 for f in fragments {
20 by_path.entry(f.path()).or_default().push(f);
21 }
22
23 let mut edges: EdgeDict = FxHashMap::default();
24
25 let star_on = std::env::var_os("DIFFCTX_FILE_STAR").is_some();
29 let reps = if star_on {
30 super::super::base::file_representatives(fragments)
31 } else {
32 FxHashMap::default()
33 };
34
35 for (path, frags) in &by_path {
36 if frags.len() < 2 {
37 continue;
38 }
39 let mut sorted = frags.clone();
40 sorted.sort_by(|a, b| {
41 a.start_line()
42 .cmp(&b.start_line())
43 .then(b.end_line().cmp(&a.end_line()))
44 });
45
46 let mut stack: Vec<&Fragment> = Vec::new();
47
48 for f in &sorted {
49 while let Some(top) = stack.last() {
50 if f.start_line() > top.end_line() {
51 stack.pop();
52 } else {
53 break;
54 }
55 }
56
57 if let Some(parent) = stack.last() {
58 if parent.start_line() <= f.start_line()
59 && f.end_line() <= parent.end_line()
60 && parent.id != f.id
61 {
62 add_edge(&mut edges, &f.id, &parent.id, weight, reverse_factor);
63 }
64 }
65
66 stack.push(f);
67 }
68
69 if star_on {
76 if let Some(rep) = reps.get(*path) {
77 for f in &sorted {
78 if f.id != *rep {
79 add_edge(&mut edges, &f.id, rep, weight, reverse_factor);
80 }
81 }
82 }
83 }
84 }
85
86 edges
87 }
88}