1use std::collections::BTreeMap;
2
3use crate::DynTapi;
4
5pub struct TypesBuilder {
6 pub prelude: String,
7 pub start_namespace: Box<dyn Fn(&[String], &str) -> String>,
8 pub end_namespace: Box<dyn Fn(&[String], &str) -> String>,
9 pub decl: Box<dyn Fn(DynTapi) -> Option<String>>,
10}
11
12impl TypesBuilder {
13 pub fn types(&self, tys: impl IntoIterator<Item = DynTapi>) -> String {
14 let mut s = self.prelude.trim_start().to_string();
15
16 pub struct Node<'a> {
17 path: Vec<String>,
18 builder: &'a TypesBuilder,
19 children: BTreeMap<String, Node<'a>>,
20 decls: Vec<DynTapi>,
21 }
22
23 let mut root = Node::new(Vec::new(), self);
24
25 for ty in tys {
26 let mut node = &mut root;
27 let mut path = Vec::new();
28 for p in ty.path() {
29 node = node
30 .children
31 .entry(p.to_string())
32 .or_insert_with(|| Node::new(path.clone(), self));
33 path.push(p.to_string());
34 }
35 node.decls.push(ty);
36 }
37
38 impl<'a> Node<'a> {
39 fn new(path: Vec<String>, builder: &'a TypesBuilder) -> Self {
40 Self {
41 builder,
42 path,
43 children: Default::default(),
44 decls: Default::default(),
45 }
46 }
47
48 fn write(&self, s: &mut String, indent: usize) {
49 for decl in &self.decls {
50 if let Some(decl) = (self.builder.decl)(*decl) {
51 for l in decl.lines() {
52 for _ in 0..indent {
53 s.push_str(" ");
54 }
55 s.push_str(l);
56 s.push('\n');
57 }
58 }
59 }
60 for (name, node) in &self.children {
61 for _ in 0..indent {
62 s.push_str(" ");
63 }
64 s.push_str(&(self.builder.start_namespace)(&node.path, name));
65 s.push('\n');
66 node.write(s, indent + 1);
67 for _ in 0..indent {
68 s.push_str(" ");
69 }
70 s.push_str(&(self.builder.end_namespace)(&node.path, name));
71 s.push('\n');
72 }
73 }
74 }
75
76 root.write(&mut s, 0);
77
78 s
79 }
80}