cargo_show_asm/
callgraph.rs1use regex::Regex;
2use std::collections::{HashMap, HashSet, VecDeque};
3
4use crate::esafeprintln;
5
6#[derive(Debug, Clone, Default)]
7pub struct CallGraph<'a>(pub HashMap<&'a str, HashSet<&'a str>>);
9
10#[derive(Debug, Clone, Default)]
12pub struct InvCallGraph<'a>(pub HashMap<&'a str, HashSet<&'a str>>);
13
14impl<'a> CallGraph<'a> {
15 pub fn filter(&self, regex_str: &str, max_depth: usize) -> HashMap<&'a str, usize> {
16 let re = match Regex::new(regex_str) {
17 Ok(re) => re,
18 Err(err) => {
19 esafeprintln!("{err}");
20 std::process::exit(1);
21 }
22 };
23 self.invert()
24 .callers_of(&re)
25 .into_iter()
26 .filter(|(_, d)| *d <= max_depth)
27 .collect()
28 }
29
30 pub fn invert(&self) -> InvCallGraph<'a> {
31 let mut inv: HashMap<&str, HashSet<&str>> = HashMap::new();
32 for (&caller, callees) in &self.0 {
33 for &callee in callees {
34 inv.entry(callee).or_default().insert(caller);
35 }
36 }
37 InvCallGraph(inv)
38 }
39}
40
41impl<'a> InvCallGraph<'a> {
42 pub fn callers_of(&self, re: &Regex) -> HashMap<&'a str, usize> {
43 let mut depths: HashMap<&str, usize> = HashMap::new();
44 let mut queue: VecDeque<(&str, usize)> = VecDeque::new();
45
46 for &node in self.0.keys() {
47 if re.is_match(node) {
48 depths.insert(node, 0);
49 queue.push_back((node, 0));
50 }
51 }
52
53 while let Some((node, depth)) = queue.pop_front() {
54 if let Some(callers) = self.0.get(node) {
55 for &caller in callers {
56 use std::collections::hash_map::Entry;
57 if let Entry::Vacant(e) = depths.entry(caller) {
58 e.insert(depth + 1);
59 queue.push_back((caller, depth + 1));
60 }
61 }
62 }
63 }
64
65 depths
66 }
67}