use std::any::TypeId; use std::fmt; use std::fmt::Formatter; use std::hash::Hash; use crate::descriptor::EnumDescriptorProto; use crate::descriptor::EnumValueDescriptorProto; use crate::enums::Enum; use crate::reflect::enums::generated::GeneratedEnumDescriptor; use crate::reflect::file::index::EnumIndices; use crate::reflect::file::FileDescriptorImpl; use crate::reflect::FileDescriptor; use crate::reflect::MessageDescriptor; use crate::EnumFull; pub(crate) mod generated; /// Description for enum variant. /// /// Used in reflection. #[derive(Clone, Eq, PartialEq, Hash)] pub struct EnumValueDescriptor { pub(crate) enum_descriptor: EnumDescriptor, pub(crate) index: usize, } fn _assert_send_sync() { fn _assert_send_sync() {} _assert_send_sync::(); } impl fmt::Debug for EnumValueDescriptor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("EnumValueDescriptor") .field("enum_descriptor", &self.enum_descriptor) .field("name", &self.name()) .finish() } } impl fmt::Display for EnumValueDescriptor { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{}.{}", self.enum_descriptor, self.name()) } } impl EnumValueDescriptor { pub(crate) fn new(enum_descriptor: EnumDescriptor, index: usize) -> EnumValueDescriptor { EnumValueDescriptor { enum_descriptor, index, } } /// `.proto` object which declared this value. pub fn proto(&self) -> &EnumValueDescriptorProto { &self.enum_descriptor.proto().value[self.index] } /// Name of enum variant as specified in proto file pub fn name(&self) -> &str { self.proto().name() } /// Fully qualified enum value name: fully qualified enum name followed by value name. pub fn full_name(&self) -> String { self.to_string() } /// `i32` value of the enum variant pub fn value(&self) -> i32 { self.proto().number() } /// Get descriptor of enum holding this value. pub fn enum_descriptor(&self) -> &EnumDescriptor { &self.enum_descriptor } /// Convert this value descriptor into proper enum object. /// /// ``` /// # use protobuf::well_known_types::struct_::NullValue; /// # use protobuf::EnumFull; /// # use protobuf::reflect::EnumValueDescriptor; /// /// # if !cfg!(miri) { /// let value: EnumValueDescriptor = NullValue::NULL_VALUE.descriptor(); /// let null: Option = value.cast(); /// assert_eq!(Some(NullValue::NULL_VALUE), null); /// # } /// ``` pub fn cast(&self) -> Option { if self.enum_descriptor != E::enum_descriptor() { return None; } E::from_i32(self.value()) } } /// Dynamic representation of enum type. /// /// Can be used in reflective operations. #[derive(Clone, Eq, PartialEq, Hash)] pub struct EnumDescriptor { file_descriptor: FileDescriptor, index: usize, } impl fmt::Display for EnumDescriptor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.full_name()) } } impl fmt::Debug for EnumDescriptor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("EnumDescriptor") .field("full_name", &self.full_name()) .finish_non_exhaustive() } } impl EnumDescriptor { pub(crate) fn new(file_descriptor: FileDescriptor, index: usize) -> EnumDescriptor { EnumDescriptor { file_descriptor, index, } } fn get_impl(&self) -> EnumDescriptorImplRef { match &self.file_descriptor.imp { FileDescriptorImpl::Generated(g) => { EnumDescriptorImplRef::Generated(&g.enums[self.index]) } FileDescriptorImpl::Dynamic(..) => EnumDescriptorImplRef::Dynamic, } } /// Descriptor objects which defined this enum. pub fn proto(&self) -> &EnumDescriptorProto { &self.index_entry().proto } /// Enum name as given in `.proto` file pub fn name(&self) -> &str { self.proto().name() } fn index_entry(&self) -> &EnumIndices { self.file_descriptor.enum_indices(self.index) } /// Fully qualified protobuf name of enum 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 } /// Get `EnumDescriptor` object for given enum type pub fn for_type() -> EnumDescriptor { E::enum_descriptor() } /// 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)) } /// This enum values pub fn values<'a>(&'a self) -> impl Iterator + 'a { let value_len = self.proto().value.len(); (0..value_len).map(move |index| EnumValueDescriptor { enum_descriptor: self.clone(), index, }) } /// Find enum variant by name pub fn value_by_name(&self, name: &str) -> Option { let index = *self.file_descriptor.common().enums[self.index] .index_by_name .get(name)?; Some(EnumValueDescriptor { enum_descriptor: self.clone(), index, }) } /// Find enum variant by number pub fn value_by_number(&self, number: i32) -> Option { let index = *self.file_descriptor.common().enums[self.index] .index_by_number .get(&number)?; Some(self.value_by_index(index)) } /// Get enum variant by index (as declared in `.proto` file). pub fn value_by_index(&self, index: usize) -> EnumValueDescriptor { assert!(index < self.proto().value.len()); EnumValueDescriptor { enum_descriptor: self.clone(), index, } } /// Default enum value (first variant). pub fn default_value(&self) -> EnumValueDescriptor { EnumValueDescriptor { enum_descriptor: self.clone(), index: 0, } } /// Find enum variant by number or return default (first) enum value pub fn value_by_number_or_default(&self, number: i32) -> EnumValueDescriptor { self.value_by_number(number) .unwrap_or_else(|| self.default_value()) } /// Check if this enum descriptor corresponds given enum type /// /// ``` /// # use protobuf::EnumFull; /// # use protobuf::descriptor::field_descriptor_proto::Label; /// # use protobuf::reflect::EnumDescriptor; /// /// # if !cfg!(miri) { /// let descriptor: EnumDescriptor = Label::enum_descriptor(); /// /// assert!(descriptor.is::