prost_build/
code_generator.rs

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
28/// State object for the code generation process on a single input file.
29pub 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    // This type has the same name as another nested type at the same level
69    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        // Skip external types.
177        if self
178            .context
179            .resolve_extern_ident(&fq_message_name)
180            .is_some()
181        {
182            return;
183        }
184
185        // Split the nested message types into a vector of normal nested message types, and a map
186        // of the map field entry types. The path index of the nested message types is preserved so
187        // that comments can be retrieved.
188        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        // Split the fields into a vector of the normal fields, and oneof fields.
214        // Path indexes are preserved so that comments can be retrieved.
215        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        // Optional fields create a synthetic oneof that we want to skip
231        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                    // Field types are fully qualified, so we extract
495                    // the last segment and strip it from the left
496                    // side of the default value.
497                    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"); // End of match
851
852        self.depth -= 1;
853        self.push_indent();
854        self.buf.push_str("}\n"); // End of as_str_name()
855
856        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"); // End of match
887
888        self.depth -= 1;
889        self.push_indent();
890        self.buf.push_str("}\n"); // End of from_str_name()
891
892        self.path.pop();
893        self.depth -= 1;
894        self.push_indent();
895        self.buf.push_str("}\n"); // End of impl
896    }
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        // protoc should always give fully qualified identifiers.
1011        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 no package is specified the start of the package name will be '.'
1024        // and split will return an empty string ("") which breaks resolution
1025        // The fix to this is to ignore the first item if it is empty.
1026        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        // Skip path elements in common.
1035        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    /// Returns `true` if the field options includes the `deprecated` option.
1099    fn deprecated(&self, field: &FieldDescriptorProto) -> bool {
1100        field.options.as_ref().is_some_and(FieldOptions::deprecated)
1101    }
1102
1103    /// Returns the fully-qualified name, starting with a dot
1104    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
1116/// Returns `true` if the repeated field type can be packed.
1117fn 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        // Skip duplicate enum values. Protobuf allows this when the
1156        // 'allow_alias' option is set.
1157        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}