1use crate::descriptor::{
2 build::DescriptorPoolOffsets,
3 tag, to_index,
4 types::{
5 DescriptorProto, EnumDescriptorProto, EnumValueDescriptorProto, FieldDescriptorProto,
6 FileDescriptorProto, MethodDescriptorProto, OneofDescriptorProto, ServiceDescriptorProto,
7 },
8 EnumIndex, EnumValueIndex, ExtensionIndex, FieldIndex, FileIndex, MessageIndex, MethodIndex,
9 OneofIndex, ServiceIndex,
10};
11
12pub(super) trait Visitor {
13 fn visit_file(&mut self, _path: &[i32], _index: FileIndex, _file: &FileDescriptorProto) {}
14
15 fn visit_message(
16 &mut self,
17 _path: &[i32],
18 _full_name: &str,
19 _file: FileIndex,
20 _parent_message: Option<MessageIndex>,
21 _index: MessageIndex,
22 _message: &DescriptorProto,
23 ) {
24 }
25
26 fn visit_field(
27 &mut self,
28 _path: &[i32],
29 _full_name: &str,
30 _file: FileIndex,
31 _message: MessageIndex,
32 _index: FieldIndex,
33 _field: &FieldDescriptorProto,
34 ) {
35 }
36
37 fn visit_oneof(
38 &mut self,
39 _path: &[i32],
40 _full_name: &str,
41 _file: FileIndex,
42 _message: MessageIndex,
43 _index: OneofIndex,
44 _oneof: &OneofDescriptorProto,
45 ) {
46 }
47
48 fn visit_service(
49 &mut self,
50 _path: &[i32],
51 _full_name: &str,
52 _file: FileIndex,
53 _index: ServiceIndex,
54 _service: &ServiceDescriptorProto,
55 ) {
56 }
57
58 fn visit_method(
59 &mut self,
60 _path: &[i32],
61 _full_name: &str,
62 _file: FileIndex,
63 _service: ServiceIndex,
64 _index: MethodIndex,
65 _method: &MethodDescriptorProto,
66 ) {
67 }
68
69 fn visit_enum(
70 &mut self,
71 _path: &[i32],
72 _full_name: &str,
73 _file: FileIndex,
74 _parent_message: Option<MessageIndex>,
75 _index: EnumIndex,
76 _enum: &EnumDescriptorProto,
77 ) {
78 }
79
80 fn visit_enum_value(
81 &mut self,
82 _path: &[i32],
83 _full_name: &str,
84 _file: FileIndex,
85 _enum_: EnumIndex,
86 _index: EnumValueIndex,
87 _value: &EnumValueDescriptorProto,
88 ) {
89 }
90
91 fn visit_extension(
92 &mut self,
93 _path: &[i32],
94 _full_name: &str,
95 _file: FileIndex,
96 _parent_message: Option<MessageIndex>,
97 _index: ExtensionIndex,
98 _extension: &FieldDescriptorProto,
99 ) {
100 }
101}
102
103pub(super) fn visit(
104 offsets: DescriptorPoolOffsets,
105 files: &[FileDescriptorProto],
106 visitor: &mut dyn Visitor,
107) {
108 let mut context = Context {
109 path: Vec::new(),
110 scope: String::new(),
111 offsets,
112 };
113
114 for file in files {
115 context.visit_file(file, visitor);
116 }
117}
118
119struct Context {
120 path: Vec<i32>,
121 scope: String,
122 offsets: DescriptorPoolOffsets,
123}
124
125impl Context {
126 fn visit_file(&mut self, file: &FileDescriptorProto, visitor: &mut dyn Visitor) {
127 if !file.package().is_empty() {
128 self.push_scope(file.package());
129 }
130
131 let index = post_inc(&mut self.offsets.file);
132 visitor.visit_file(&self.path, index, file);
133
134 self.push_path(tag::file::MESSAGE_TYPE);
135 for (i, message) in file.message_type.iter().enumerate() {
136 self.push_path(i as i32);
137 self.visit_message(message, visitor, index, None);
138 self.pop_path();
139 }
140 self.pop_path();
141
142 self.push_path(tag::file::ENUM_TYPE);
143 for (i, enum_) in file.enum_type.iter().enumerate() {
144 self.push_path(i as i32);
145 self.visit_enum(enum_, visitor, index, None);
146 self.pop_path();
147 }
148 self.pop_path();
149
150 self.push_path(tag::file::SERVICE);
151 for (i, service) in file.service.iter().enumerate() {
152 self.push_path(i as i32);
153 self.visit_service(service, visitor, index);
154 self.pop_path();
155 }
156 self.pop_path();
157
158 self.push_path(tag::file::EXTENSION);
159 for (i, extension) in file.extension.iter().enumerate() {
160 self.push_path(i as i32);
161 self.visit_extension(extension, visitor, index, None);
162 self.pop_path();
163 }
164 self.pop_path();
165
166 if !file.package().is_empty() {
167 self.pop_scope(file.package());
168 }
169 }
170
171 fn visit_message(
172 &mut self,
173 message: &DescriptorProto,
174 visitor: &mut dyn Visitor,
175 file: FileIndex,
176 parent_message: Option<MessageIndex>,
177 ) {
178 self.push_scope(message.name());
179
180 let index = post_inc(&mut self.offsets.message);
181 visitor.visit_message(
182 &self.path,
183 &self.scope,
184 file,
185 parent_message,
186 index,
187 message,
188 );
189
190 self.push_path(tag::message::ONEOF_DECL);
191 for (i, oneof) in message.oneof_decl.iter().enumerate() {
192 self.push_path(i as i32);
193 self.visit_oneof(oneof, visitor, file, index, to_index(i));
194 self.pop_path();
195 }
196 self.pop_path();
197
198 self.push_path(tag::message::FIELD);
199 for (i, field) in message.field.iter().enumerate() {
200 self.push_path(i as i32);
201 self.visit_field(field, visitor, file, index, to_index(i));
202 self.pop_path();
203 }
204 self.pop_path();
205
206 self.push_path(tag::message::NESTED_TYPE);
207 for (i, nested) in message.nested_type.iter().enumerate() {
208 self.push_path(i as i32);
209 self.visit_message(nested, visitor, file, Some(index));
210 self.pop_path();
211 }
212 self.pop_path();
213
214 self.push_path(tag::message::ENUM_TYPE);
215 for (i, enum_) in message.enum_type.iter().enumerate() {
216 self.push_path(i as i32);
217 self.visit_enum(enum_, visitor, file, Some(index));
218 self.pop_path();
219 }
220 self.pop_path();
221
222 self.push_path(tag::message::EXTENSION);
223 for (i, extension) in message.extension.iter().enumerate() {
224 self.push_path(i as i32);
225 self.visit_extension(extension, visitor, file, Some(index));
226 self.pop_path();
227 }
228 self.pop_path();
229
230 self.pop_scope(message.name());
231 }
232
233 fn visit_field(
234 &mut self,
235 field: &FieldDescriptorProto,
236 visitor: &mut dyn Visitor,
237 file: FileIndex,
238 message: MessageIndex,
239 index: FieldIndex,
240 ) {
241 self.push_scope(field.name());
242 visitor.visit_field(&self.path, &self.scope, file, message, index, field);
243 self.pop_scope(field.name());
244 }
245
246 fn visit_oneof(
247 &mut self,
248 oneof: &OneofDescriptorProto,
249 visitor: &mut dyn Visitor,
250 file: FileIndex,
251 message: MessageIndex,
252 index: OneofIndex,
253 ) {
254 self.push_scope(oneof.name());
255 visitor.visit_oneof(&self.path, &self.scope, file, message, index, oneof);
256 self.pop_scope(oneof.name());
257 }
258
259 fn visit_service(
260 &mut self,
261 service: &ServiceDescriptorProto,
262 visitor: &mut dyn Visitor,
263 file: FileIndex,
264 ) {
265 self.push_scope(service.name());
266
267 let index = post_inc(&mut self.offsets.service);
268 visitor.visit_service(&self.path, &self.scope, file, index, service);
269
270 self.push_path(tag::service::METHOD);
271 for (i, method) in service.method.iter().enumerate() {
272 self.push_path(i as i32);
273 self.visit_method(method, visitor, file, index, to_index(i));
274 self.pop_path();
275 }
276 self.pop_path();
277
278 self.pop_scope(service.name());
279 }
280
281 fn visit_method(
282 &mut self,
283 method: &MethodDescriptorProto,
284 visitor: &mut dyn Visitor,
285 file: FileIndex,
286 service: ServiceIndex,
287 index: MethodIndex,
288 ) {
289 self.push_scope(method.name());
290 visitor.visit_method(&self.path, &self.scope, file, service, index, method);
291 self.pop_scope(method.name());
292 }
293
294 fn visit_enum(
295 &mut self,
296 enum_: &EnumDescriptorProto,
297 visitor: &mut dyn Visitor,
298 file: FileIndex,
299 parent_message: Option<MessageIndex>,
300 ) {
301 self.push_scope(enum_.name());
302
303 let index = post_inc(&mut self.offsets.enum_);
304 visitor.visit_enum(&self.path, &self.scope, file, parent_message, index, enum_);
305
306 self.pop_scope(enum_.name());
307
308 self.push_path(tag::enum_::VALUE);
309 for (i, method) in enum_.value.iter().enumerate() {
310 self.push_path(i as i32);
311 self.visit_enum_value(method, visitor, file, index, to_index(i));
312 self.pop_path();
313 }
314 self.pop_path();
315 }
316
317 fn visit_enum_value(
318 &mut self,
319 value: &EnumValueDescriptorProto,
320 visitor: &mut dyn Visitor,
321 file: FileIndex,
322 enum_: EnumIndex,
323 index: EnumValueIndex,
324 ) {
325 self.push_scope(value.name());
326 visitor.visit_enum_value(&self.path, &self.scope, file, enum_, index, value);
327 self.pop_scope(value.name());
328 }
329
330 fn visit_extension(
331 &mut self,
332 extension: &FieldDescriptorProto,
333 visitor: &mut dyn Visitor,
334 file: FileIndex,
335 parent_message: Option<MessageIndex>,
336 ) {
337 self.push_scope(extension.name());
338 let index = post_inc(&mut self.offsets.extension);
339 visitor.visit_extension(
340 &self.path,
341 &self.scope,
342 file,
343 parent_message,
344 index,
345 extension,
346 );
347 self.pop_scope(extension.name());
348 }
349
350 fn push_path(&mut self, path: i32) {
351 self.path.push(path);
352 }
353
354 fn pop_path(&mut self) {
355 self.path.pop().unwrap();
356 }
357
358 fn push_scope(&mut self, scope: &str) {
359 if !self.scope.is_empty() {
360 self.scope.push('.');
361 }
362 self.scope.push_str(scope);
363 }
364
365 fn pop_scope(&mut self, scope: &str) {
366 debug_assert!(self.scope.ends_with(scope));
367 self.scope
368 .truncate((self.scope.len() - scope.len()).saturating_sub(1));
369 }
370}
371
372fn post_inc(index: &mut u32) -> u32 {
373 let value = *index;
374 *index = value + 1;
375 value
376}