protobuf_codegen/gen/
scope.rs1use std::ops::Deref;
2
3use protobuf::reflect::EnumDescriptor;
4use protobuf::reflect::EnumValueDescriptor;
5use protobuf::reflect::FieldDescriptor;
6use protobuf::reflect::FileDescriptor;
7use protobuf::reflect::MessageDescriptor;
8use protobuf::reflect::OneofDescriptor;
9use protobuf_parse::ProtobufAbsPath;
10use protobuf_parse::ProtobufAbsPathRef;
11use protobuf_parse::ProtobufIdentRef;
12use protobuf_parse::ProtobufRelPath;
13use protobuf_parse::ProtobufRelPathRef;
14
15use crate::customize::Customize;
16use crate::gen::field::rust_field_name_for_protobuf_field_name;
17use crate::gen::file_and_mod::FileAndMod;
18use crate::gen::map::map_entry;
19use crate::gen::message::message_name_to_nested_mod_name;
20use crate::gen::paths::proto_path_to_rust_mod;
21use crate::gen::rust::ident::RustIdent;
22use crate::gen::rust::ident_with_path::RustIdentWithPath;
23use crate::gen::rust::rel_path::RustRelativePath;
24use crate::gen::strx::capitalize;
25
26pub(crate) struct RootScope<'a> {
27 pub file_descriptors: &'a [FileDescriptor],
28}
29
30impl<'a> RootScope<'a> {
31 fn packages(&'a self) -> Vec<FileScope<'a>> {
32 self.file_descriptors
33 .iter()
34 .map(|fd| FileScope {
35 file_descriptor: fd,
36 })
37 .collect()
38 }
39
40 pub fn _find_enum(&'a self, fqn: &ProtobufAbsPath) -> EnumWithScope<'a> {
42 match self.find_message_or_enum(fqn) {
43 MessageOrEnumWithScope::Enum(e) => e,
44 _ => panic!("not an enum: {}", fqn),
45 }
46 }
47
48 pub fn find_message(&'a self, fqn: &ProtobufAbsPath) -> MessageWithScope<'a> {
50 match self.find_message_or_enum(fqn) {
51 MessageOrEnumWithScope::Message(m) => m,
52 _ => panic!("not a message: {}", fqn),
53 }
54 }
55
56 pub fn find_message_or_enum(&'a self, fqn: &ProtobufAbsPath) -> MessageOrEnumWithScope<'a> {
58 assert!(!fqn.is_root());
59 self.packages()
60 .into_iter()
61 .flat_map(|p| p.find_message_or_enum_abs(fqn))
62 .next()
63 .expect(&format!("enum not found by name: {}", fqn))
64 }
65}
66
67#[derive(Clone, Debug)]
68pub(crate) struct FileScope<'a> {
69 pub file_descriptor: &'a FileDescriptor,
70}
71
72impl<'a> Deref for FileScope<'a> {
73 type Target = FileDescriptor;
74
75 fn deref(&self) -> &Self::Target {
76 self.file_descriptor
77 }
78}
79
80impl<'a> FileScope<'a> {
81 fn package(&self) -> ProtobufAbsPath {
82 ProtobufAbsPath::package_from_file_descriptor(self.file_descriptor)
83 }
84
85 pub fn to_scope(&self) -> Scope<'a> {
86 Scope {
87 file_scope: self.clone(),
88 path: Vec::new(),
89 }
90 }
91
92 fn find_message_or_enum(
93 &self,
94 name: &ProtobufRelPathRef,
95 ) -> Option<MessageOrEnumWithScope<'a>> {
96 self.find_messages_and_enums()
97 .into_iter()
98 .filter(|e| e.protobuf_name_to_package().as_ref() == name)
99 .next()
100 }
101
102 fn find_message_or_enum_abs(
103 &self,
104 name: &ProtobufAbsPathRef,
105 ) -> Option<MessageOrEnumWithScope<'a>> {
106 let name = name.to_owned();
107 match name.remove_prefix(&self.package()) {
108 Some(rem) => self.find_message_or_enum(&rem),
109 None => None,
110 }
111 }
112
113 pub fn find_enums(&self) -> Vec<EnumWithScope<'a>> {
115 let mut r = Vec::new();
116
117 self.to_scope().walk_scopes(|scope| {
118 r.extend(scope.enums());
119 });
120
121 r
122 }
123
124 pub fn find_messages(&self) -> Vec<MessageWithScope<'a>> {
126 let mut r = Vec::new();
127
128 self.to_scope().walk_scopes(|scope| {
129 r.extend(scope.messages());
130 });
131
132 r
133 }
134
135 pub fn find_messages_except_map(&self) -> Vec<MessageWithScope<'a>> {
137 self.find_messages()
138 .into_iter()
139 .filter(|m| !m.is_map())
140 .collect()
141 }
142
143 pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
145 let mut r = Vec::new();
146
147 self.to_scope().walk_scopes(|scope| {
148 r.extend(scope.messages_and_enums());
149 });
150
151 r
152 }
153}
154
155#[derive(Clone, Debug)]
156pub(crate) struct Scope<'a> {
157 pub file_scope: FileScope<'a>,
158 pub path: Vec<MessageDescriptor>,
159}
160
161impl<'a> Scope<'a> {
162 pub(crate) fn file_descriptor(&self) -> FileDescriptor {
163 self.file_scope.file_descriptor.clone()
164 }
165
166 fn message_descriptors(&self) -> Vec<MessageDescriptor> {
168 if self.path.is_empty() {
169 self.file_scope.file_descriptor.messages().collect()
170 } else {
171 self.path.last().unwrap().nested_messages().collect()
172 }
173 }
174
175 fn enum_descriptors(&self) -> Vec<EnumDescriptor> {
177 if self.path.is_empty() {
178 self.file_scope.file_descriptor.enums().collect()
179 } else {
180 self.path.last().unwrap().nested_enums().collect()
181 }
182 }
183
184 pub fn messages(&self) -> Vec<MessageWithScope<'a>> {
186 self.message_descriptors()
187 .into_iter()
188 .map(|message| MessageWithScope {
189 scope: self.clone(),
190 message,
191 })
192 .collect()
193 }
194
195 pub fn enums(&self) -> Vec<EnumWithScope<'a>> {
197 self.enum_descriptors()
198 .into_iter()
199 .map(|en| EnumWithScope {
200 scope: self.clone(),
201 en,
202 })
203 .collect()
204 }
205
206 pub fn messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
208 self.messages()
209 .into_iter()
210 .map(|m| MessageOrEnumWithScope::Message(m))
211 .chain(
212 self.enums()
213 .into_iter()
214 .map(|m| MessageOrEnumWithScope::Enum(m)),
215 )
216 .collect()
217 }
218
219 fn nested_scopes(&self) -> Vec<Scope<'a>> {
221 self.message_descriptors()
222 .into_iter()
223 .map(|m| {
224 let mut nested = self.clone();
225 nested.path.push(m);
226 nested
227 })
228 .collect()
229 }
230
231 fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) {
232 (*callback)(self);
233
234 for nested in self.nested_scopes() {
235 nested.walk_scopes_impl(callback);
236 }
237 }
238
239 fn walk_scopes<F>(&self, mut callback: F)
241 where
242 F: FnMut(&Scope<'a>),
243 {
244 self.walk_scopes_impl(&mut callback);
245 }
246
247 pub fn rust_path_to_file(&self) -> RustRelativePath {
248 RustRelativePath::from_idents(
249 self.path
250 .iter()
251 .map(|m| message_name_to_nested_mod_name(m.name())),
252 )
253 }
254
255 pub fn path_str(&self) -> String {
256 let v: Vec<&str> = self.path.iter().map(|m| m.name()).collect();
257 v.join(".")
258 }
259
260 pub fn prefix(&self) -> String {
261 let path_str = self.path_str();
262 if path_str.is_empty() {
263 path_str
264 } else {
265 format!("{}.", path_str)
266 }
267 }
268
269 pub fn protobuf_path_to_file(&self) -> ProtobufRelPath {
270 ProtobufRelPath::from_components(self.path.iter().map(|m| ProtobufIdentRef::new(m.name())))
271 }
272
273 pub fn protobuf_absolute_path(&self) -> ProtobufAbsPath {
274 let mut r = self.file_scope.package();
275 r.push_relative(&self.protobuf_path_to_file());
276 r
277 }
278
279 pub fn file_and_mod(&self, customize: Customize) -> FileAndMod {
280 FileAndMod {
281 file: self.file_scope.file_descriptor.proto().name().to_owned(),
282 relative_mod: self.rust_path_to_file(),
283 customize,
284 }
285 }
286}
287
288pub(crate) trait WithScope<'a> {
289 fn scope(&self) -> &Scope<'a>;
290
291 fn file_descriptor(&self) -> FileDescriptor {
292 self.scope().file_descriptor()
293 }
294
295 fn name(&self) -> &ProtobufIdentRef;
297
298 fn name_to_package(&self) -> String {
299 let mut r = self.scope().prefix();
300 r.push_str(&self.name());
301 r
302 }
303
304 fn protobuf_name_to_package(&self) -> ProtobufRelPath {
305 let r = self.scope().protobuf_path_to_file();
306 r.append_ident(ProtobufIdentRef::new(self.name()))
307 }
308
309 fn name_absolute(&self) -> ProtobufAbsPath {
311 let mut path = self.scope().protobuf_absolute_path();
312 path.push_simple(self.name());
313 path
314 }
315
316 fn rust_name(&self) -> RustIdent {
318 let rust_name = capitalize(&self.name());
319 RustIdent::new(&rust_name)
320 }
321
322 fn rust_name_to_file(&self) -> RustIdentWithPath {
323 self.scope()
324 .rust_path_to_file()
325 .into_path()
326 .with_ident(self.rust_name())
327 }
328
329 fn rust_name_with_file(&self) -> RustIdentWithPath {
331 let mut r = self.rust_name_to_file();
332 r.prepend_ident(proto_path_to_rust_mod(
333 self.scope().file_descriptor().name(),
334 ));
335 r
336 }
337}
338
339#[derive(Clone, Debug)]
340pub(crate) struct MessageWithScope<'a> {
341 pub scope: Scope<'a>,
342 pub message: MessageDescriptor,
343}
344
345impl<'a> WithScope<'a> for MessageWithScope<'a> {
346 fn scope(&self) -> &Scope<'a> {
347 &self.scope
348 }
349
350 fn name(&self) -> &ProtobufIdentRef {
351 ProtobufIdentRef::new(self.message.name())
352 }
353}
354
355impl<'a> MessageWithScope<'a> {
356 pub fn into_scope(mut self) -> Scope<'a> {
357 self.scope.path.push(self.message);
358 self.scope
359 }
360
361 pub fn to_scope(&self) -> Scope<'a> {
362 self.clone().into_scope()
363 }
364
365 pub fn fields(&self) -> Vec<FieldWithContext<'a>> {
366 self.message
367 .fields()
368 .into_iter()
369 .map(|field| FieldWithContext {
370 field,
371 message: self.clone(),
372 })
373 .collect()
374 }
375
376 pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> {
377 self.message
378 .oneofs()
379 .into_iter()
380 .map(|oneof| OneofWithContext {
381 message: self.clone(),
382 oneof,
383 })
384 .collect()
385 }
386
387 pub fn mod_name(&self) -> RustIdent {
388 message_name_to_nested_mod_name(self.message.name())
389 }
390
391 pub fn is_map(&self) -> bool {
393 map_entry(self).is_some()
394 }
395}
396
397#[derive(Clone, Debug)]
398pub(crate) struct EnumWithScope<'a> {
399 pub scope: Scope<'a>,
400 pub en: EnumDescriptor,
401}
402
403impl<'a> EnumWithScope<'a> {
404 pub fn values(&self) -> Vec<EnumValueWithContext<'a>> {
405 self.en
406 .values()
407 .into_iter()
408 .map(|v| EnumValueWithContext {
409 en: self.clone(),
410 proto: v,
411 })
412 .collect()
413 }
414
415 pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> {
417 self.values()
418 .into_iter()
419 .find(|v| v.proto.proto().name() == name)
420 .unwrap()
421 }
422}
423
424#[derive(Clone, Debug)]
425pub(crate) struct EnumValueWithContext<'a> {
426 pub en: EnumWithScope<'a>,
427 pub proto: EnumValueDescriptor,
428}
429
430impl<'a> EnumValueWithContext<'a> {
431 pub fn rust_name(&self) -> RustIdent {
432 RustIdent::new(self.proto.name())
434 }
435}
436
437impl<'a> WithScope<'a> for EnumWithScope<'a> {
438 fn scope(&self) -> &Scope<'a> {
439 &self.scope
440 }
441
442 fn name(&self) -> &ProtobufIdentRef {
443 ProtobufIdentRef::new(self.en.name())
444 }
445}
446
447pub(crate) enum MessageOrEnumWithScope<'a> {
448 Message(MessageWithScope<'a>),
449 Enum(EnumWithScope<'a>),
450}
451
452impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> {
453 fn scope(&self) -> &Scope<'a> {
454 match self {
455 MessageOrEnumWithScope::Message(m) => m.scope(),
456 MessageOrEnumWithScope::Enum(e) => e.scope(),
457 }
458 }
459
460 fn name(&self) -> &ProtobufIdentRef {
461 match self {
462 MessageOrEnumWithScope::Message(m) => m.name(),
463 MessageOrEnumWithScope::Enum(e) => e.name(),
464 }
465 }
466}
467
468#[derive(Clone)]
469pub(crate) struct FieldWithContext<'a> {
470 pub field: FieldDescriptor,
471 pub message: MessageWithScope<'a>,
472}
473
474impl<'a> Deref for FieldWithContext<'a> {
475 type Target = FieldDescriptor;
476
477 fn deref(&self) -> &Self::Target {
478 &self.field
479 }
480}
481
482impl<'a> FieldWithContext<'a> {
483 pub fn is_oneof(&self) -> bool {
484 self.field.containing_oneof().is_some()
485 }
486
487 pub fn oneof(&self) -> Option<OneofWithContext<'a>> {
488 match self.field.containing_oneof() {
489 Some(oneof) => Some(OneofWithContext {
490 message: self.message.clone(),
491 oneof,
492 }),
493 None => None,
494 }
495 }
496}
497
498#[derive(Clone)]
499pub(crate) struct OneofVariantWithContext<'a> {
500 pub oneof: &'a OneofWithContext<'a>,
501 pub field: FieldDescriptor,
502}
503
504#[derive(Clone)]
505pub(crate) struct OneofWithContext<'a> {
506 pub oneof: OneofDescriptor,
507 pub message: MessageWithScope<'a>,
508}
509
510impl<'a> OneofWithContext<'a> {
511 pub fn field_name(&'a self) -> RustIdent {
512 return rust_field_name_for_protobuf_field_name(self.oneof.name());
513 }
514
515 pub fn rust_name(&self) -> RustIdentWithPath {
517 let type_name = RustIdent::from(capitalize(self.oneof.name()));
518 self.message
519 .to_scope()
520 .rust_path_to_file()
521 .into_path()
522 .with_ident(type_name)
523 }
524
525 pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> {
526 self.message
527 .fields()
528 .into_iter()
529 .filter(|f| f.field.containing_oneof().as_ref() == Some(&self.oneof))
530 .map(|f| OneofVariantWithContext {
531 oneof: self,
532 field: f.field,
533 })
534 .collect()
535 }
536}