protobuf/reflect/file/
building.rsuse std::collections::HashMap;
use std::iter;
use crate::descriptor::field_descriptor_proto;
use crate::descriptor::DescriptorProto;
use crate::descriptor::EnumDescriptorProto;
use crate::descriptor::FieldDescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::reflect::error::ReflectError;
use crate::reflect::field::index::ForwardProtobufFieldType;
use crate::reflect::field::index::ForwardProtobufTypeBox;
use crate::reflect::file::index::MessageIndices;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::name::protobuf_name_starts_with_package;
use crate::reflect::runtime_type_box::RuntimeType;
use crate::reflect::FileDescriptor;
pub(crate) struct FileDescriptorBuilding<'a> {
pub(crate) current_file_descriptor: &'a FileDescriptorProto,
pub(crate) deps_with_public: &'a [FileDescriptor],
pub(crate) message_by_name_to_package: &'a HashMap<String, usize>,
pub(crate) messages: &'a [MessageIndices],
pub(crate) enums_by_name_to_package: &'a HashMap<String, usize>,
}
impl<'a> FileDescriptorBuilding<'a> {
fn all_descriptors(&self) -> impl Iterator<Item = &'a FileDescriptorProto> {
iter::once(self.current_file_descriptor)
.chain(self.deps_with_public.iter().map(|d| d.proto()))
}
pub fn find_enum(&self, full_name: &str) -> &'a EnumDescriptorProto {
assert!(full_name.starts_with("."));
for file in self.all_descriptors() {
if let Some(name_to_package) =
protobuf_name_starts_with_package(full_name, file.package())
{
if let Some((_, me)) = find_message_or_enum(file, name_to_package) {
match me {
MessageOrEnum::Enum(e) => return e,
MessageOrEnum::Message(_) => panic!("not an enum: {}", full_name),
}
}
}
}
panic!(
"enum not found: {}, in files: {}",
full_name,
self.all_files_str()
);
}
fn all_files_str(&self) -> String {
self.all_descriptors()
.map(|d| d.name())
.collect::<Vec<_>>()
.join(", ")
}
pub(crate) fn resolve_field_type(
&self,
field: &FieldDescriptorProto,
) -> crate::Result<ForwardProtobufFieldType> {
Ok(match field.label() {
field_descriptor_proto::Label::LABEL_OPTIONAL
| field_descriptor_proto::Label::LABEL_REQUIRED => {
ForwardProtobufFieldType::Singular(self.resolve_field_element_type(field)?)
}
field_descriptor_proto::Label::LABEL_REPEATED => {
let element = self.resolve_field_element_type(field)?;
let type_proto = match &element {
ForwardProtobufTypeBox::CurrentFileMessage(m) => {
Some(&*self.messages[*m].proto)
}
ForwardProtobufTypeBox::ProtobufTypeBox(t) => match t.runtime() {
RuntimeType::Message(m) => Some(m.proto()),
_ => None,
},
_ => None,
};
match type_proto {
Some(m) if m.options.get_or_default().map_entry() => self.map_field(m)?,
_ => ForwardProtobufFieldType::Repeated(element),
}
}
})
}
fn resolve_field_element_type(
&self,
field: &FieldDescriptorProto,
) -> crate::Result<ForwardProtobufTypeBox> {
Ok(match field.type_() {
field_descriptor_proto::Type::TYPE_MESSAGE
| field_descriptor_proto::Type::TYPE_GROUP => {
self.resolve_message(field.type_name())?
}
field_descriptor_proto::Type::TYPE_ENUM => {
if let Some(name_to_package) = protobuf_name_starts_with_package(
field.type_name(),
self.current_file_descriptor.package(),
) {
if let Some(index) = self.enums_by_name_to_package.get(name_to_package) {
return Ok(ForwardProtobufTypeBox::CurrentFileEnum(*index));
}
}
for dep in self.deps_with_public {
if let Some(m) = dep.enum_by_full_name(field.type_name()) {
return Ok(ForwardProtobufTypeBox::enumeration(m));
}
}
panic!(
"enum not found: {}; files: {}",
field.type_name(),
self.all_files_str()
);
}
t => ForwardProtobufTypeBox::from_proto_type(t),
})
}
pub(crate) fn resolve_message(&self, type_name: &str) -> crate::Result<ForwardProtobufTypeBox> {
if let Some(name_to_package) =
protobuf_name_starts_with_package(type_name, self.current_file_descriptor.package())
{
if let Some(index) = self.message_by_name_to_package.get(name_to_package) {
return Ok(ForwardProtobufTypeBox::CurrentFileMessage(*index));
}
}
for dep in self.deps_with_public {
if let Some(m) = dep.message_by_full_name(type_name) {
return Ok(ForwardProtobufTypeBox::message(m));
}
}
Err(ReflectError::MessageNotFoundInFiles(type_name.to_owned(), self.all_files_str()).into())
}
fn map_field(&self, type_proto: &DescriptorProto) -> crate::Result<ForwardProtobufFieldType> {
assert!(type_proto.name().ends_with("Entry"));
assert_eq!(0, type_proto.extension.len());
assert_eq!(0, type_proto.extension_range.len());
assert_eq!(0, type_proto.nested_type.len());
assert_eq!(0, type_proto.enum_type.len());
assert_eq!(2, type_proto.field.len());
let key = &type_proto.field[0];
let value = &type_proto.field[1];
assert_eq!("key", key.name());
assert_eq!("value", value.name());
assert_eq!(1, key.number());
assert_eq!(2, value.number());
assert_eq!(field_descriptor_proto::Label::LABEL_OPTIONAL, key.label());
assert_eq!(field_descriptor_proto::Label::LABEL_OPTIONAL, value.label());
let key = self.resolve_field_element_type(key)?;
let value = self.resolve_field_element_type(value)?;
Ok(ForwardProtobufFieldType::Map(key, value))
}
}