libgir/analysis/
class_hierarchy.rs
1use std::{
2 collections::{HashMap, HashSet},
3 iter,
4};
5
6use crate::library::*;
7
8#[derive(Debug)]
9struct Node {
10 supers: Vec<TypeId>,
11 subs: HashSet<TypeId>,
12}
13
14#[derive(Debug)]
15pub struct Info {
16 hier: HashMap<TypeId, Node>,
17}
18
19pub fn run(library: &Library) -> Info {
20 let mut hier = HashMap::new();
21 for (tid, _) in library.types() {
22 get_node(library, &mut hier, tid);
23 }
24 Info { hier }
25}
26
27fn get_node<'a>(
28 library: &Library,
29 hier: &'a mut HashMap<TypeId, Node>,
30 tid: TypeId,
31) -> Option<&'a mut Node> {
32 if hier.contains_key(&tid) {
33 return hier.get_mut(&tid);
34 }
35
36 let direct_supers: Vec<TypeId> = match library.type_(tid) {
37 Type::Class(Class {
38 parent, implements, ..
39 }) => parent.iter().chain(implements.iter()).copied().collect(),
40 Type::Interface(Interface { prerequisites, .. }) => prerequisites.clone(),
41 _ => return None,
42 };
43
44 let mut supers = Vec::new();
45 for super_ in direct_supers {
46 let node = get_node(library, hier, super_).expect("parent must be a class or interface");
47 node.subs.insert(tid);
48 for &tid in [super_].iter().chain(node.supers.iter()) {
49 if !supers.contains(&tid) {
50 supers.push(tid);
51 }
52 }
53 }
54
55 hier.insert(
56 tid,
57 Node {
58 supers,
59 subs: HashSet::new(),
60 },
61 );
62 hier.get_mut(&tid)
63}
64
65impl Info {
66 pub fn subtypes<'a>(&'a self, tid: TypeId) -> Box<dyn Iterator<Item = TypeId> + 'a> {
67 match self.hier.get(&tid) {
68 Some(node) => Box::new(node.subs.iter().copied()),
69 None => Box::new(iter::empty()),
70 }
71 }
72
73 pub fn supertypes(&self, tid: TypeId) -> &[TypeId] {
74 match self.hier.get(&tid) {
75 Some(node) => &node.supers,
76 None => &[],
77 }
78 }
79}