1 //! Convert parser model to rust-protobuf model
2
3 mod option_resolver;
4 mod type_resolver;
5
6 use protobuf;
7 use protobuf::descriptor::descriptor_proto::ReservedRange;
8 use protobuf::descriptor::field_descriptor_proto;
9 use protobuf::descriptor::field_descriptor_proto::Type;
10 use protobuf::descriptor::FieldDescriptorProto;
11 use protobuf::descriptor::OneofDescriptorProto;
12 use protobuf::reflect::FileDescriptor;
13 use protobuf_support::json_name::json_name;
14 use protobuf_support::text_format::escape_bytes_to;
15
16 use crate::case_convert::camel_case;
17 use crate::path::fs_path_to_proto_path;
18 use crate::proto_path::ProtoPath;
19 use crate::protobuf_abs_path::ProtobufAbsPath;
20 use crate::protobuf_ident::ProtobufIdent;
21 use crate::pure::convert::option_resolver::OptionResoler;
22 use crate::pure::convert::option_resolver::ProtobufOptions;
23 use crate::pure::convert::type_resolver::MessageOrEnum;
24 use crate::pure::convert::type_resolver::TypeResolver;
25 use crate::pure::model;
26 use crate::FileDescriptorPair;
27 use crate::ProtobufAbsPathRef;
28 use crate::ProtobufIdentRef;
29
30 #[derive(Debug, thiserror::Error)]
31 enum ConvertError {
32 #[error("default value is not a string literal")]
33 DefaultValueIsNotStringLiteral,
34 #[error("expecting a message for name {0}")]
35 ExpectingMessage(ProtobufAbsPath),
36 #[error("expecting an enum for name {0}")]
37 ExpectingEnum(ProtobufAbsPath),
38 }
39
40 pub struct WithFullName<T> {
41 full_name: ProtobufAbsPath,
42 t: T,
43 }
44
45 #[derive(Debug, PartialEq)]
46 enum TypeResolved {
47 Int32,
48 Int64,
49 Uint32,
50 Uint64,
51 Sint32,
52 Sint64,
53 Bool,
54 Fixed64,
55 Sfixed64,
56 Double,
57 String,
58 Bytes,
59 Fixed32,
60 Sfixed32,
61 Float,
62 Message(ProtobufAbsPath),
63 Enum(ProtobufAbsPath),
64 Group(ProtobufAbsPath),
65 }
66
67 impl TypeResolved {
from_field(field: &FieldDescriptorProto) -> TypeResolved68 fn from_field(field: &FieldDescriptorProto) -> TypeResolved {
69 match field.type_() {
70 Type::TYPE_DOUBLE => TypeResolved::Double,
71 Type::TYPE_FLOAT => TypeResolved::Float,
72 Type::TYPE_INT64 => TypeResolved::Int64,
73 Type::TYPE_UINT64 => TypeResolved::Uint64,
74 Type::TYPE_INT32 => TypeResolved::Int32,
75 Type::TYPE_FIXED64 => TypeResolved::Fixed64,
76 Type::TYPE_FIXED32 => TypeResolved::Fixed32,
77 Type::TYPE_UINT32 => TypeResolved::Uint32,
78 Type::TYPE_SFIXED32 => TypeResolved::Sfixed32,
79 Type::TYPE_SFIXED64 => TypeResolved::Sfixed64,
80 Type::TYPE_SINT32 => TypeResolved::Sint32,
81 Type::TYPE_SINT64 => TypeResolved::Sint64,
82 Type::TYPE_BOOL => TypeResolved::Bool,
83 Type::TYPE_STRING => TypeResolved::String,
84 Type::TYPE_BYTES => TypeResolved::Bytes,
85 Type::TYPE_GROUP => {
86 assert!(!field.type_name().is_empty());
87 TypeResolved::Group(ProtobufAbsPath::new(field.type_name()))
88 }
89 Type::TYPE_ENUM => {
90 assert!(!field.type_name().is_empty());
91 TypeResolved::Enum(ProtobufAbsPath::new(field.type_name()))
92 }
93 Type::TYPE_MESSAGE => {
94 assert!(!field.type_name().is_empty());
95 TypeResolved::Message(ProtobufAbsPath::new(field.type_name()))
96 }
97 }
98 }
99
type_enum(&self) -> Type100 fn type_enum(&self) -> Type {
101 match self {
102 TypeResolved::Bool => Type::TYPE_BOOL,
103 TypeResolved::Int32 => Type::TYPE_INT32,
104 TypeResolved::Int64 => Type::TYPE_INT64,
105 TypeResolved::Uint32 => Type::TYPE_UINT32,
106 TypeResolved::Uint64 => Type::TYPE_UINT64,
107 TypeResolved::Sint32 => Type::TYPE_SINT32,
108 TypeResolved::Sint64 => Type::TYPE_SINT64,
109 TypeResolved::Fixed32 => Type::TYPE_FIXED32,
110 TypeResolved::Fixed64 => Type::TYPE_FIXED64,
111 TypeResolved::Sfixed32 => Type::TYPE_SFIXED32,
112 TypeResolved::Sfixed64 => Type::TYPE_SFIXED64,
113 TypeResolved::Float => Type::TYPE_FLOAT,
114 TypeResolved::Double => Type::TYPE_DOUBLE,
115 TypeResolved::String => Type::TYPE_STRING,
116 TypeResolved::Bytes => Type::TYPE_BYTES,
117 TypeResolved::Message(_) => Type::TYPE_MESSAGE,
118 TypeResolved::Enum(_) => Type::TYPE_ENUM,
119 TypeResolved::Group(_) => Type::TYPE_GROUP,
120 }
121 }
122
type_name(&self) -> Option<&ProtobufAbsPath>123 fn type_name(&self) -> Option<&ProtobufAbsPath> {
124 match self {
125 TypeResolved::Message(t) | TypeResolved::Enum(t) | TypeResolved::Group(t) => Some(t),
126 _ => None,
127 }
128 }
129 }
130
131 pub(crate) struct Resolver<'a> {
132 type_resolver: TypeResolver<'a>,
133 current_file: &'a model::FileDescriptor,
134 }
135
136 impl<'a> Resolver<'a> {
map_entry_name_for_field_name(field_name: &str) -> ProtobufIdent137 fn map_entry_name_for_field_name(field_name: &str) -> ProtobufIdent {
138 // Field name and message name must match, otherwise
139 // Google's validation fails.
140 // https://git.io/JeOvF
141 ProtobufIdent::from(format!("{}Entry", camel_case(field_name)))
142 }
143
map_entry_field( &self, scope: &ProtobufAbsPath, name: &str, number: i32, field_type: &model::FieldType, ) -> anyhow::Result<protobuf::descriptor::FieldDescriptorProto>144 fn map_entry_field(
145 &self,
146 scope: &ProtobufAbsPath,
147 name: &str,
148 number: i32,
149 field_type: &model::FieldType,
150 ) -> anyhow::Result<protobuf::descriptor::FieldDescriptorProto> {
151 // should be consisent with DescriptorBuilder::ValidateMapEntry
152
153 let mut output = protobuf::descriptor::FieldDescriptorProto::new();
154
155 output.set_name(name.to_owned());
156 output.set_number(number);
157
158 let t = self.field_type(&scope, name, field_type)?;
159 output.set_type(t.type_enum());
160 if let Some(t_name) = t.type_name() {
161 output.set_type_name(t_name.path.clone());
162 }
163
164 output.set_label(field_descriptor_proto::Label::LABEL_OPTIONAL);
165
166 output.set_json_name(json_name(&name));
167
168 Ok(output)
169 }
170
map_entry_message( &self, scope: &ProtobufAbsPath, field_name: &str, key: &model::FieldType, value: &model::FieldType, ) -> anyhow::Result<protobuf::descriptor::DescriptorProto>171 fn map_entry_message(
172 &self,
173 scope: &ProtobufAbsPath,
174 field_name: &str,
175 key: &model::FieldType,
176 value: &model::FieldType,
177 ) -> anyhow::Result<protobuf::descriptor::DescriptorProto> {
178 let mut output = protobuf::descriptor::DescriptorProto::new();
179
180 output.options.mut_or_insert_default().set_map_entry(true);
181 output.set_name(Resolver::map_entry_name_for_field_name(field_name).into_string());
182 output
183 .field
184 .push(self.map_entry_field(&scope, "key", 1, key)?);
185 output
186 .field
187 .push(self.map_entry_field(&scope, "value", 2, value)?);
188
189 Ok(output)
190 }
191
group_message( &self, scope: &ProtobufAbsPath, name: &str, fields: &[model::WithLoc<model::Field>], ) -> anyhow::Result<protobuf::descriptor::DescriptorProto>192 fn group_message(
193 &self,
194 scope: &ProtobufAbsPath,
195 name: &str,
196 fields: &[model::WithLoc<model::Field>],
197 ) -> anyhow::Result<protobuf::descriptor::DescriptorProto> {
198 let mut output = protobuf::descriptor::DescriptorProto::new();
199
200 output.set_name(name.to_owned());
201
202 for f in fields {
203 output.field.push(self.field(scope, f, None)?);
204 }
205
206 Ok(output)
207 }
208
message( &self, scope: &ProtobufAbsPathRef, input: &model::Message, ) -> anyhow::Result<protobuf::descriptor::DescriptorProto>209 fn message(
210 &self,
211 scope: &ProtobufAbsPathRef,
212 input: &model::Message,
213 ) -> anyhow::Result<protobuf::descriptor::DescriptorProto> {
214 let mut nested_scope = scope.to_owned();
215 nested_scope.push_simple(ProtobufIdentRef::new(&input.name));
216
217 let mut output = protobuf::descriptor::DescriptorProto::new();
218 output.set_name(input.name.clone());
219
220 let mut nested_messages = Vec::new();
221
222 for m in &input.messages {
223 let message = self.message(&nested_scope, &m.t)?;
224 nested_messages.push(model::WithLoc {
225 t: message,
226 loc: m.loc,
227 });
228 }
229
230 for f in input.regular_fields_including_in_oneofs() {
231 match &f.t.typ {
232 model::FieldType::Map(t) => {
233 let message = self.map_entry_message(&nested_scope, &f.t.name, &t.0, &t.1)?;
234 nested_messages.push(model::WithLoc {
235 t: message,
236 loc: f.loc,
237 });
238 }
239 model::FieldType::Group(model::Group {
240 name: group_name,
241 fields,
242 ..
243 }) => {
244 let message = self.group_message(&nested_scope, group_name, fields)?;
245 nested_messages.push(model::WithLoc {
246 t: message,
247 loc: f.loc,
248 });
249 }
250 _ => (),
251 }
252 }
253
254 // Preserve declaration order
255 nested_messages.sort_by_key(|m| m.loc);
256 output.nested_type = nested_messages
257 .into_iter()
258 .map(|model::WithLoc { t, .. }| t)
259 .collect();
260
261 output.enum_type = input
262 .enums
263 .iter()
264 .map(|e| self.enumeration(scope, e))
265 .collect::<Result<_, _>>()?;
266
267 {
268 let mut fields = Vec::new();
269
270 for fo in &input.fields {
271 match &fo.t {
272 model::FieldOrOneOf::Field(f) => {
273 let oneof_index = if self.is_proto3_optional(f) {
274 let oneof_index = output.oneof_decl.len() as i32;
275 let mut oneof = OneofDescriptorProto::new();
276 oneof.set_name(format!("_{}", f.name));
277 output.oneof_decl.push(oneof);
278 Some(oneof_index)
279 } else {
280 None
281 };
282 fields.push(self.field(&nested_scope, f, oneof_index)?);
283 }
284 model::FieldOrOneOf::OneOf(o) => {
285 let oneof_index = output.oneof_decl.len();
286 for f in &o.fields {
287 fields.push(self.field(&nested_scope, f, Some(oneof_index as i32))?);
288 }
289 output.oneof_decl.push(self.oneof(scope, o)?);
290 }
291 }
292 }
293
294 output.field = fields;
295 }
296
297 for ext in &input.extension_ranges {
298 let mut extension_range = protobuf::descriptor::descriptor_proto::ExtensionRange::new();
299 extension_range.set_start(ext.from);
300 extension_range.set_end(ext.to + 1);
301 output.extension_range.push(extension_range);
302 }
303 for ext in &input.extensions {
304 let mut extension = self.field(scope, &ext.t.field, None)?;
305 extension.set_extendee(
306 self.type_resolver
307 .resolve_message_or_enum(scope, &ext.t.extendee)?
308 .full_name
309 .path,
310 );
311 output.extension.push(extension);
312 }
313
314 for reserved in &input.reserved_nums {
315 let mut reserved_range = ReservedRange::new();
316 reserved_range.set_start(reserved.from);
317 reserved_range.set_end(reserved.to + 1);
318 output.reserved_range.push(reserved_range);
319 }
320 output.reserved_name = input.reserved_names.clone().into();
321
322 Ok(output)
323 }
324
service_method( &self, input: &model::Method, ) -> anyhow::Result<protobuf::descriptor::MethodDescriptorProto>325 fn service_method(
326 &self,
327 input: &model::Method,
328 ) -> anyhow::Result<protobuf::descriptor::MethodDescriptorProto> {
329 let scope = &self.current_file.package;
330 let mut output = protobuf::descriptor::MethodDescriptorProto::new();
331 output.set_name(input.name.clone());
332 output.set_input_type(
333 self.type_resolver
334 .resolve_message_or_enum(scope, &input.input_type)?
335 .full_name
336 .to_string(),
337 );
338 output.set_output_type(
339 self.type_resolver
340 .resolve_message_or_enum(scope, &input.output_type)?
341 .full_name
342 .to_string(),
343 );
344 Ok(output)
345 }
346
service( &self, input: &model::Service, ) -> anyhow::Result<protobuf::descriptor::ServiceDescriptorProto>347 fn service(
348 &self,
349 input: &model::Service,
350 ) -> anyhow::Result<protobuf::descriptor::ServiceDescriptorProto> {
351 let mut output = protobuf::descriptor::ServiceDescriptorProto::new();
352 output.set_name(input.name.clone());
353
354 output.method = input
355 .methods
356 .iter()
357 .map(|m| self.service_method(m))
358 .collect::<Result<_, _>>()?;
359
360 Ok(output)
361 }
362
is_proto3_optional(&self, input: &model::WithLoc<model::Field>) -> bool363 fn is_proto3_optional(&self, input: &model::WithLoc<model::Field>) -> bool {
364 (self.current_file.syntax, input.t.rule)
365 == (model::Syntax::Proto3, Some(model::Rule::Optional))
366 }
367
field( &self, scope: &ProtobufAbsPathRef, input: &model::WithLoc<model::Field>, oneof_index: Option<i32>, ) -> anyhow::Result<protobuf::descriptor::FieldDescriptorProto>368 fn field(
369 &self,
370 scope: &ProtobufAbsPathRef,
371 input: &model::WithLoc<model::Field>,
372 oneof_index: Option<i32>,
373 ) -> anyhow::Result<protobuf::descriptor::FieldDescriptorProto> {
374 let mut output = protobuf::descriptor::FieldDescriptorProto::new();
375 output.set_name(input.t.name.clone());
376
377 if let model::FieldType::Map(..) = input.t.typ {
378 output.set_label(protobuf::descriptor::field_descriptor_proto::Label::LABEL_REPEATED);
379 } else {
380 output.set_label(label(input.t.rule));
381
382 if self.is_proto3_optional(input) {
383 output.set_proto3_optional(true);
384 }
385 }
386
387 let t = self.field_type(scope, &input.t.name, &input.t.typ)?;
388 output.set_type(t.type_enum());
389 if let Some(t_name) = t.type_name() {
390 output.set_type_name(t_name.path.clone());
391 }
392
393 output.set_number(input.t.number);
394 // TODO: move default to option parser
395 if let Some(ref default) = input.t.options.as_slice().by_name("default") {
396 let default = match output.type_() {
397 protobuf::descriptor::field_descriptor_proto::Type::TYPE_STRING => {
398 if let &model::ProtobufConstant::String(ref s) = default {
399 s.decode_utf8()?
400 } else {
401 return Err(ConvertError::DefaultValueIsNotStringLiteral.into());
402 }
403 }
404 protobuf::descriptor::field_descriptor_proto::Type::TYPE_BYTES => {
405 if let &model::ProtobufConstant::String(ref s) = default {
406 let mut buf = String::new();
407 escape_bytes_to(&s.decode_bytes()?, &mut buf);
408 buf
409 } else {
410 return Err(ConvertError::DefaultValueIsNotStringLiteral.into());
411 }
412 }
413 _ => default.format(),
414 };
415 output.set_default_value(default);
416 }
417
418 if let Some(oneof_index) = oneof_index {
419 output.set_oneof_index(oneof_index);
420 }
421
422 if let Some(json_name) = input.t.options.as_slice().by_name_string("json_name")? {
423 output.set_json_name(json_name);
424 } else {
425 output.set_json_name(json_name(&input.t.name));
426 }
427
428 Ok(output)
429 }
430
find_message_by_abs_name( &self, abs_path: &ProtobufAbsPath, ) -> anyhow::Result<WithFullName<&'a model::Message>>431 fn find_message_by_abs_name(
432 &self,
433 abs_path: &ProtobufAbsPath,
434 ) -> anyhow::Result<WithFullName<&'a model::Message>> {
435 let with_full_name = self
436 .type_resolver
437 .find_message_or_enum_by_abs_name(abs_path)?;
438 match with_full_name.t {
439 MessageOrEnum::Message(m) => Ok(WithFullName {
440 t: m,
441 full_name: with_full_name.full_name,
442 }),
443 MessageOrEnum::Enum(..) => Err(ConvertError::ExpectingMessage(abs_path.clone()).into()),
444 }
445 }
446
find_enum_by_abs_name( &self, abs_path: &ProtobufAbsPath, ) -> anyhow::Result<&'a model::Enumeration>447 fn find_enum_by_abs_name(
448 &self,
449 abs_path: &ProtobufAbsPath,
450 ) -> anyhow::Result<&'a model::Enumeration> {
451 match self
452 .type_resolver
453 .find_message_or_enum_by_abs_name(abs_path)?
454 .t
455 {
456 MessageOrEnum::Enum(e) => Ok(e),
457 MessageOrEnum::Message(..) => Err(ConvertError::ExpectingEnum(abs_path.clone()).into()),
458 }
459 }
460
field_type( &self, scope: &ProtobufAbsPathRef, name: &str, input: &model::FieldType, ) -> anyhow::Result<TypeResolved>461 fn field_type(
462 &self,
463 scope: &ProtobufAbsPathRef,
464 name: &str,
465 input: &model::FieldType,
466 ) -> anyhow::Result<TypeResolved> {
467 Ok(match *input {
468 model::FieldType::Bool => TypeResolved::Bool,
469 model::FieldType::Int32 => TypeResolved::Int32,
470 model::FieldType::Int64 => TypeResolved::Int64,
471 model::FieldType::Uint32 => TypeResolved::Uint32,
472 model::FieldType::Uint64 => TypeResolved::Uint64,
473 model::FieldType::Sint32 => TypeResolved::Sint32,
474 model::FieldType::Sint64 => TypeResolved::Sint64,
475 model::FieldType::Fixed32 => TypeResolved::Fixed32,
476 model::FieldType::Fixed64 => TypeResolved::Fixed64,
477 model::FieldType::Sfixed32 => TypeResolved::Sfixed32,
478 model::FieldType::Sfixed64 => TypeResolved::Sfixed64,
479 model::FieldType::Float => TypeResolved::Float,
480 model::FieldType::Double => TypeResolved::Double,
481 model::FieldType::String => TypeResolved::String,
482 model::FieldType::Bytes => TypeResolved::Bytes,
483 model::FieldType::MessageOrEnum(ref name) => {
484 let t = self.type_resolver.resolve_message_or_enum(scope, &name)?;
485 match t.t {
486 MessageOrEnum::Message(..) => TypeResolved::Message(t.full_name),
487 MessageOrEnum::Enum(..) => TypeResolved::Enum(t.full_name),
488 }
489 }
490 model::FieldType::Map(..) => {
491 let mut type_name = scope.to_owned();
492 type_name.push_simple(&Resolver::map_entry_name_for_field_name(name));
493 TypeResolved::Message(type_name)
494 }
495 model::FieldType::Group(model::Group {
496 name: ref group_name,
497 ..
498 }) => {
499 let mut type_name = scope.to_owned();
500 type_name.push_simple(ProtobufIdentRef::new(group_name));
501 TypeResolved::Group(type_name)
502 }
503 })
504 }
505
enum_value( &self, _scope: &ProtobufAbsPathRef, input: &model::EnumValue, ) -> anyhow::Result<protobuf::descriptor::EnumValueDescriptorProto>506 fn enum_value(
507 &self,
508 _scope: &ProtobufAbsPathRef,
509 input: &model::EnumValue,
510 ) -> anyhow::Result<protobuf::descriptor::EnumValueDescriptorProto> {
511 let mut output = protobuf::descriptor::EnumValueDescriptorProto::new();
512 output.set_name(input.name.clone());
513 output.set_number(input.number);
514 Ok(output)
515 }
516
enumeration( &self, scope: &ProtobufAbsPathRef, input: &model::Enumeration, ) -> anyhow::Result<protobuf::descriptor::EnumDescriptorProto>517 fn enumeration(
518 &self,
519 scope: &ProtobufAbsPathRef,
520 input: &model::Enumeration,
521 ) -> anyhow::Result<protobuf::descriptor::EnumDescriptorProto> {
522 let mut output = protobuf::descriptor::EnumDescriptorProto::new();
523 output.set_name(input.name.clone());
524 output.value = input
525 .values
526 .iter()
527 .map(|v| self.enum_value(scope, &v))
528 .collect::<Result<_, _>>()?;
529 Ok(output)
530 }
531
oneof( &self, _scope: &ProtobufAbsPathRef, input: &model::OneOf, ) -> anyhow::Result<protobuf::descriptor::OneofDescriptorProto>532 fn oneof(
533 &self,
534 _scope: &ProtobufAbsPathRef,
535 input: &model::OneOf,
536 ) -> anyhow::Result<protobuf::descriptor::OneofDescriptorProto> {
537 let mut output = protobuf::descriptor::OneofDescriptorProto::new();
538 output.set_name(input.name.clone());
539 Ok(output)
540 }
541
extension( &self, scope: &ProtobufAbsPath, input: &model::Extension, ) -> anyhow::Result<( protobuf::descriptor::FieldDescriptorProto, Option<protobuf::descriptor::DescriptorProto>, )>542 fn extension(
543 &self,
544 scope: &ProtobufAbsPath,
545 input: &model::Extension,
546 ) -> anyhow::Result<(
547 protobuf::descriptor::FieldDescriptorProto,
548 Option<protobuf::descriptor::DescriptorProto>,
549 )> {
550 let mut field = self.field(scope, &input.field, None)?;
551 field.set_extendee(
552 self.type_resolver
553 .resolve_message_or_enum(scope, &input.extendee)?
554 .full_name
555 .to_string(),
556 );
557 let group_messages = if let model::FieldType::Group(g) = &input.field.t.typ {
558 Some(self.group_message(scope, &g.name, &g.fields)?)
559 } else {
560 None
561 };
562 Ok((field, group_messages))
563 }
564 }
565
syntax(input: model::Syntax) -> String566 fn syntax(input: model::Syntax) -> String {
567 match input {
568 model::Syntax::Proto2 => "proto2".to_owned(),
569 model::Syntax::Proto3 => "proto3".to_owned(),
570 }
571 }
572
label(input: Option<model::Rule>) -> protobuf::descriptor::field_descriptor_proto::Label573 fn label(input: Option<model::Rule>) -> protobuf::descriptor::field_descriptor_proto::Label {
574 match input {
575 Some(model::Rule::Optional) => {
576 protobuf::descriptor::field_descriptor_proto::Label::LABEL_OPTIONAL
577 }
578 Some(model::Rule::Required) => {
579 protobuf::descriptor::field_descriptor_proto::Label::LABEL_REQUIRED
580 }
581 Some(model::Rule::Repeated) => {
582 protobuf::descriptor::field_descriptor_proto::Label::LABEL_REPEATED
583 }
584 None => protobuf::descriptor::field_descriptor_proto::Label::LABEL_OPTIONAL,
585 }
586 }
587
populate_dependencies( input: &model::FileDescriptor, output: &mut protobuf::descriptor::FileDescriptorProto, )588 pub(crate) fn populate_dependencies(
589 input: &model::FileDescriptor,
590 output: &mut protobuf::descriptor::FileDescriptorProto,
591 ) {
592 for import in &input.imports {
593 if import.vis == model::ImportVis::Public {
594 output
595 .public_dependency
596 .push(output.dependency.len() as i32);
597 } else if import.vis == model::ImportVis::Weak {
598 output.weak_dependency.push(output.dependency.len() as i32);
599 }
600 output.dependency.push(import.path.to_string());
601 }
602 }
603
file_descriptor( name: &ProtoPath, input: &model::FileDescriptor, deps: &[FileDescriptorPair], ) -> anyhow::Result<protobuf::descriptor::FileDescriptorProto>604 pub(crate) fn file_descriptor(
605 name: &ProtoPath,
606 input: &model::FileDescriptor,
607 deps: &[FileDescriptorPair],
608 ) -> anyhow::Result<protobuf::descriptor::FileDescriptorProto> {
609 let resolver = Resolver {
610 current_file: &input,
611 type_resolver: TypeResolver {
612 current_file: &input,
613 deps,
614 },
615 };
616
617 let mut output = protobuf::descriptor::FileDescriptorProto::new();
618 output.set_name(fs_path_to_proto_path(name));
619 output.set_syntax(syntax(input.syntax));
620
621 if input.package != ProtobufAbsPath::root() {
622 output.set_package(input.package.to_root_rel().to_string());
623 }
624
625 populate_dependencies(&input, &mut output);
626
627 let mut messages = Vec::new();
628 let mut services = Vec::new();
629
630 let mut extensions = Vec::new();
631 for e in &input.extensions {
632 let (ext, group_messages) = resolver.extension(&resolver.current_file.package, &e.t)?;
633 extensions.push(ext);
634 messages.extend(group_messages.map(model::WithLoc::with_loc(e.loc)));
635 }
636 output.extension = extensions;
637
638 for m in &input.messages {
639 let message = resolver.message(&resolver.current_file.package, &m.t)?;
640 messages.push(model::WithLoc {
641 t: message,
642 loc: m.loc,
643 });
644 }
645
646 for s in &input.services {
647 let service = resolver.service(&s.t)?;
648 services.push(model::WithLoc {
649 t: service,
650 loc: s.loc,
651 })
652 }
653
654 // Preserve declaration order
655 messages.sort_by_key(|m| m.loc);
656 output.message_type = messages
657 .into_iter()
658 .map(|model::WithLoc { t, .. }| t)
659 .collect();
660
661 output.enum_type = input
662 .enums
663 .iter()
664 .map(|e| resolver.enumeration(&resolver.current_file.package, e))
665 .collect::<Result<_, _>>()?;
666
667 output.service = services
668 .into_iter()
669 .map(|model::WithLoc { t, .. }| t)
670 .collect();
671
672 let descriptor_without_options = FileDescriptor::new_dynamic(
673 output.clone(),
674 &deps
675 .iter()
676 .map(|d| d.descriptor.clone())
677 .collect::<Vec<_>>(),
678 )?;
679
680 let option_resolver = OptionResoler {
681 resolver: &resolver,
682 descriptor_without_options,
683 };
684
685 option_resolver.file(&mut output)?;
686
687 Ok(output)
688 }
689