1 use std::collections::HashMap; 2 use std::iter; 3 4 use crate::descriptor::field_descriptor_proto; 5 use crate::descriptor::DescriptorProto; 6 use crate::descriptor::EnumDescriptorProto; 7 use crate::descriptor::FieldDescriptorProto; 8 use crate::descriptor::FileDescriptorProto; 9 use crate::reflect::error::ReflectError; 10 use crate::reflect::field::index::ForwardProtobufFieldType; 11 use crate::reflect::field::index::ForwardProtobufTypeBox; 12 use crate::reflect::file::index::MessageIndices; 13 use crate::reflect::find_message_or_enum::find_message_or_enum; 14 use crate::reflect::find_message_or_enum::MessageOrEnum; 15 use crate::reflect::name::protobuf_name_starts_with_package; 16 use crate::reflect::runtime_type_box::RuntimeType; 17 use crate::reflect::FileDescriptor; 18 19 pub(crate) struct FileDescriptorBuilding<'a> { 20 pub(crate) current_file_descriptor: &'a FileDescriptorProto, 21 pub(crate) deps_with_public: &'a [FileDescriptor], 22 pub(crate) message_by_name_to_package: &'a HashMap<String, usize>, 23 pub(crate) messages: &'a [MessageIndices], 24 pub(crate) enums_by_name_to_package: &'a HashMap<String, usize>, 25 } 26 27 impl<'a> FileDescriptorBuilding<'a> { all_descriptors(&self) -> impl Iterator<Item = &'a FileDescriptorProto>28 fn all_descriptors(&self) -> impl Iterator<Item = &'a FileDescriptorProto> { 29 iter::once(self.current_file_descriptor) 30 .chain(self.deps_with_public.iter().map(|d| d.proto())) 31 } 32 find_enum(&self, full_name: &str) -> &'a EnumDescriptorProto33 pub fn find_enum(&self, full_name: &str) -> &'a EnumDescriptorProto { 34 assert!(full_name.starts_with(".")); 35 36 for file in self.all_descriptors() { 37 if let Some(name_to_package) = 38 protobuf_name_starts_with_package(full_name, file.package()) 39 { 40 if let Some((_, me)) = find_message_or_enum(file, name_to_package) { 41 match me { 42 MessageOrEnum::Enum(e) => return e, 43 MessageOrEnum::Message(_) => panic!("not an enum: {}", full_name), 44 } 45 } 46 } 47 } 48 49 panic!( 50 "enum not found: {}, in files: {}", 51 full_name, 52 self.all_files_str() 53 ); 54 } 55 all_files_str(&self) -> String56 fn all_files_str(&self) -> String { 57 self.all_descriptors() 58 .map(|d| d.name()) 59 .collect::<Vec<_>>() 60 .join(", ") 61 } 62 resolve_field_type( &self, field: &FieldDescriptorProto, ) -> crate::Result<ForwardProtobufFieldType>63 pub(crate) fn resolve_field_type( 64 &self, 65 field: &FieldDescriptorProto, 66 ) -> crate::Result<ForwardProtobufFieldType> { 67 Ok(match field.label() { 68 field_descriptor_proto::Label::LABEL_OPTIONAL 69 | field_descriptor_proto::Label::LABEL_REQUIRED => { 70 ForwardProtobufFieldType::Singular(self.resolve_field_element_type(field)?) 71 } 72 field_descriptor_proto::Label::LABEL_REPEATED => { 73 let element = self.resolve_field_element_type(field)?; 74 let type_proto = match &element { 75 ForwardProtobufTypeBox::CurrentFileMessage(m) => { 76 Some(&*self.messages[*m].proto) 77 } 78 ForwardProtobufTypeBox::ProtobufTypeBox(t) => match t.runtime() { 79 RuntimeType::Message(m) => Some(m.proto()), 80 _ => None, 81 }, 82 _ => None, 83 }; 84 match type_proto { 85 Some(m) if m.options.get_or_default().map_entry() => self.map_field(m)?, 86 _ => ForwardProtobufFieldType::Repeated(element), 87 } 88 } 89 }) 90 } 91 resolve_field_element_type( &self, field: &FieldDescriptorProto, ) -> crate::Result<ForwardProtobufTypeBox>92 fn resolve_field_element_type( 93 &self, 94 field: &FieldDescriptorProto, 95 ) -> crate::Result<ForwardProtobufTypeBox> { 96 Ok(match field.type_() { 97 field_descriptor_proto::Type::TYPE_MESSAGE 98 | field_descriptor_proto::Type::TYPE_GROUP => { 99 self.resolve_message(field.type_name())? 100 } 101 field_descriptor_proto::Type::TYPE_ENUM => { 102 if let Some(name_to_package) = protobuf_name_starts_with_package( 103 field.type_name(), 104 self.current_file_descriptor.package(), 105 ) { 106 if let Some(index) = self.enums_by_name_to_package.get(name_to_package) { 107 return Ok(ForwardProtobufTypeBox::CurrentFileEnum(*index)); 108 } 109 } 110 for dep in self.deps_with_public { 111 if let Some(m) = dep.enum_by_full_name(field.type_name()) { 112 return Ok(ForwardProtobufTypeBox::enumeration(m)); 113 } 114 } 115 panic!( 116 "enum not found: {}; files: {}", 117 field.type_name(), 118 self.all_files_str() 119 ); 120 } 121 t => ForwardProtobufTypeBox::from_proto_type(t), 122 }) 123 } 124 resolve_message(&self, type_name: &str) -> crate::Result<ForwardProtobufTypeBox>125 pub(crate) fn resolve_message(&self, type_name: &str) -> crate::Result<ForwardProtobufTypeBox> { 126 if let Some(name_to_package) = 127 protobuf_name_starts_with_package(type_name, self.current_file_descriptor.package()) 128 { 129 if let Some(index) = self.message_by_name_to_package.get(name_to_package) { 130 return Ok(ForwardProtobufTypeBox::CurrentFileMessage(*index)); 131 } 132 } 133 for dep in self.deps_with_public { 134 if let Some(m) = dep.message_by_full_name(type_name) { 135 return Ok(ForwardProtobufTypeBox::message(m)); 136 } 137 } 138 Err(ReflectError::MessageNotFoundInFiles(type_name.to_owned(), self.all_files_str()).into()) 139 } 140 map_field(&self, type_proto: &DescriptorProto) -> crate::Result<ForwardProtobufFieldType>141 fn map_field(&self, type_proto: &DescriptorProto) -> crate::Result<ForwardProtobufFieldType> { 142 assert!(type_proto.name().ends_with("Entry")); 143 144 assert_eq!(0, type_proto.extension.len()); 145 assert_eq!(0, type_proto.extension_range.len()); 146 assert_eq!(0, type_proto.nested_type.len()); 147 assert_eq!(0, type_proto.enum_type.len()); 148 149 assert_eq!(2, type_proto.field.len()); 150 let key = &type_proto.field[0]; 151 let value = &type_proto.field[1]; 152 153 assert_eq!("key", key.name()); 154 assert_eq!("value", value.name()); 155 156 assert_eq!(1, key.number()); 157 assert_eq!(2, value.number()); 158 159 assert_eq!(field_descriptor_proto::Label::LABEL_OPTIONAL, key.label()); 160 assert_eq!(field_descriptor_proto::Label::LABEL_OPTIONAL, value.label()); 161 162 // It is OK to resolve using current descriptor because map field 163 // should always point to the same file. 164 let key = self.resolve_field_element_type(key)?; 165 let value = self.resolve_field_element_type(value)?; 166 Ok(ForwardProtobufFieldType::Map(key, value)) 167 } 168 } 169