use std::fmt; use std::io::Read; use crate::descriptor::DescriptorProto; use crate::descriptor::FileDescriptorProto; use crate::message_dyn::MessageDyn; use crate::message_full::MessageFull; use crate::reflect::dynamic::DynamicMessage; use crate::reflect::file::index::MessageIndices; use crate::reflect::file::FileDescriptorImpl; use crate::reflect::message::generated::GeneratedMessageDescriptor; use crate::reflect::reflect_eq::ReflectEq; use crate::reflect::reflect_eq::ReflectEqMode; use crate::reflect::EnumDescriptor; use crate::reflect::FieldDescriptor; use crate::reflect::FileDescriptor; use crate::reflect::OneofDescriptor; use crate::CodedInputStream; pub(crate) mod generated; pub(crate) mod is_initialized_is_always_true; pub(crate) mod message_ref; /// Dynamic representation of message type. /// /// Used for reflection. #[derive(Clone, Eq, PartialEq, Hash)] pub struct MessageDescriptor { pub(crate) file_descriptor: FileDescriptor, pub(crate) index: usize, } impl fmt::Display for MessageDescriptor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.full_name()) } } impl fmt::Debug for MessageDescriptor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MessageDescriptor").finish_non_exhaustive() } } impl MessageDescriptor { pub(crate) fn new(file_descriptor: FileDescriptor, index: usize) -> MessageDescriptor { MessageDescriptor { file_descriptor, index, } } /// Get underlying `DescriptorProto` object. pub fn proto(&self) -> &DescriptorProto { self.file_descriptor.message_proto_by_index(self.index) } /// Message name as specified in `.proto` file. pub fn name(&self) -> &str { self.proto().name() } fn index_entry(&self) -> &MessageIndices { self.file_descriptor.message_indices(self.index) } /// Get a message descriptor for given message type pub fn for_type() -> MessageDescriptor { M::descriptor() } /// Messages declared in this messages. pub fn nested_messages(&self) -> impl Iterator + '_ { self.index_entry() .nested_messages .iter() .map(|i| MessageDescriptor::new(self.file_descriptor.clone(), *i)) } /// Get enums declared in this message. pub fn nested_enums(&self) -> impl Iterator + '_ { self.index_entry() .nested_enums .clone() .map(|i| EnumDescriptor::new(self.file_descriptor.clone(), i)) } /// Get a message containing this message, or `None` if this message is declared at file level. pub fn enclosing_message(&self) -> Option { self.index_entry() .enclosing_message .map(|i| MessageDescriptor::new(self.file_descriptor.clone(), i)) } pub(crate) fn get_impl(&self) -> MessageDescriptorImplRef { match &self.file_descriptor.imp { FileDescriptorImpl::Generated(g) => { MessageDescriptorImplRef::Generated(&g.messages[self.index]) } FileDescriptorImpl::Dynamic(..) => MessageDescriptorImplRef::Dynamic, } } /// [`FileDescriptor`] containing this message. pub fn file_descriptor(&self) -> &FileDescriptor { &self.file_descriptor } /// `FileDescriptorProto` containg this message type pub fn file_descriptor_proto(&self) -> &FileDescriptorProto { self.file_descriptor().proto() } /// This message descriptor is a map entry. pub fn is_map_entry(&self) -> bool { self.index().map_entry } fn assert_not_map_entry(&self) { assert!( !self.is_map_entry(), "message is map entry: {}", self.full_name() ); } /// Message is considered always initialized. #[doc(hidden)] pub fn is_initialized_is_always_true(&self) -> bool { self.index().is_initialized_is_always_true } /// New empty message. /// /// # Panics /// /// If this message is a map entry message. pub fn new_instance(&self) -> Box { self.assert_not_map_entry(); match self.get_impl() { MessageDescriptorImplRef::Generated(g) => g.non_map().factory.new_instance(), MessageDescriptorImplRef::Dynamic => Box::new(DynamicMessage::new(self.clone())), } } /// Shared immutable empty message. /// /// Returns `None` for dynamic message. /// /// # Panics /// /// If this message is a map entry message. pub fn default_instance(&self) -> Option<&'static dyn MessageDyn> { self.assert_not_map_entry(); match self.get_impl() { MessageDescriptorImplRef::Generated(g) => Some(g.non_map().factory.default_instance()), MessageDescriptorImplRef::Dynamic => None, } } /// Clone a message pub(crate) fn clone_message(&self, message: &dyn MessageDyn) -> Box { assert!(&message.descriptor_dyn() == self); match self.get_impl() { MessageDescriptorImplRef::Generated(g) => g.non_map().factory.clone(message), MessageDescriptorImplRef::Dynamic => { let message: &DynamicMessage = DynamicMessage::downcast_ref(message); Box::new(message.clone()) } } } /// Check if two messages equal. /// /// # Panics /// /// Is any message has different type than this descriptor. pub fn eq(&self, a: &dyn MessageDyn, b: &dyn MessageDyn) -> bool { match self.get_impl() { MessageDescriptorImplRef::Generated(g) => g.non_map().factory.eq(a, b), MessageDescriptorImplRef::Dynamic => unimplemented!(), } } /// Similar to `eq`, but considers `NaN` values equal. /// /// # Panics /// /// Is any message has different type than this descriptor. pub(crate) fn reflect_eq( &self, a: &dyn MessageDyn, b: &dyn MessageDyn, mode: &ReflectEqMode, ) -> bool { // Explicitly force panic even if field list is empty assert_eq!(self, &a.descriptor_dyn()); assert_eq!(self, &b.descriptor_dyn()); for field in self.fields() { let af = field.get_reflect(a); let bf = field.get_reflect(b); if !af.reflect_eq(&bf, mode) { return false; } } true } pub(crate) fn reflect_eq_maybe_unrelated( a: &dyn MessageDyn, b: &dyn MessageDyn, mode: &ReflectEqMode, ) -> bool { let ad = a.descriptor_dyn(); let bd = b.descriptor_dyn(); ad == bd && ad.reflect_eq(a, b, mode) } /// Fully qualified protobuf message name pub fn full_name(&self) -> &str { &self.index_entry().full_name } /// Name relative to the package where the message is declared. pub fn name_to_package(&self) -> &str { &self.index_entry().name_to_package } /// Nested oneofs including synthetic. pub fn all_oneofs<'a>(&'a self) -> impl Iterator + 'a { self.index_entry() .oneofs .clone() .map(move |i| OneofDescriptor { file_descriptor: self.file_descriptor.clone(), index: i, }) } /// Non-synthetic oneofs. pub fn oneofs<'a>(&'a self) -> impl Iterator + 'a { self.all_oneofs().filter(|oneof| !oneof.is_synthetic()) } /// Get message oneof by name (**not implemented**). pub fn oneof_by_name(&self, name: &str) -> Option { self.all_oneofs().find(|oneof| oneof.name() == name) } /// Message field descriptors. pub fn fields<'a>(&'a self) -> impl Iterator + 'a { self.index() .message_index .regular_field_range() .map(move |index| FieldDescriptor { file_descriptor: self.file_descriptor.clone(), index, }) } /// Extension fields. pub fn extensions(&self) -> impl Iterator + '_ { self.index() .message_index .extension_field_range() .map(move |index| FieldDescriptor { file_descriptor: self.file_descriptor.clone(), index, }) } pub(crate) fn index(&self) -> &MessageIndices { &self.file_descriptor.common().messages[self.index] } pub(crate) fn field_by_index(&self, index: usize) -> FieldDescriptor { FieldDescriptor { file_descriptor: self.file_descriptor.clone(), index: self.index().message_index.first_field_index + index, } } /// Find message field by protobuf field name /// /// Note: protobuf field name might be different for Rust field name. // TODO: return value, not pointer, pointer is not compatible with dynamic message pub fn field_by_name(&self, name: &str) -> Option { let &index = self.index().message_index.field_index_by_name.get(name)?; Some(self.field_by_index(index)) } /// Find message field by field name or field JSON name pub fn field_by_name_or_json_name<'a>(&'a self, name: &str) -> Option { let &index = self .index() .message_index .field_index_by_name_or_json_name .get(name)?; Some(self.field_by_index(index)) } /// Find message field by field name pub fn field_by_number(&self, number: u32) -> Option { let &index = self .index() .message_index .field_index_by_number .get(&number)?; Some(self.field_by_index(index)) } /// Parse message from stream. pub fn parse_from(&self, is: &mut CodedInputStream) -> crate::Result> { let mut r = self.new_instance(); r.merge_from_dyn(is)?; r.check_initialized_dyn()?; Ok(r) } /// Parse message from reader. /// Parse stops on EOF or when error encountered. pub fn parse_from_reader(&self, reader: &mut dyn Read) -> crate::Result> { let mut is = CodedInputStream::new(reader); let r = self.parse_from(&mut is)?; is.check_eof()?; Ok(r) } /// Parse message from byte array. pub fn parse_from_bytes(&self, bytes: &[u8]) -> crate::Result> { let mut is = CodedInputStream::from_bytes(bytes); let r = self.parse_from(&mut is)?; is.check_eof()?; Ok(r) } } pub(crate) enum MessageDescriptorImplRef { Generated(&'static GeneratedMessageDescriptor), Dynamic, } #[cfg(test)] mod test { use crate::descriptor::descriptor_proto::ExtensionRange; use crate::descriptor::field_descriptor_proto::Type; use crate::descriptor::DescriptorProto; use crate::descriptor::FieldDescriptorProto; use crate::EnumFull; use crate::MessageFull; #[test] #[cfg_attr(miri, ignore)] // Too slow on Miri. fn nested_messages() { assert!(DescriptorProto::descriptor() .nested_messages() .collect::>() .contains(&ExtensionRange::descriptor())); } #[test] #[cfg_attr(miri, ignore)] // Too slow on Miri. fn nested_enums() { assert!(FieldDescriptorProto::descriptor() .nested_enums() .collect::>() .contains(&Type::enum_descriptor())); } #[test] #[cfg_attr(miri, ignore)] // Too slow on Miri. fn enclosing_message() { assert_eq!( Some(DescriptorProto::descriptor()), ExtensionRange::descriptor().enclosing_message() ); assert_eq!(None, DescriptorProto::descriptor().enclosing_message()); } }