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}