1use super::*;
2
3// This uses BTree rather than Hash as we're getting close to writing the tokens in sorted order.
4#[derive(Debug)]
5pub struct TypeTree {
6 pub namespace: &'static str,
7 pub nested: BTreeMap<&'static str, Self>,
8 pub types: BTreeSet<Type>,
9}
10
11impl TypeTree {
12 pub fn new(dependencies: &TypeMap) -> Self {
13 let mut tree = Self::with_namespace("");
14
15 for (tn, types) in dependencies.iter() {
16 let tree = tree.insert_namespace(tn.namespace());
17 types.iter().for_each(|ty| {
18 tree.types.insert(ty.clone());
19 });
20 }
21
22 tree
23 }
24
25 // This is used to provide a flat iterator of trees so that they can be processed in parallel.
26 pub fn flatten_trees(&self) -> Vec<&Self> {
27 let mut flatten = if self.namespace.is_empty() {
28 vec![]
29 } else {
30 vec![self]
31 };
32 flatten.extend(self.nested.values().flat_map(|tree| tree.flatten_trees()));
33 flatten
34 }
35
36 // This is used to actually remove the tree structure and just have a flat iterator or types
37 // that just happen to be sorted, thanks to BTreeSet, so that a flat list of types can be
38 // generated in sort order.
39 pub fn flatten_types(mut self) -> BTreeSet<Type> {
40 fn flatten(set: &mut BTreeSet<Type>, tree: &mut TypeTree) {
41 set.append(&mut tree.types);
42
43 for tree in tree.nested.values_mut() {
44 flatten(set, tree);
45 }
46 }
47
48 let mut types = BTreeSet::new();
49 flatten(&mut types, &mut self);
50 types
51 }
52
53 pub fn feature(&self) -> String {
54 self.namespace.split_once('.').unwrap().1.replace('.', "_")
55 }
56
57 fn with_namespace(namespace: &'static str) -> Self {
58 Self {
59 namespace,
60 nested: BTreeMap::new(),
61 types: BTreeSet::new(),
62 }
63 }
64
65 fn insert_namespace(&mut self, namespace: &'static str) -> &mut Self {
66 fn insert_namespace<'a>(
67 parent: &'a mut TypeTree,
68 namespace: &'static str,
69 pos: usize,
70 ) -> &'a mut TypeTree {
71 if let Some(next) = namespace[pos..].find('.') {
72 let next = pos + next;
73
74 let parent = parent
75 .nested
76 .entry(&namespace[pos..next])
77 .or_insert_with(|| TypeTree::with_namespace(&namespace[..next]));
78
79 insert_namespace(parent, namespace, next + 1)
80 } else {
81 parent
82 .nested
83 .entry(&namespace[pos..])
84 .or_insert_with(|| TypeTree::with_namespace(namespace))
85 }
86 }
87
88 if namespace.is_empty() {
89 self
90 } else {
91 insert_namespace(self, namespace, 0)
92 }
93 }
94}
95