1mod option_resolver;
4mod type_resolver;
5
6use protobuf::descriptor::descriptor_proto::ReservedRange;
7use protobuf::descriptor::enum_descriptor_proto::EnumReservedRange;
8use protobuf::descriptor::field_descriptor_proto;
9use protobuf::descriptor::field_descriptor_proto::Type;
10use protobuf::descriptor::FieldDescriptorProto;
11use protobuf::descriptor::OneofDescriptorProto;
12use protobuf::reflect::FileDescriptor;
13use protobuf_support::json_name::json_name;
14use protobuf_support::text_format::escape_bytes_to;
15
16use crate::case_convert::camel_case;
17use crate::path::fs_path_to_proto_path;
18use crate::proto_path::ProtoPath;
19use crate::protobuf_abs_path::ProtobufAbsPath;
20use crate::protobuf_ident::ProtobufIdent;
21use crate::pure::convert::option_resolver::OptionResoler;
22use crate::pure::convert::option_resolver::ProtobufOptions;
23use crate::pure::convert::type_resolver::MessageOrEnum;
24use crate::pure::convert::type_resolver::TypeResolver;
25use crate::pure::model;
26use crate::FileDescriptorPair;
27use crate::ProtobufAbsPathRef;
28use crate::ProtobufIdentRef;
29
30#[derive(Debug, thiserror::Error)]
31enum 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
40pub struct WithFullName<T> {
41 full_name: ProtobufAbsPath,
42 t: T,
43}
44
45#[derive(Debug, PartialEq)]
46enum 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
67impl TypeResolved {
68 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
100 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
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
131pub(crate) struct Resolver<'a> {
132 type_resolver: TypeResolver<'a>,
133 current_file: &'a model::FileDescriptor,
134}
135
136impl<'a> Resolver<'a> {
137 fn map_entry_name_for_field_name(field_name: &str) -> ProtobufIdent {
138 ProtobufIdent::from(format!("{}Entry", camel_case(field_name)))
142 }
143
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 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
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
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
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 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.start());
300 extension_range.set_end(*ext.end() + 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.start());
317 reserved_range.set_end(*reserved.end() + 1);
318 output.reserved_range.push(reserved_range);
319 }
320 output.reserved_name = input.reserved_names.clone().into();
321
322 Ok(output)
323 }
324
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
345 if input.client_streaming {
346 output.set_client_streaming(input.client_streaming);
347 }
348
349 if input.server_streaming {
350 output.set_server_streaming(input.server_streaming);
351 }
352 Ok(output)
353 }
354
355 fn service(
356 &self,
357 input: &model::Service,
358 ) -> anyhow::Result<protobuf::descriptor::ServiceDescriptorProto> {
359 let mut output = protobuf::descriptor::ServiceDescriptorProto::new();
360 output.set_name(input.name.clone());
361
362 output.method = input
363 .methods
364 .iter()
365 .map(|m| self.service_method(m))
366 .collect::<Result<_, _>>()?;
367
368 Ok(output)
369 }
370
371 fn is_proto3_optional(&self, input: &model::WithLoc<model::Field>) -> bool {
372 (self.current_file.syntax, input.t.rule)
373 == (model::Syntax::Proto3, Some(model::Rule::Optional))
374 }
375
376 fn field(
377 &self,
378 scope: &ProtobufAbsPathRef,
379 input: &model::WithLoc<model::Field>,
380 oneof_index: Option<i32>,
381 ) -> anyhow::Result<protobuf::descriptor::FieldDescriptorProto> {
382 let mut output = protobuf::descriptor::FieldDescriptorProto::new();
383 output.set_name(input.t.name.clone());
384
385 if let model::FieldType::Map(..) = input.t.typ {
386 output.set_label(protobuf::descriptor::field_descriptor_proto::Label::LABEL_REPEATED);
387 } else {
388 output.set_label(label(input.t.rule));
389
390 if self.is_proto3_optional(input) {
391 output.set_proto3_optional(true);
392 }
393 }
394
395 let t = self.field_type(scope, &input.t.name, &input.t.typ)?;
396 output.set_type(t.type_enum());
397 if let Some(t_name) = t.type_name() {
398 output.set_type_name(t_name.path.clone());
399 }
400
401 output.set_number(input.t.number);
402 if let Some(ref default) = input.t.options.as_slice().by_name("default") {
404 let default = match output.type_() {
405 protobuf::descriptor::field_descriptor_proto::Type::TYPE_STRING => {
406 if let &model::ProtobufConstant::String(ref s) = default {
407 s.decode_utf8()?
408 } else {
409 return Err(ConvertError::DefaultValueIsNotStringLiteral.into());
410 }
411 }
412 protobuf::descriptor::field_descriptor_proto::Type::TYPE_BYTES => {
413 if let &model::ProtobufConstant::String(ref s) = default {
414 let mut buf = String::new();
415 escape_bytes_to(&s.decode_bytes()?, &mut buf);
416 buf
417 } else {
418 return Err(ConvertError::DefaultValueIsNotStringLiteral.into());
419 }
420 }
421 _ => default.format(),
422 };
423 output.set_default_value(default);
424 }
425
426 if let Some(oneof_index) = oneof_index {
427 output.set_oneof_index(oneof_index);
428 }
429
430 if let Some(json_name) = input.t.options.as_slice().by_name_string("json_name")? {
431 output.set_json_name(json_name);
432 } else {
433 output.set_json_name(json_name(&input.t.name));
434 }
435
436 Ok(output)
437 }
438
439 fn find_message_by_abs_name(
440 &self,
441 abs_path: &ProtobufAbsPath,
442 ) -> anyhow::Result<WithFullName<&'a model::Message>> {
443 let with_full_name = self
444 .type_resolver
445 .find_message_or_enum_by_abs_name(abs_path)?;
446 match with_full_name.t {
447 MessageOrEnum::Message(m) => Ok(WithFullName {
448 t: m,
449 full_name: with_full_name.full_name,
450 }),
451 MessageOrEnum::Enum(..) => Err(ConvertError::ExpectingMessage(abs_path.clone()).into()),
452 }
453 }
454
455 fn find_enum_by_abs_name(
456 &self,
457 abs_path: &ProtobufAbsPath,
458 ) -> anyhow::Result<&'a model::Enumeration> {
459 match self
460 .type_resolver
461 .find_message_or_enum_by_abs_name(abs_path)?
462 .t
463 {
464 MessageOrEnum::Enum(e) => Ok(e),
465 MessageOrEnum::Message(..) => Err(ConvertError::ExpectingEnum(abs_path.clone()).into()),
466 }
467 }
468
469 fn field_type(
470 &self,
471 scope: &ProtobufAbsPathRef,
472 name: &str,
473 input: &model::FieldType,
474 ) -> anyhow::Result<TypeResolved> {
475 Ok(match *input {
476 model::FieldType::Bool => TypeResolved::Bool,
477 model::FieldType::Int32 => TypeResolved::Int32,
478 model::FieldType::Int64 => TypeResolved::Int64,
479 model::FieldType::Uint32 => TypeResolved::Uint32,
480 model::FieldType::Uint64 => TypeResolved::Uint64,
481 model::FieldType::Sint32 => TypeResolved::Sint32,
482 model::FieldType::Sint64 => TypeResolved::Sint64,
483 model::FieldType::Fixed32 => TypeResolved::Fixed32,
484 model::FieldType::Fixed64 => TypeResolved::Fixed64,
485 model::FieldType::Sfixed32 => TypeResolved::Sfixed32,
486 model::FieldType::Sfixed64 => TypeResolved::Sfixed64,
487 model::FieldType::Float => TypeResolved::Float,
488 model::FieldType::Double => TypeResolved::Double,
489 model::FieldType::String => TypeResolved::String,
490 model::FieldType::Bytes => TypeResolved::Bytes,
491 model::FieldType::MessageOrEnum(ref name) => {
492 let t = self.type_resolver.resolve_message_or_enum(scope, &name)?;
493 match t.t {
494 MessageOrEnum::Message(..) => TypeResolved::Message(t.full_name),
495 MessageOrEnum::Enum(..) => TypeResolved::Enum(t.full_name),
496 }
497 }
498 model::FieldType::Map(..) => {
499 let mut type_name = scope.to_owned();
500 type_name.push_simple(&Resolver::map_entry_name_for_field_name(name));
501 TypeResolved::Message(type_name)
502 }
503 model::FieldType::Group(model::Group {
504 name: ref group_name,
505 ..
506 }) => {
507 let mut type_name = scope.to_owned();
508 type_name.push_simple(ProtobufIdentRef::new(group_name));
509 TypeResolved::Group(type_name)
510 }
511 })
512 }
513
514 fn enum_value(
515 &self,
516 _scope: &ProtobufAbsPathRef,
517 input: &model::EnumValue,
518 ) -> anyhow::Result<protobuf::descriptor::EnumValueDescriptorProto> {
519 let mut output = protobuf::descriptor::EnumValueDescriptorProto::new();
520 output.set_name(input.name.clone());
521 output.set_number(input.number);
522 Ok(output)
523 }
524
525 fn enumeration(
526 &self,
527 scope: &ProtobufAbsPathRef,
528 input: &model::Enumeration,
529 ) -> anyhow::Result<protobuf::descriptor::EnumDescriptorProto> {
530 let mut output = protobuf::descriptor::EnumDescriptorProto::new();
531 output.set_name(input.name.clone());
532 output.value = input
533 .values
534 .iter()
535 .map(|v| self.enum_value(scope, &v))
536 .collect::<Result<_, _>>()?;
537
538 for reserved in &input.reserved_nums {
539 let mut reserved_range = EnumReservedRange::new();
540 reserved_range.set_start(*reserved.start());
541 reserved_range.set_end(*reserved.end());
544 output.reserved_range.push(reserved_range);
545 }
546
547 output.reserved_name = input.reserved_names.clone().into();
548
549 Ok(output)
550 }
551
552 fn oneof(
553 &self,
554 _scope: &ProtobufAbsPathRef,
555 input: &model::OneOf,
556 ) -> anyhow::Result<protobuf::descriptor::OneofDescriptorProto> {
557 let mut output = protobuf::descriptor::OneofDescriptorProto::new();
558 output.set_name(input.name.clone());
559 Ok(output)
560 }
561
562 fn extension(
563 &self,
564 scope: &ProtobufAbsPath,
565 input: &model::Extension,
566 ) -> anyhow::Result<(
567 protobuf::descriptor::FieldDescriptorProto,
568 Option<protobuf::descriptor::DescriptorProto>,
569 )> {
570 let mut field = self.field(scope, &input.field, None)?;
571 field.set_extendee(
572 self.type_resolver
573 .resolve_message_or_enum(scope, &input.extendee)?
574 .full_name
575 .to_string(),
576 );
577 let group_messages = if let model::FieldType::Group(g) = &input.field.t.typ {
578 Some(self.group_message(scope, &g.name, &g.fields)?)
579 } else {
580 None
581 };
582 Ok((field, group_messages))
583 }
584}
585
586fn syntax(input: model::Syntax) -> String {
587 match input {
588 model::Syntax::Proto2 => "proto2".to_owned(),
589 model::Syntax::Proto3 => "proto3".to_owned(),
590 }
591}
592
593fn label(input: Option<model::Rule>) -> protobuf::descriptor::field_descriptor_proto::Label {
594 match input {
595 Some(model::Rule::Optional) => {
596 protobuf::descriptor::field_descriptor_proto::Label::LABEL_OPTIONAL
597 }
598 Some(model::Rule::Required) => {
599 protobuf::descriptor::field_descriptor_proto::Label::LABEL_REQUIRED
600 }
601 Some(model::Rule::Repeated) => {
602 protobuf::descriptor::field_descriptor_proto::Label::LABEL_REPEATED
603 }
604 None => protobuf::descriptor::field_descriptor_proto::Label::LABEL_OPTIONAL,
605 }
606}
607
608pub(crate) fn populate_dependencies(
609 input: &model::FileDescriptor,
610 output: &mut protobuf::descriptor::FileDescriptorProto,
611) {
612 for import in &input.imports {
613 if import.vis == model::ImportVis::Public {
614 output
615 .public_dependency
616 .push(output.dependency.len() as i32);
617 } else if import.vis == model::ImportVis::Weak {
618 output.weak_dependency.push(output.dependency.len() as i32);
619 }
620 output.dependency.push(import.path.to_string());
621 }
622}
623
624pub(crate) fn file_descriptor(
625 name: &ProtoPath,
626 input: &model::FileDescriptor,
627 deps: &[FileDescriptorPair],
628) -> anyhow::Result<protobuf::descriptor::FileDescriptorProto> {
629 let resolver = Resolver {
630 current_file: &input,
631 type_resolver: TypeResolver {
632 current_file: &input,
633 deps,
634 },
635 };
636
637 let mut output = protobuf::descriptor::FileDescriptorProto::new();
638 output.set_name(fs_path_to_proto_path(name));
639 output.set_syntax(syntax(input.syntax));
640
641 if input.package != ProtobufAbsPath::root() {
642 output.set_package(input.package.to_root_rel().to_string());
643 }
644
645 populate_dependencies(&input, &mut output);
646
647 let mut messages = Vec::new();
648 let mut services = Vec::new();
649
650 let mut extensions = Vec::new();
651 for e in &input.extensions {
652 let (ext, group_messages) = resolver.extension(&resolver.current_file.package, &e.t)?;
653 extensions.push(ext);
654 messages.extend(group_messages.map(model::WithLoc::with_loc(e.loc)));
655 }
656 output.extension = extensions;
657
658 for m in &input.messages {
659 let message = resolver.message(&resolver.current_file.package, &m.t)?;
660 messages.push(model::WithLoc {
661 t: message,
662 loc: m.loc,
663 });
664 }
665
666 for s in &input.services {
667 let service = resolver.service(&s.t)?;
668 services.push(model::WithLoc {
669 t: service,
670 loc: s.loc,
671 })
672 }
673
674 messages.sort_by_key(|m| m.loc);
676 output.message_type = messages
677 .into_iter()
678 .map(|model::WithLoc { t, .. }| t)
679 .collect();
680
681 output.enum_type = input
682 .enums
683 .iter()
684 .map(|e| resolver.enumeration(&resolver.current_file.package, e))
685 .collect::<Result<_, _>>()?;
686
687 output.service = services
688 .into_iter()
689 .map(|model::WithLoc { t, .. }| t)
690 .collect();
691
692 let descriptor_without_options = FileDescriptor::new_dynamic(
693 output.clone(),
694 &deps
695 .iter()
696 .map(|d| d.descriptor.clone())
697 .collect::<Vec<_>>(),
698 )?;
699
700 let option_resolver = OptionResoler {
701 resolver: &resolver,
702 descriptor_without_options,
703 };
704
705 option_resolver.file(&mut output)?;
706
707 Ok(output)
708}