prost_reflect/descriptor/build/
visit.rs

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}