tapi/
builder.rs

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}