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