1use std::ascii;
2use std::borrow::Cow;
3use std::collections::{HashMap, HashSet};
4use std::iter;
5
6use itertools::{Either, Itertools};
7use log::debug;
8use multimap::MultiMap;
9use prost_types::field_descriptor_proto::{Label, Type};
10use prost_types::source_code_info::Location;
11use prost_types::{
12 DescriptorProto, EnumDescriptorProto, EnumValueDescriptorProto, EnumValueOptions,
13 FieldDescriptorProto, FieldOptions, FileDescriptorProto, OneofDescriptorProto,
14 ServiceDescriptorProto, SourceCodeInfo,
15};
16
17use crate::ast::{Comments, Method, Service};
18use crate::context::Context;
19use crate::ident::{strip_enum_prefix, to_snake, to_upper_camel};
20use crate::Config;
21
22mod c_escaping;
23use c_escaping::unescape_c_escape_string;
24
25mod syntax;
26use syntax::Syntax;
27
28pub struct CodeGenerator<'a, 'b> {
30 context: &'a mut Context<'b>,
31 package: String,
32 type_path: Vec<String>,
33 source_info: Option<SourceCodeInfo>,
34 syntax: Syntax,
35 depth: u8,
36 path: Vec<i32>,
37 buf: &'a mut String,
38}
39
40fn push_indent(buf: &mut String, depth: u8) {
41 for _ in 0..depth {
42 buf.push_str(" ");
43 }
44}
45
46struct Field {
47 descriptor: FieldDescriptorProto,
48 path_index: i32,
49}
50
51impl Field {
52 fn new(descriptor: FieldDescriptorProto, path_index: i32) -> Self {
53 Self {
54 descriptor,
55 path_index,
56 }
57 }
58
59 fn rust_name(&self) -> String {
60 to_snake(self.descriptor.name())
61 }
62}
63
64struct OneofField {
65 descriptor: OneofDescriptorProto,
66 fields: Vec<Field>,
67 path_index: i32,
68 has_type_name_conflict: bool,
70}
71
72impl OneofField {
73 fn new(
74 parent: &DescriptorProto,
75 descriptor: OneofDescriptorProto,
76 fields: Vec<Field>,
77 path_index: i32,
78 ) -> Self {
79 let nested_type_names = parent.nested_type.iter().map(DescriptorProto::name);
80 let nested_enum_names = parent.enum_type.iter().map(EnumDescriptorProto::name);
81 let has_type_name_conflict = nested_type_names
82 .chain(nested_enum_names)
83 .any(|type_name| to_upper_camel(type_name) == to_upper_camel(descriptor.name()));
84
85 Self {
86 descriptor,
87 fields,
88 path_index,
89 has_type_name_conflict,
90 }
91 }
92
93 fn rust_name(&self) -> String {
94 to_snake(self.descriptor.name())
95 }
96
97 fn type_name(&self) -> String {
98 let mut name = to_upper_camel(self.descriptor.name());
99 if self.has_type_name_conflict {
100 name.push_str("OneOf");
101 }
102 name
103 }
104}
105
106impl<'b> CodeGenerator<'_, 'b> {
107 fn config(&self) -> &Config {
108 self.context.config()
109 }
110
111 pub(crate) fn generate(context: &mut Context<'b>, file: FileDescriptorProto, buf: &mut String) {
112 let source_info = file.source_code_info.map(|mut s| {
113 s.location.retain(|loc| {
114 let len = loc.path.len();
115 len > 0 && len % 2 == 0
116 });
117 s.location.sort_by(|a, b| a.path.cmp(&b.path));
118 s
119 });
120
121 let mut code_gen = CodeGenerator {
122 context,
123 package: file.package.unwrap_or_default(),
124 type_path: Vec::new(),
125 source_info,
126 syntax: file.syntax.as_deref().into(),
127 depth: 0,
128 path: Vec::new(),
129 buf,
130 };
131
132 debug!(
133 "file: {:?}, package: {:?}",
134 file.name.as_ref().unwrap(),
135 code_gen.package
136 );
137
138 code_gen.path.push(4);
139 for (idx, message) in file.message_type.into_iter().enumerate() {
140 code_gen.path.push(idx as i32);
141 code_gen.append_message(message);
142 code_gen.path.pop();
143 }
144 code_gen.path.pop();
145
146 code_gen.path.push(5);
147 for (idx, desc) in file.enum_type.into_iter().enumerate() {
148 code_gen.path.push(idx as i32);
149 code_gen.append_enum(desc);
150 code_gen.path.pop();
151 }
152 code_gen.path.pop();
153
154 if code_gen.context.service_generator_mut().is_some() {
155 code_gen.path.push(6);
156 for (idx, service) in file.service.into_iter().enumerate() {
157 code_gen.path.push(idx as i32);
158 code_gen.push_service(service);
159 code_gen.path.pop();
160 }
161
162 if let Some(service_generator) = code_gen.context.service_generator_mut() {
163 service_generator.finalize(code_gen.buf);
164 }
165
166 code_gen.path.pop();
167 }
168 }
169
170 fn append_message(&mut self, message: DescriptorProto) {
171 debug!(" message: {:?}", message.name());
172
173 let message_name = message.name().to_string();
174 let fq_message_name = self.fq_name(&message_name);
175
176 if self
178 .context
179 .resolve_extern_ident(&fq_message_name)
180 .is_some()
181 {
182 return;
183 }
184
185 type NestedTypes = Vec<(DescriptorProto, usize)>;
189 type MapTypes = HashMap<String, (FieldDescriptorProto, FieldDescriptorProto)>;
190 let (nested_types, map_types): (NestedTypes, MapTypes) = message
191 .nested_type
192 .iter()
193 .enumerate()
194 .partition_map(|(idx, nested_type)| {
195 if nested_type
196 .options
197 .as_ref()
198 .and_then(|options| options.map_entry)
199 .unwrap_or(false)
200 {
201 let key = nested_type.field[0].clone();
202 let value = nested_type.field[1].clone();
203 assert_eq!("key", key.name());
204 assert_eq!("value", value.name());
205
206 let name = format!("{}.{}", &fq_message_name, nested_type.name());
207 Either::Right((name, (key, value)))
208 } else {
209 Either::Left((nested_type.clone(), idx))
210 }
211 });
212
213 type OneofFieldsByIndex = MultiMap<i32, Field>;
216 let (fields, mut oneof_map): (Vec<Field>, OneofFieldsByIndex) = message
217 .field
218 .iter()
219 .enumerate()
220 .partition_map(|(idx, proto)| {
221 let idx = idx as i32;
222 if proto.proto3_optional.unwrap_or(false) {
223 Either::Left(Field::new(proto.clone(), idx))
224 } else if let Some(oneof_index) = proto.oneof_index {
225 Either::Right((oneof_index, Field::new(proto.clone(), idx)))
226 } else {
227 Either::Left(Field::new(proto.clone(), idx))
228 }
229 });
230 let oneof_fields: Vec<OneofField> = message
232 .oneof_decl
233 .iter()
234 .enumerate()
235 .filter_map(|(idx, proto)| {
236 let idx = idx as i32;
237 oneof_map
238 .remove(&idx)
239 .map(|fields| OneofField::new(&message, proto.clone(), fields, idx))
240 })
241 .collect();
242
243 self.append_doc(&fq_message_name, None);
244 self.append_type_attributes(&fq_message_name);
245 self.append_message_attributes(&fq_message_name);
246 self.push_indent();
247 self.buf.push_str(&format!(
248 "#[derive(Clone, {}PartialEq, {}{}::Message)]\n",
249 if self.context.can_message_derive_copy(&fq_message_name) {
250 "Copy, "
251 } else {
252 ""
253 },
254 if self.context.can_message_derive_eq(&fq_message_name) {
255 "Eq, Hash, "
256 } else {
257 ""
258 },
259 self.context.prost_path()
260 ));
261 self.append_prost_path_attribute();
262 self.append_skip_debug(&fq_message_name);
263 self.push_indent();
264 self.buf.push_str("pub struct ");
265 self.buf.push_str(&to_upper_camel(&message_name));
266 self.buf.push_str(" {\n");
267
268 self.depth += 1;
269 self.path.push(2);
270 for field in &fields {
271 self.path.push(field.path_index);
272 match field
273 .descriptor
274 .type_name
275 .as_ref()
276 .and_then(|type_name| map_types.get(type_name))
277 {
278 Some((key, value)) => self.append_map_field(&fq_message_name, field, key, value),
279 None => self.append_field(&fq_message_name, field),
280 }
281 self.path.pop();
282 }
283 self.path.pop();
284
285 self.path.push(8);
286 for oneof in &oneof_fields {
287 self.path.push(oneof.path_index);
288 self.append_oneof_field(&message_name, &fq_message_name, oneof);
289 self.path.pop();
290 }
291 self.path.pop();
292
293 self.depth -= 1;
294 self.push_indent();
295 self.buf.push_str("}\n");
296
297 if !message.enum_type.is_empty() || !nested_types.is_empty() || !oneof_fields.is_empty() {
298 self.push_mod(&message_name);
299 self.path.push(3);
300 for (nested_type, idx) in nested_types {
301 self.path.push(idx as i32);
302 self.append_message(nested_type);
303 self.path.pop();
304 }
305 self.path.pop();
306
307 self.path.push(4);
308 for (idx, nested_enum) in message.enum_type.into_iter().enumerate() {
309 self.path.push(idx as i32);
310 self.append_enum(nested_enum);
311 self.path.pop();
312 }
313 self.path.pop();
314
315 for oneof in &oneof_fields {
316 self.append_oneof(&fq_message_name, oneof);
317 }
318
319 self.pop_mod();
320 }
321
322 if self.config().enable_type_names {
323 self.append_type_name(&message_name, &fq_message_name);
324 }
325 }
326
327 fn append_type_name(&mut self, message_name: &str, fq_message_name: &str) {
328 let prost_path = self.context.prost_path();
329
330 self.buf.push_str(&format!(
331 "impl {prost_path}::Name for {} {{\n",
332 to_upper_camel(message_name)
333 ));
334 self.depth += 1;
335
336 self.buf
337 .push_str(&format!("const NAME: &'static str = \"{message_name}\";\n"));
338 self.buf.push_str(&format!(
339 "const PACKAGE: &'static str = \"{}\";\n",
340 self.package,
341 ));
342
343 let string_path = format!("{prost_path}::alloc::string::String");
344
345 let full_name = format!(
346 "{}{}{}{}{message_name}",
347 self.package.trim_matches('.'),
348 if self.package.is_empty() { "" } else { "." },
349 self.type_path.join("."),
350 if self.type_path.is_empty() { "" } else { "." },
351 );
352 let domain_name = self.context.type_name_domain(fq_message_name);
353
354 self.buf.push_str(&format!(
355 r#"fn full_name() -> {string_path} {{ "{full_name}".into() }}"#,
356 ));
357
358 self.buf.push_str(&format!(
359 r#"fn type_url() -> {string_path} {{ "{domain_name}/{full_name}".into() }}"#,
360 ));
361
362 self.depth -= 1;
363 self.buf.push_str("}\n");
364 }
365
366 fn append_type_attributes(&mut self, fq_message_name: &str) {
367 assert_eq!(b'.', fq_message_name.as_bytes()[0]);
368 for attribute in self.context.type_attributes(fq_message_name) {
369 push_indent(self.buf, self.depth);
370 self.buf.push_str(attribute);
371 self.buf.push('\n');
372 }
373 }
374
375 fn append_message_attributes(&mut self, fq_message_name: &str) {
376 assert_eq!(b'.', fq_message_name.as_bytes()[0]);
377 for attribute in self.context.message_attributes(fq_message_name) {
378 push_indent(self.buf, self.depth);
379 self.buf.push_str(attribute);
380 self.buf.push('\n');
381 }
382 }
383
384 fn append_prost_path_attribute(&mut self) {
385 if let Some(prost_path_attribute) = self.context.prost_path_attribute() {
386 self.buf.push_str(prost_path_attribute);
387 self.buf.push('\n');
388 }
389 }
390
391 fn append_skip_debug(&mut self, fq_message_name: &str) {
392 if self.context.should_skip_debug(fq_message_name) {
393 push_indent(self.buf, self.depth);
394 self.buf.push_str("#[prost(skip_debug)]");
395 self.buf.push('\n');
396 }
397 }
398
399 fn append_enum_attributes(&mut self, fq_message_name: &str) {
400 assert_eq!(b'.', fq_message_name.as_bytes()[0]);
401 for attribute in self.context.enum_attributes(fq_message_name) {
402 push_indent(self.buf, self.depth);
403 self.buf.push_str(attribute);
404 self.buf.push('\n');
405 }
406 }
407
408 fn append_field_attributes(&mut self, fq_message_name: &str, field_name: &str) {
409 assert_eq!(b'.', fq_message_name.as_bytes()[0]);
410 for attribute in self.context.field_attributes(fq_message_name, field_name) {
411 push_indent(self.buf, self.depth);
412 self.buf.push_str(attribute);
413 self.buf.push('\n');
414 }
415 }
416
417 fn append_field(&mut self, fq_message_name: &str, field: &Field) {
418 let type_ = field.descriptor.r#type();
419 let repeated = field.descriptor.label() == Label::Repeated;
420 let deprecated = self.deprecated(&field.descriptor);
421 let optional = self.optional(&field.descriptor);
422 let boxed = self
423 .context
424 .should_box_message_field(fq_message_name, &field.descriptor);
425 let ty = self.resolve_type(&field.descriptor, fq_message_name);
426
427 debug!(
428 " field: {:?}, type: {:?}, boxed: {}",
429 field.descriptor.name(),
430 ty,
431 boxed
432 );
433
434 self.append_doc(fq_message_name, Some(field.descriptor.name()));
435
436 if deprecated {
437 self.push_indent();
438 self.buf.push_str("#[deprecated]\n");
439 }
440
441 self.push_indent();
442 self.buf.push_str("#[prost(");
443 let type_tag = self.field_type_tag(&field.descriptor);
444 self.buf.push_str(&type_tag);
445
446 if type_ == Type::Bytes {
447 let bytes_type = self
448 .context
449 .bytes_type(fq_message_name, field.descriptor.name());
450 self.buf
451 .push_str(&format!(" = {:?}", bytes_type.annotation()));
452 }
453
454 match field.descriptor.label() {
455 Label::Optional => {
456 if optional {
457 self.buf.push_str(", optional");
458 }
459 }
460 Label::Required => self.buf.push_str(", required"),
461 Label::Repeated => {
462 self.buf.push_str(", repeated");
463 if can_pack(&field.descriptor)
464 && !field
465 .descriptor
466 .options
467 .as_ref()
468 .map_or(self.syntax == Syntax::Proto3, |options| options.packed())
469 {
470 self.buf.push_str(", packed = \"false\"");
471 }
472 }
473 }
474
475 if boxed {
476 self.buf.push_str(", boxed");
477 }
478 self.buf.push_str(", tag = \"");
479 self.buf.push_str(&field.descriptor.number().to_string());
480
481 if let Some(ref default) = field.descriptor.default_value {
482 self.buf.push_str("\", default = \"");
483 if type_ == Type::Bytes {
484 self.buf.push_str("b\\\"");
485 for b in unescape_c_escape_string(default) {
486 self.buf.extend(
487 ascii::escape_default(b).flat_map(|c| (c as char).escape_default()),
488 );
489 }
490 self.buf.push_str("\\\"");
491 } else if type_ == Type::Enum {
492 let mut enum_value = to_upper_camel(default);
493 if self.config().strip_enum_prefix {
494 let enum_type = field
498 .descriptor
499 .type_name
500 .as_ref()
501 .and_then(|ty| ty.split('.').next_back())
502 .unwrap();
503
504 enum_value = strip_enum_prefix(&to_upper_camel(enum_type), &enum_value)
505 }
506 self.buf.push_str(&enum_value);
507 } else {
508 self.buf.push_str(&default.escape_default().to_string());
509 }
510 }
511
512 self.buf.push_str("\")]\n");
513 self.append_field_attributes(fq_message_name, field.descriptor.name());
514 self.push_indent();
515 self.buf.push_str("pub ");
516 self.buf.push_str(&field.rust_name());
517 self.buf.push_str(": ");
518
519 let prost_path = self.context.prost_path();
520
521 if repeated {
522 self.buf
523 .push_str(&format!("{prost_path}::alloc::vec::Vec<"));
524 } else if optional {
525 self.buf.push_str("::core::option::Option<");
526 }
527 if boxed {
528 self.buf
529 .push_str(&format!("{prost_path}::alloc::boxed::Box<"));
530 }
531 self.buf.push_str(&ty);
532 if boxed {
533 self.buf.push('>');
534 }
535 if repeated || optional {
536 self.buf.push('>');
537 }
538 self.buf.push_str(",\n");
539 }
540
541 fn append_map_field(
542 &mut self,
543 fq_message_name: &str,
544 field: &Field,
545 key: &FieldDescriptorProto,
546 value: &FieldDescriptorProto,
547 ) {
548 let key_ty = self.resolve_type(key, fq_message_name);
549 let value_ty = self.resolve_type(value, fq_message_name);
550
551 debug!(
552 " map field: {:?}, key type: {:?}, value type: {:?}",
553 field.descriptor.name(),
554 key_ty,
555 value_ty
556 );
557
558 self.append_doc(fq_message_name, Some(field.descriptor.name()));
559 self.push_indent();
560
561 let map_type = self
562 .context
563 .map_type(fq_message_name, field.descriptor.name());
564 let key_tag = self.field_type_tag(key);
565 let value_tag = self.map_value_type_tag(value);
566
567 self.buf.push_str(&format!(
568 "#[prost({} = \"{}, {}\", tag = \"{}\")]\n",
569 map_type.annotation(),
570 key_tag,
571 value_tag,
572 field.descriptor.number()
573 ));
574 self.append_field_attributes(fq_message_name, field.descriptor.name());
575 self.push_indent();
576 match map_type {
577 crate::MapType::HashMap => {
578 self.buf.push_str(&format!(
579 "pub {}: ::std::collections::HashMap<{}, {}>,\n",
580 field.rust_name(),
581 key_ty,
582 value_ty
583 ));
584 }
585 crate::MapType::BTreeMap => {
586 self.buf.push_str(&format!(
587 "pub {}: {}::alloc::collections::BTreeMap<{}, {}>,\n",
588 field.rust_name(),
589 self.context.prost_path(),
590 key_ty,
591 value_ty
592 ));
593 }
594 }
595 }
596
597 fn append_oneof_field(
598 &mut self,
599 message_name: &str,
600 fq_message_name: &str,
601 oneof: &OneofField,
602 ) {
603 let type_name = format!("{}::{}", to_snake(message_name), oneof.type_name());
604 self.append_doc(fq_message_name, None);
605 self.push_indent();
606 self.buf.push_str(&format!(
607 "#[prost(oneof = \"{}\", tags = \"{}\")]\n",
608 type_name,
609 oneof
610 .fields
611 .iter()
612 .map(|field| field.descriptor.number())
613 .join(", "),
614 ));
615 self.append_field_attributes(fq_message_name, oneof.descriptor.name());
616 self.push_indent();
617 self.buf.push_str(&format!(
618 "pub {}: ::core::option::Option<{}>,\n",
619 oneof.rust_name(),
620 type_name
621 ));
622 }
623
624 fn append_oneof(&mut self, fq_message_name: &str, oneof: &OneofField) {
625 self.path.push(8);
626 self.path.push(oneof.path_index);
627 self.append_doc(fq_message_name, None);
628 self.path.pop();
629 self.path.pop();
630
631 let oneof_name = format!("{}.{}", fq_message_name, oneof.descriptor.name());
632 self.append_type_attributes(&oneof_name);
633 self.append_enum_attributes(&oneof_name);
634 self.push_indent();
635
636 let can_oneof_derive_copy = oneof.fields.iter().all(|field| {
637 self.context
638 .can_field_derive_copy(fq_message_name, &field.descriptor)
639 });
640 let can_oneof_derive_eq = oneof.fields.iter().all(|field| {
641 self.context
642 .can_field_derive_eq(fq_message_name, &field.descriptor)
643 });
644 self.buf.push_str(&format!(
645 "#[derive(Clone, {}PartialEq, {}{}::Oneof)]\n",
646 if can_oneof_derive_copy { "Copy, " } else { "" },
647 if can_oneof_derive_eq {
648 "Eq, Hash, "
649 } else {
650 ""
651 },
652 self.context.prost_path()
653 ));
654 self.append_prost_path_attribute();
655 self.append_skip_debug(fq_message_name);
656 self.push_indent();
657 self.buf.push_str("pub enum ");
658 self.buf.push_str(&oneof.type_name());
659 self.buf.push_str(" {\n");
660
661 self.path.push(2);
662 self.depth += 1;
663 for field in &oneof.fields {
664 self.path.push(field.path_index);
665 self.append_doc(fq_message_name, Some(field.descriptor.name()));
666 self.path.pop();
667
668 if self.deprecated(&field.descriptor) {
669 self.push_indent();
670 self.buf.push_str("#[deprecated]\n");
671 }
672
673 self.push_indent();
674 let ty_tag = self.field_type_tag(&field.descriptor);
675 self.buf.push_str(&format!(
676 "#[prost({}, tag = \"{}\")]\n",
677 ty_tag,
678 field.descriptor.number()
679 ));
680 self.append_field_attributes(&oneof_name, field.descriptor.name());
681
682 self.push_indent();
683 let ty = self.resolve_type(&field.descriptor, fq_message_name);
684
685 let boxed = self.context.should_box_oneof_field(
686 fq_message_name,
687 oneof.descriptor.name(),
688 &field.descriptor,
689 );
690
691 debug!(
692 " oneof: {:?}, type: {:?}, boxed: {}",
693 field.descriptor.name(),
694 ty,
695 boxed
696 );
697
698 if boxed {
699 self.buf.push_str(&format!(
700 "{}({}::alloc::boxed::Box<{}>),\n",
701 to_upper_camel(field.descriptor.name()),
702 self.context.prost_path(),
703 ty
704 ));
705 } else {
706 self.buf.push_str(&format!(
707 "{}({}),\n",
708 to_upper_camel(field.descriptor.name()),
709 ty
710 ));
711 }
712 }
713 self.depth -= 1;
714 self.path.pop();
715
716 self.push_indent();
717 self.buf.push_str("}\n");
718 }
719
720 fn location(&self) -> Option<&Location> {
721 let source_info = self.source_info.as_ref()?;
722 let idx = source_info
723 .location
724 .binary_search_by_key(&&self.path[..], |location| &location.path[..])
725 .unwrap();
726 Some(&source_info.location[idx])
727 }
728
729 fn append_doc(&mut self, fq_name: &str, field_name: Option<&str>) {
730 if !self.context.should_disable_comments(fq_name, field_name) {
731 if let Some(comments) = self.location().map(Comments::from_location) {
732 comments.append_with_indent(self.depth, self.buf);
733 }
734 }
735 }
736
737 fn append_enum(&mut self, desc: EnumDescriptorProto) {
738 debug!(" enum: {:?}", desc.name());
739
740 let proto_enum_name = desc.name();
741 let enum_name = to_upper_camel(proto_enum_name);
742
743 let enum_values = &desc.value;
744 let fq_proto_enum_name = self.fq_name(proto_enum_name);
745
746 if self
747 .context
748 .resolve_extern_ident(&fq_proto_enum_name)
749 .is_some()
750 {
751 return;
752 }
753
754 self.append_doc(&fq_proto_enum_name, None);
755 self.append_type_attributes(&fq_proto_enum_name);
756 self.append_enum_attributes(&fq_proto_enum_name);
757 self.push_indent();
758 let dbg = if self.context.should_skip_debug(&fq_proto_enum_name) {
759 ""
760 } else {
761 "Debug, "
762 };
763 self.buf.push_str(&format!(
764 "#[derive(Clone, Copy, {}PartialEq, Eq, Hash, PartialOrd, Ord, {}::Enumeration)]\n",
765 dbg,
766 self.context.prost_path(),
767 ));
768 self.append_prost_path_attribute();
769 self.push_indent();
770 self.buf.push_str("#[repr(i32)]\n");
771 self.push_indent();
772 self.buf.push_str("pub enum ");
773 self.buf.push_str(&enum_name);
774 self.buf.push_str(" {\n");
775
776 let variant_mappings =
777 build_enum_value_mappings(&enum_name, self.config().strip_enum_prefix, enum_values);
778
779 self.depth += 1;
780 self.path.push(2);
781 for variant in variant_mappings.iter() {
782 self.path.push(variant.path_idx as i32);
783
784 self.append_doc(&fq_proto_enum_name, Some(variant.proto_name));
785 self.append_field_attributes(&fq_proto_enum_name, variant.proto_name);
786 if variant.deprecated {
787 self.push_indent();
788 self.buf.push_str("#[deprecated]\n");
789 }
790 self.push_indent();
791 self.buf.push_str(&variant.generated_variant_name);
792 self.buf.push_str(" = ");
793 self.buf.push_str(&variant.proto_number.to_string());
794 self.buf.push_str(",\n");
795
796 self.path.pop();
797 }
798
799 self.path.pop();
800 self.depth -= 1;
801
802 self.push_indent();
803 self.buf.push_str("}\n");
804
805 self.push_indent();
806 self.buf.push_str("impl ");
807 self.buf.push_str(&enum_name);
808 self.buf.push_str(" {\n");
809 self.depth += 1;
810 self.path.push(2);
811
812 self.push_indent();
813 self.buf.push_str(
814 "/// String value of the enum field names used in the ProtoBuf definition.\n",
815 );
816 self.push_indent();
817 self.buf.push_str("///\n");
818 self.push_indent();
819 self.buf.push_str(
820 "/// The values are not transformed in any way and thus are considered stable\n",
821 );
822 self.push_indent();
823 self.buf.push_str(
824 "/// (if the ProtoBuf definition does not change) and safe for programmatic use.\n",
825 );
826 self.push_indent();
827 self.buf
828 .push_str("pub fn as_str_name(&self) -> &'static str {\n");
829 self.depth += 1;
830
831 self.push_indent();
832 self.buf.push_str("match self {\n");
833 self.depth += 1;
834
835 for variant in variant_mappings.iter() {
836 if variant.deprecated {
837 self.push_indent();
838 self.buf.push_str("#[allow(deprecated)]\n");
839 }
840 self.push_indent();
841 self.buf.push_str("Self::");
842 self.buf.push_str(&variant.generated_variant_name);
843 self.buf.push_str(" => \"");
844 self.buf.push_str(variant.proto_name);
845 self.buf.push_str("\",\n");
846 }
847
848 self.depth -= 1;
849 self.push_indent();
850 self.buf.push_str("}\n"); self.depth -= 1;
853 self.push_indent();
854 self.buf.push_str("}\n"); self.push_indent();
857 self.buf
858 .push_str("/// Creates an enum from field names used in the ProtoBuf definition.\n");
859
860 self.push_indent();
861 self.buf
862 .push_str("pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {\n");
863 self.depth += 1;
864
865 self.push_indent();
866 self.buf.push_str("match value {\n");
867 self.depth += 1;
868
869 for variant in variant_mappings.iter() {
870 self.push_indent();
871 self.buf.push('\"');
872 self.buf.push_str(variant.proto_name);
873 self.buf.push_str("\" => Some(");
874 if variant.deprecated {
875 self.buf.push_str("#[allow(deprecated)] ");
876 }
877 self.buf.push_str("Self::");
878 self.buf.push_str(&variant.generated_variant_name);
879 self.buf.push_str("),\n");
880 }
881 self.push_indent();
882 self.buf.push_str("_ => None,\n");
883
884 self.depth -= 1;
885 self.push_indent();
886 self.buf.push_str("}\n"); self.depth -= 1;
889 self.push_indent();
890 self.buf.push_str("}\n"); self.path.pop();
893 self.depth -= 1;
894 self.push_indent();
895 self.buf.push_str("}\n"); }
897
898 fn push_service(&mut self, service: ServiceDescriptorProto) {
899 let name = service.name().to_owned();
900 debug!(" service: {name:?}");
901
902 let comments = self
903 .location()
904 .map(Comments::from_location)
905 .unwrap_or_default();
906
907 self.path.push(2);
908 let methods = service
909 .method
910 .into_iter()
911 .enumerate()
912 .map(|(idx, mut method)| {
913 debug!(" method: {:?}", method.name());
914
915 self.path.push(idx as i32);
916 let comments = self
917 .location()
918 .map(Comments::from_location)
919 .unwrap_or_default();
920 self.path.pop();
921
922 let name = method.name.take().unwrap();
923 let input_proto_type = method.input_type.take().unwrap();
924 let output_proto_type = method.output_type.take().unwrap();
925 let input_type = self.resolve_ident(&input_proto_type);
926 let output_type = self.resolve_ident(&output_proto_type);
927 let client_streaming = method.client_streaming();
928 let server_streaming = method.server_streaming();
929
930 Method {
931 name: to_snake(&name),
932 proto_name: name,
933 comments,
934 input_type,
935 output_type,
936 input_proto_type,
937 output_proto_type,
938 options: method.options.unwrap_or_default(),
939 client_streaming,
940 server_streaming,
941 }
942 })
943 .collect();
944 self.path.pop();
945
946 let service = Service {
947 name: to_upper_camel(&name),
948 proto_name: name,
949 package: self.package.clone(),
950 comments,
951 methods,
952 options: service.options.unwrap_or_default(),
953 };
954
955 if let Some(service_generator) = self.context.service_generator_mut() {
956 service_generator.generate(service, self.buf)
957 }
958 }
959
960 fn push_indent(&mut self) {
961 push_indent(self.buf, self.depth);
962 }
963
964 fn push_mod(&mut self, module: &str) {
965 self.push_indent();
966 self.buf.push_str("/// Nested message and enum types in `");
967 self.buf.push_str(module);
968 self.buf.push_str("`.\n");
969
970 self.push_indent();
971 self.buf.push_str("pub mod ");
972 self.buf.push_str(&to_snake(module));
973 self.buf.push_str(" {\n");
974
975 self.type_path.push(module.into());
976
977 self.depth += 1;
978 }
979
980 fn pop_mod(&mut self) {
981 self.depth -= 1;
982
983 self.type_path.pop();
984
985 self.push_indent();
986 self.buf.push_str("}\n");
987 }
988
989 fn resolve_type(&self, field: &FieldDescriptorProto, fq_message_name: &str) -> String {
990 match field.r#type() {
991 Type::Float => String::from("f32"),
992 Type::Double => String::from("f64"),
993 Type::Uint32 | Type::Fixed32 => String::from("u32"),
994 Type::Uint64 | Type::Fixed64 => String::from("u64"),
995 Type::Int32 | Type::Sfixed32 | Type::Sint32 | Type::Enum => String::from("i32"),
996 Type::Int64 | Type::Sfixed64 | Type::Sint64 => String::from("i64"),
997 Type::Bool => String::from("bool"),
998 Type::String => format!("{}::alloc::string::String", self.context.prost_path()),
999 Type::Bytes => match self.context.bytes_type(fq_message_name, field.name()) {
1000 crate::BytesType::Vec => {
1001 format!("{}::alloc::vec::Vec<u8>", self.context.prost_path())
1002 }
1003 crate::BytesType::Bytes => format!("{}::bytes::Bytes", self.context.prost_path()),
1004 },
1005 Type::Group | Type::Message => self.resolve_ident(field.type_name()),
1006 }
1007 }
1008
1009 fn resolve_ident(&self, pb_ident: &str) -> String {
1010 assert_eq!(".", &pb_ident[..1]);
1012
1013 if let Some(proto_ident) = self.context.resolve_extern_ident(pb_ident) {
1014 return proto_ident;
1015 }
1016
1017 let mut local_path = self
1018 .package
1019 .split('.')
1020 .chain(self.type_path.iter().map(String::as_str))
1021 .peekable();
1022
1023 if local_path.peek().is_some_and(|s| s.is_empty()) {
1027 local_path.next();
1028 }
1029
1030 let mut ident_path = pb_ident[1..].split('.');
1031 let ident_type = ident_path.next_back().unwrap();
1032 let mut ident_path = ident_path.peekable();
1033
1034 while local_path.peek().is_some() && local_path.peek() == ident_path.peek() {
1036 local_path.next();
1037 ident_path.next();
1038 }
1039
1040 local_path
1041 .map(|_| "super".to_string())
1042 .chain(ident_path.map(to_snake))
1043 .chain(iter::once(to_upper_camel(ident_type)))
1044 .join("::")
1045 }
1046
1047 fn field_type_tag(&self, field: &FieldDescriptorProto) -> Cow<'static, str> {
1048 match field.r#type() {
1049 Type::Float => Cow::Borrowed("float"),
1050 Type::Double => Cow::Borrowed("double"),
1051 Type::Int32 => Cow::Borrowed("int32"),
1052 Type::Int64 => Cow::Borrowed("int64"),
1053 Type::Uint32 => Cow::Borrowed("uint32"),
1054 Type::Uint64 => Cow::Borrowed("uint64"),
1055 Type::Sint32 => Cow::Borrowed("sint32"),
1056 Type::Sint64 => Cow::Borrowed("sint64"),
1057 Type::Fixed32 => Cow::Borrowed("fixed32"),
1058 Type::Fixed64 => Cow::Borrowed("fixed64"),
1059 Type::Sfixed32 => Cow::Borrowed("sfixed32"),
1060 Type::Sfixed64 => Cow::Borrowed("sfixed64"),
1061 Type::Bool => Cow::Borrowed("bool"),
1062 Type::String => Cow::Borrowed("string"),
1063 Type::Bytes => Cow::Borrowed("bytes"),
1064 Type::Group => Cow::Borrowed("group"),
1065 Type::Message => Cow::Borrowed("message"),
1066 Type::Enum => Cow::Owned(format!(
1067 "enumeration = {:?}",
1068 self.resolve_ident(field.type_name())
1069 )),
1070 }
1071 }
1072
1073 fn map_value_type_tag(&self, field: &FieldDescriptorProto) -> Cow<'static, str> {
1074 match field.r#type() {
1075 Type::Enum => Cow::Owned(format!(
1076 "enumeration({})",
1077 self.resolve_ident(field.type_name())
1078 )),
1079 _ => self.field_type_tag(field),
1080 }
1081 }
1082
1083 fn optional(&self, field: &FieldDescriptorProto) -> bool {
1084 if field.proto3_optional.unwrap_or(false) {
1085 return true;
1086 }
1087
1088 if field.label() != Label::Optional {
1089 return false;
1090 }
1091
1092 match field.r#type() {
1093 Type::Message => true,
1094 _ => self.syntax == Syntax::Proto2,
1095 }
1096 }
1097
1098 fn deprecated(&self, field: &FieldDescriptorProto) -> bool {
1100 field.options.as_ref().is_some_and(FieldOptions::deprecated)
1101 }
1102
1103 fn fq_name(&self, message_name: &str) -> String {
1105 format!(
1106 "{}{}{}{}.{}",
1107 if self.package.is_empty() { "" } else { "." },
1108 self.package.trim_matches('.'),
1109 if self.type_path.is_empty() { "" } else { "." },
1110 self.type_path.join("."),
1111 message_name,
1112 )
1113 }
1114}
1115
1116fn can_pack(field: &FieldDescriptorProto) -> bool {
1118 matches!(
1119 field.r#type(),
1120 Type::Float
1121 | Type::Double
1122 | Type::Int32
1123 | Type::Int64
1124 | Type::Uint32
1125 | Type::Uint64
1126 | Type::Sint32
1127 | Type::Sint64
1128 | Type::Fixed32
1129 | Type::Fixed64
1130 | Type::Sfixed32
1131 | Type::Sfixed64
1132 | Type::Bool
1133 | Type::Enum
1134 )
1135}
1136
1137struct EnumVariantMapping<'a> {
1138 path_idx: usize,
1139 proto_name: &'a str,
1140 proto_number: i32,
1141 generated_variant_name: String,
1142 deprecated: bool,
1143}
1144
1145fn build_enum_value_mappings<'a>(
1146 generated_enum_name: &str,
1147 do_strip_enum_prefix: bool,
1148 enum_values: &'a [EnumValueDescriptorProto],
1149) -> Vec<EnumVariantMapping<'a>> {
1150 let mut numbers = HashSet::new();
1151 let mut generated_names = HashMap::new();
1152 let mut mappings = Vec::new();
1153
1154 for (idx, value) in enum_values.iter().enumerate() {
1155 if !numbers.insert(value.number()) {
1158 continue;
1159 }
1160
1161 let mut generated_variant_name = to_upper_camel(value.name());
1162 if do_strip_enum_prefix {
1163 generated_variant_name =
1164 strip_enum_prefix(generated_enum_name, &generated_variant_name);
1165 }
1166
1167 if let Some(old_v) = generated_names.insert(generated_variant_name.to_owned(), value.name())
1168 {
1169 panic!("Generated enum variant names overlap: `{}` variant name to be used both by `{}` and `{}` ProtoBuf enum values",
1170 generated_variant_name, old_v, value.name());
1171 }
1172
1173 mappings.push(EnumVariantMapping {
1174 path_idx: idx,
1175 proto_name: value.name(),
1176 proto_number: value.number(),
1177 generated_variant_name,
1178 deprecated: enum_field_deprecated(value),
1179 })
1180 }
1181 mappings
1182}
1183
1184fn enum_field_deprecated(value: &EnumValueDescriptorProto) -> bool {
1185 value
1186 .options
1187 .as_ref()
1188 .is_some_and(EnumValueOptions::deprecated)
1189}