protoc_gen_prost_crate/generator/
include_file.rs1use std::rc::Rc;
2
3use once_cell::sync::Lazy;
4use prost_build::Module;
5use prost_types::compiler::code_generator_response::File;
6use protoc_gen_prost::{Generator, ModuleRequestSet, Result};
7
8use crate::PackageLimiter;
9
10pub(crate) struct IncludeFileGenerator<'a> {
11 filename: &'a str,
12 limiter: Rc<PackageLimiter>,
13}
14
15impl<'a> IncludeFileGenerator<'a> {
16 pub(crate) fn new(filename: &'a str, limiter: Rc<PackageLimiter>) -> Self {
17 Self { filename, limiter }
18 }
19}
20
21impl<'a> Generator for IncludeFileGenerator<'a> {
22 fn generate(&mut self, module_request_set: &ModuleRequestSet) -> Result {
23 let mut context = CodeGenContext::new();
24
25 let _: () = module_request_set
26 .requests()
27 .filter_map(|(module, request)| {
28 let filename = request.output_filename()?;
29 self.limiter
30 .is_allowed(request.proto_package_name())
31 .then(|| {
32 context.move_to(module, request.proto_package_name());
33 context.push_include(filename);
34 context.push_insertion_point(request.proto_package_name());
35 })
36 })
37 .collect();
38
39 let content = context.finish();
40
41 let file = File {
42 name: Some(self.filename.to_string()),
43 content: Some(content),
44 ..File::default()
45 };
46
47 Ok(vec![file])
48 }
49}
50
51static ROOT_MODULE: Lazy<Module> = Lazy::new(|| Module::from_parts([] as [String; 0]));
52
53#[must_use]
54#[derive(Debug)]
55struct CodeGenContext<'a> {
56 last: &'a Module,
57 indent: String,
58 buf: String,
59}
60
61const INDENT: &str = " ";
62
63impl<'a> CodeGenContext<'a> {
64 fn new() -> Self {
65 let mut buf = String::with_capacity(16_384);
67 buf.push_str("// @generated\n");
68
69 let indent = String::with_capacity(INDENT.len() * 8);
70
71 Self {
72 last: &*ROOT_MODULE,
73 indent,
74 buf,
75 }
76 }
77
78 fn indent(&mut self) {
79 self.indent.push_str(INDENT);
80 }
81
82 fn dedent(&mut self) {
83 self.indent.truncate(
84 self.indent
85 .len()
86 .checked_sub(INDENT.len())
87 .expect("indent underflow"),
88 );
89 }
90
91 fn push_indent(&mut self) {
92 self.buf.push_str(&self.indent);
93 }
94
95 fn move_to(&mut self, next: &'a Module, package: &str) {
96 let (down, prefix) = difference(self.last, next);
97
98 for _ in 0..down {
99 self.close_module();
100 }
101
102 let take = next.len() - prefix - 1;
103
104 for module_name in next.parts().skip(prefix).take(take) {
105 self.open_module(module_name);
106 }
107
108 self.push_attribute_insertion_point(package);
109 self.open_module(next.parts().last().unwrap());
110
111 self.last = next;
112 }
113
114 fn finish(mut self) -> String {
115 while !self.indent.is_empty() {
116 self.close_module()
117 }
118 self.buf
119 }
120
121 fn push_include(&mut self, filename: &str) {
122 self.push_indent();
123 self.buf.push_str("include!(\"");
124 self.buf.push_str(filename);
125 self.buf.push_str("\");\n");
126 }
127
128 fn push_insertion_point(&mut self, package_name: &str) {
129 self.push_indent();
130 self.buf.push_str("// @@protoc_insertion_point(");
131 self.buf.push_str(package_name);
132 self.buf.push_str(")\n");
133 }
134
135 fn push_attribute_insertion_point(&mut self, package_name: &str) {
136 self.push_indent();
137 self.buf.push_str("// @@protoc_insertion_point(attribute:");
138 self.buf.push_str(package_name);
139 self.buf.push_str(")\n");
140 }
141
142 fn close_module(&mut self) {
143 self.dedent();
144 self.push_indent();
145 self.buf.push_str("}\n");
146 }
147
148 fn open_module(&mut self, module_name: &str) {
149 self.push_indent();
150 self.buf.push_str("pub mod ");
151 self.buf.push_str(module_name);
152 self.buf.push_str(" {\n");
153 self.indent();
154 }
155}
156
157fn difference(left: &Module, right: &Module) -> (usize, usize) {
158 let mut left_parts = left.parts();
159 let mut right_parts = right.parts();
160
161 let mut prefix = 0;
162
163 loop {
164 match (left_parts.next(), right_parts.next()) {
165 (Some(left), Some(right)) if left == right => prefix += 1,
166 (Some(_), Some(_)) => return (left_parts.count() + 1, prefix),
167 (Some(_), None) => return (left_parts.count() + 1, prefix),
168 (None, Some(_)) => return (0, prefix),
169 (None, None) => return (0, prefix),
170 }
171 }
172}