1 use std::any::TypeId;
2 use std::fmt;
3 use std::fmt::Formatter;
4 use std::hash::Hash;
5 
6 use crate::descriptor::EnumDescriptorProto;
7 use crate::descriptor::EnumValueDescriptorProto;
8 use crate::enums::Enum;
9 use crate::reflect::enums::generated::GeneratedEnumDescriptor;
10 use crate::reflect::file::index::EnumIndices;
11 use crate::reflect::file::FileDescriptorImpl;
12 use crate::reflect::FileDescriptor;
13 use crate::reflect::MessageDescriptor;
14 use crate::EnumFull;
15 
16 pub(crate) mod generated;
17 
18 /// Description for enum variant.
19 ///
20 /// Used in reflection.
21 #[derive(Clone, Eq, PartialEq, Hash)]
22 pub struct EnumValueDescriptor {
23     pub(crate) enum_descriptor: EnumDescriptor,
24     pub(crate) index: usize,
25 }
26 
_assert_send_sync()27 fn _assert_send_sync() {
28     fn _assert_send_sync<T: Send + Sync>() {}
29     _assert_send_sync::<EnumValueDescriptor>();
30 }
31 
32 impl fmt::Debug for EnumValueDescriptor {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result33     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34         f.debug_struct("EnumValueDescriptor")
35             .field("enum_descriptor", &self.enum_descriptor)
36             .field("name", &self.name())
37             .finish()
38     }
39 }
40 
41 impl fmt::Display for EnumValueDescriptor {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result42     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
43         write!(f, "{}.{}", self.enum_descriptor, self.name())
44     }
45 }
46 
47 impl EnumValueDescriptor {
new(enum_descriptor: EnumDescriptor, index: usize) -> EnumValueDescriptor48     pub(crate) fn new(enum_descriptor: EnumDescriptor, index: usize) -> EnumValueDescriptor {
49         EnumValueDescriptor {
50             enum_descriptor,
51             index,
52         }
53     }
54 
55     /// `.proto` object which declared this value.
proto(&self) -> &EnumValueDescriptorProto56     pub fn proto(&self) -> &EnumValueDescriptorProto {
57         &self.enum_descriptor.proto().value[self.index]
58     }
59 
60     /// Name of enum variant as specified in proto file
name(&self) -> &str61     pub fn name(&self) -> &str {
62         self.proto().name()
63     }
64 
65     /// Fully qualified enum value name: fully qualified enum name followed by value name.
full_name(&self) -> String66     pub fn full_name(&self) -> String {
67         self.to_string()
68     }
69 
70     /// `i32` value of the enum variant
value(&self) -> i3271     pub fn value(&self) -> i32 {
72         self.proto().number()
73     }
74 
75     /// Get descriptor of enum holding this value.
enum_descriptor(&self) -> &EnumDescriptor76     pub fn enum_descriptor(&self) -> &EnumDescriptor {
77         &self.enum_descriptor
78     }
79 
80     /// Convert this value descriptor into proper enum object.
81     ///
82     /// ```
83     /// # use protobuf::well_known_types::struct_::NullValue;
84     /// # use protobuf::EnumFull;
85     /// # use protobuf::reflect::EnumValueDescriptor;
86     ///
87     /// # if !cfg!(miri) {
88     /// let value: EnumValueDescriptor = NullValue::NULL_VALUE.descriptor();
89     /// let null: Option<NullValue> = value.cast();
90     /// assert_eq!(Some(NullValue::NULL_VALUE), null);
91     /// # }
92     /// ```
cast<E: EnumFull>(&self) -> Option<E>93     pub fn cast<E: EnumFull>(&self) -> Option<E> {
94         if self.enum_descriptor != E::enum_descriptor() {
95             return None;
96         }
97         E::from_i32(self.value())
98     }
99 }
100 
101 /// Dynamic representation of enum type.
102 ///
103 /// Can be used in reflective operations.
104 #[derive(Clone, Eq, PartialEq, Hash)]
105 pub struct EnumDescriptor {
106     file_descriptor: FileDescriptor,
107     index: usize,
108 }
109 
110 impl fmt::Display for EnumDescriptor {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result111     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112         write!(f, "{}", self.full_name())
113     }
114 }
115 
116 impl fmt::Debug for EnumDescriptor {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result117     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118         f.debug_struct("EnumDescriptor")
119             .field("full_name", &self.full_name())
120             .finish_non_exhaustive()
121     }
122 }
123 
124 impl EnumDescriptor {
new(file_descriptor: FileDescriptor, index: usize) -> EnumDescriptor125     pub(crate) fn new(file_descriptor: FileDescriptor, index: usize) -> EnumDescriptor {
126         EnumDescriptor {
127             file_descriptor,
128             index,
129         }
130     }
131 
get_impl(&self) -> EnumDescriptorImplRef132     fn get_impl(&self) -> EnumDescriptorImplRef {
133         match &self.file_descriptor.imp {
134             FileDescriptorImpl::Generated(g) => {
135                 EnumDescriptorImplRef::Generated(&g.enums[self.index])
136             }
137             FileDescriptorImpl::Dynamic(..) => EnumDescriptorImplRef::Dynamic,
138         }
139     }
140 
141     /// Descriptor objects which defined this enum.
proto(&self) -> &EnumDescriptorProto142     pub fn proto(&self) -> &EnumDescriptorProto {
143         &self.index_entry().proto
144     }
145 
146     /// Enum name as given in `.proto` file
name(&self) -> &str147     pub fn name(&self) -> &str {
148         self.proto().name()
149     }
150 
index_entry(&self) -> &EnumIndices151     fn index_entry(&self) -> &EnumIndices {
152         self.file_descriptor.enum_indices(self.index)
153     }
154 
155     /// Fully qualified protobuf name of enum
full_name(&self) -> &str156     pub fn full_name(&self) -> &str {
157         &self.index_entry().full_name
158     }
159 
160     /// Name relative to the package where the message is declared.
name_to_package(&self) -> &str161     pub fn name_to_package(&self) -> &str {
162         &self.index_entry().name_to_package
163     }
164 
165     /// Get `EnumDescriptor` object for given enum type
for_type<E: EnumFull>() -> EnumDescriptor166     pub fn for_type<E: EnumFull>() -> EnumDescriptor {
167         E::enum_descriptor()
168     }
169 
170     /// Get a message containing this message, or `None` if this message is declared at file level.
enclosing_message(&self) -> Option<MessageDescriptor>171     pub fn enclosing_message(&self) -> Option<MessageDescriptor> {
172         self.index_entry()
173             .enclosing_message
174             .map(|i| MessageDescriptor::new(self.file_descriptor.clone(), i))
175     }
176 
177     /// This enum values
values<'a>(&'a self) -> impl Iterator<Item = EnumValueDescriptor> + 'a178     pub fn values<'a>(&'a self) -> impl Iterator<Item = EnumValueDescriptor> + 'a {
179         let value_len = self.proto().value.len();
180         (0..value_len).map(move |index| EnumValueDescriptor {
181             enum_descriptor: self.clone(),
182             index,
183         })
184     }
185 
186     /// Find enum variant by name
value_by_name(&self, name: &str) -> Option<EnumValueDescriptor>187     pub fn value_by_name(&self, name: &str) -> Option<EnumValueDescriptor> {
188         let index = *self.file_descriptor.common().enums[self.index]
189             .index_by_name
190             .get(name)?;
191         Some(EnumValueDescriptor {
192             enum_descriptor: self.clone(),
193             index,
194         })
195     }
196 
197     /// Find enum variant by number
value_by_number(&self, number: i32) -> Option<EnumValueDescriptor>198     pub fn value_by_number(&self, number: i32) -> Option<EnumValueDescriptor> {
199         let index = *self.file_descriptor.common().enums[self.index]
200             .index_by_number
201             .get(&number)?;
202         Some(self.value_by_index(index))
203     }
204 
205     /// Get enum variant by index (as declared in `.proto` file).
value_by_index(&self, index: usize) -> EnumValueDescriptor206     pub fn value_by_index(&self, index: usize) -> EnumValueDescriptor {
207         assert!(index < self.proto().value.len());
208         EnumValueDescriptor {
209             enum_descriptor: self.clone(),
210             index,
211         }
212     }
213 
214     /// Default enum value (first variant).
default_value(&self) -> EnumValueDescriptor215     pub fn default_value(&self) -> EnumValueDescriptor {
216         EnumValueDescriptor {
217             enum_descriptor: self.clone(),
218             index: 0,
219         }
220     }
221 
222     /// Find enum variant by number or return default (first) enum value
value_by_number_or_default(&self, number: i32) -> EnumValueDescriptor223     pub fn value_by_number_or_default(&self, number: i32) -> EnumValueDescriptor {
224         self.value_by_number(number)
225             .unwrap_or_else(|| self.default_value())
226     }
227 
228     /// Check if this enum descriptor corresponds given enum type
229     ///
230     /// ```
231     /// # use protobuf::EnumFull;
232     /// # use protobuf::descriptor::field_descriptor_proto::Label;
233     /// # use protobuf::reflect::EnumDescriptor;
234     ///
235     /// # if !cfg!(miri) {
236     /// let descriptor: EnumDescriptor = Label::enum_descriptor();
237     ///
238     /// assert!(descriptor.is::<Label>())
239     /// }
240     /// ```
is<E: Enum>(&self) -> bool241     pub fn is<E: Enum>(&self) -> bool {
242         match self.get_impl() {
243             EnumDescriptorImplRef::Generated(g) => g.type_id == TypeId::of::<E>(),
244             EnumDescriptorImplRef::Dynamic => false,
245         }
246     }
247 }
248 
249 enum EnumDescriptorImplRef {
250     Generated(&'static GeneratedEnumDescriptor),
251     Dynamic,
252 }
253 
254 #[cfg(test)]
255 mod test {
256     use crate::descriptor::field_descriptor_proto::Label;
257     use crate::descriptor::field_descriptor_proto::Type;
258     use crate::descriptor::FieldDescriptorProto;
259     use crate::well_known_types::struct_::NullValue;
260     use crate::EnumFull;
261     use crate::MessageFull;
262 
263     #[test]
264     #[cfg_attr(miri, ignore)] // Too slow on Miri.
enclosing_message()265     fn enclosing_message() {
266         assert_eq!(
267             Some(FieldDescriptorProto::descriptor()),
268             Type::enum_descriptor().enclosing_message()
269         );
270         assert_eq!(None, NullValue::enum_descriptor().enclosing_message());
271     }
272 
273     #[test]
274     #[cfg_attr(miri, ignore)] // Too slow on Miri.
to_string()275     fn to_string() {
276         assert_eq!(
277             "google.protobuf.FieldDescriptorProto.Label",
278             Label::enum_descriptor().to_string()
279         );
280         assert_eq!(
281             "google.protobuf.FieldDescriptorProto.Label",
282             Label::enum_descriptor().full_name()
283         );
284         assert_eq!(
285             "google.protobuf.FieldDescriptorProto.Label.LABEL_REPEATED",
286             Label::LABEL_REPEATED.descriptor().to_string()
287         );
288         assert_eq!(
289             "google.protobuf.FieldDescriptorProto.Label.LABEL_REPEATED",
290             Label::LABEL_REPEATED.descriptor().full_name()
291         );
292     }
293 }
294