panproto_protocols/
emit.rs1use panproto_schema::{Constraint, Edge, Schema, Vertex};
8
9#[must_use]
13pub fn find_roots<'a>(schema: &'a Schema, structural_edge_kinds: &[&str]) -> Vec<&'a Vertex> {
14 let mut roots: Vec<&Vertex> = schema
15 .vertices
16 .values()
17 .filter(|v| {
18 let incoming = schema.incoming_edges(&v.id);
19 !incoming
20 .iter()
21 .any(|e| structural_edge_kinds.contains(&&*e.kind))
22 })
23 .collect();
24 roots.sort_by(|a, b| a.id.cmp(&b.id));
25 roots
26}
27
28#[must_use]
33pub fn children_by_edge<'a>(
34 schema: &'a Schema,
35 parent: &str,
36 edge_kind: &str,
37) -> Vec<(&'a Edge, &'a Vertex)> {
38 let mut children: Vec<(&Edge, &Vertex)> = schema
39 .outgoing_edges(parent)
40 .iter()
41 .filter(|e| e.kind == edge_kind)
42 .filter_map(|e| schema.vertices.get(&e.tgt).map(|v| (e, v)))
43 .collect();
44 children.sort_by(|a, b| {
45 let a_name = a.0.name.as_deref().unwrap_or("");
46 let b_name = b.0.name.as_deref().unwrap_or("");
47 a_name.cmp(b_name)
48 });
49 children
50}
51
52#[must_use]
54pub fn constraint_value<'a>(schema: &'a Schema, vertex_id: &str, sort: &str) -> Option<&'a str> {
55 schema
56 .constraints
57 .get(vertex_id)?
58 .iter()
59 .find(|c| c.sort == sort)
60 .map(|c| c.value.as_str())
61}
62
63#[must_use]
65pub fn vertex_constraints<'a>(schema: &'a Schema, vertex_id: &str) -> Vec<&'a Constraint> {
66 schema
67 .constraints
68 .get(vertex_id)
69 .map(|cs| cs.iter().collect())
70 .unwrap_or_default()
71}
72
73pub struct IndentWriter {
78 buf: String,
79 level: usize,
80 indent_str: &'static str,
81}
82
83impl IndentWriter {
84 #[must_use]
88 pub const fn new(indent_str: &'static str) -> Self {
89 Self {
90 buf: String::new(),
91 level: 0,
92 indent_str,
93 }
94 }
95
96 pub const fn indent(&mut self) {
98 self.level += 1;
99 }
100
101 pub const fn dedent(&mut self) {
103 self.level = self.level.saturating_sub(1);
104 }
105
106 pub fn line(&mut self, s: &str) {
108 for _ in 0..self.level {
109 self.buf.push_str(self.indent_str);
110 }
111 self.buf.push_str(s);
112 self.buf.push('\n');
113 }
114
115 pub fn blank(&mut self) {
117 self.buf.push('\n');
118 }
119
120 pub fn raw(&mut self, s: &str) {
122 self.buf.push_str(s);
123 }
124
125 #[must_use]
127 pub fn finish(self) -> String {
128 self.buf
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn indent_writer_basic() {
138 let mut w = IndentWriter::new(" ");
139 w.line("message Foo {");
140 w.indent();
141 w.line("string bar = 1;");
142 w.dedent();
143 w.line("}");
144 let result = w.finish();
145 assert_eq!(result, "message Foo {\n string bar = 1;\n}\n");
146 }
147}