1 use std::collections::HashMap; 2 3 use crate::descriptor::EnumDescriptorProto; 4 use crate::descriptor::EnumValueDescriptorProto; 5 use crate::descriptor::FileDescriptorProto; 6 use crate::descriptorx::find_enum_by_rust_name; 7 use crate::reflect::find_message_or_enum::find_message_or_enum; 8 use crate::reflect::find_message_or_enum::MessageOrEnum; 9 use crate::ProtobufEnum; 10 11 /// Description for enum variant. 12 /// 13 /// Used in reflection. 14 #[derive(Clone, Debug)] 15 pub struct EnumValueDescriptor { 16 proto: &'static EnumValueDescriptorProto, 17 } 18 19 impl Copy for EnumValueDescriptor {} 20 21 impl EnumValueDescriptor { 22 /// Name of enum variant as specified in proto file name(&self) -> &'static str23 pub fn name(&self) -> &'static str { 24 self.proto.get_name() 25 } 26 27 /// `i32` value of the enum variant value(&self) -> i3228 pub fn value(&self) -> i32 { 29 self.proto.get_number() 30 } 31 } 32 33 /// Dynamic representation of enum type. 34 /// 35 /// Can be used in reflective operations. 36 pub struct EnumDescriptor { 37 proto: &'static EnumDescriptorProto, 38 values: Vec<EnumValueDescriptor>, 39 40 index_by_name: HashMap<String, usize>, 41 index_by_number: HashMap<i32, usize>, 42 } 43 44 impl EnumDescriptor { 45 /// Enum name as given in `.proto` file name(&self) -> &'static str46 pub fn name(&self) -> &'static str { 47 self.proto.get_name() 48 } 49 50 /// `EnumDescriptor` for enum type for_type<E: ProtobufEnum>() -> &'static EnumDescriptor51 pub fn for_type<E: ProtobufEnum>() -> &'static EnumDescriptor { 52 E::enum_descriptor_static() 53 } 54 55 /// Create new enum descriptor. 56 /// 57 /// This function is called by generated code, and should not be called manually. 58 #[deprecated( 59 since = "2.12", 60 note = "Please regenerate .rs files from .proto files to use newer APIs" 61 )] new(rust_name: &'static str, file: &'static FileDescriptorProto) -> EnumDescriptor62 pub fn new(rust_name: &'static str, file: &'static FileDescriptorProto) -> EnumDescriptor { 63 let proto = find_enum_by_rust_name(file, rust_name); 64 let mut index_by_name = HashMap::new(); 65 let mut index_by_number = HashMap::new(); 66 for (i, v) in proto.en.get_value().iter().enumerate() { 67 index_by_number.insert(v.get_number(), i); 68 index_by_name.insert(v.get_name().to_string(), i); 69 } 70 EnumDescriptor { 71 proto: proto.en, 72 values: proto 73 .en 74 .get_value() 75 .iter() 76 .map(|v| EnumValueDescriptor { proto: v }) 77 .collect(), 78 index_by_name: index_by_name, 79 index_by_number: index_by_number, 80 } 81 } 82 83 /// Create new enum descriptor. 84 /// 85 /// This function is called by generated code, and should not be called manually. new_pb_name<E>( name_in_file: &'static str, file: &'static FileDescriptorProto, ) -> EnumDescriptor where E: ProtobufEnum,86 pub fn new_pb_name<E>( 87 name_in_file: &'static str, 88 file: &'static FileDescriptorProto, 89 ) -> EnumDescriptor 90 where 91 E: ProtobufEnum, 92 { 93 let (_path_to_package, proto) = match find_message_or_enum(file, name_in_file) { 94 (path_to_package, MessageOrEnum::Enum(e)) => (path_to_package, e), 95 (_, MessageOrEnum::Message(_)) => panic!("not an enum"), 96 }; 97 98 let mut index_by_name = HashMap::new(); 99 let mut index_by_number = HashMap::new(); 100 for (i, v) in proto.get_value().iter().enumerate() { 101 index_by_number.insert(v.get_number(), i); 102 index_by_name.insert(v.get_name().to_string(), i); 103 } 104 EnumDescriptor { 105 proto, 106 values: proto 107 .get_value() 108 .iter() 109 .map(|v| EnumValueDescriptor { proto: v }) 110 .collect(), 111 index_by_name: index_by_name, 112 index_by_number: index_by_number, 113 } 114 } 115 116 /// Find enum value by name value_by_name<'a>(&'a self, name: &str) -> &'a EnumValueDescriptor117 pub fn value_by_name<'a>(&'a self, name: &str) -> &'a EnumValueDescriptor { 118 // TODO: clone is weird 119 let &index = self.index_by_name.get(&name.to_string()).unwrap(); 120 &self.values[index] 121 } 122 123 /// Find enum value by number value_by_number<'a>(&'a self, number: i32) -> &'a EnumValueDescriptor124 pub fn value_by_number<'a>(&'a self, number: i32) -> &'a EnumValueDescriptor { 125 let &index = self.index_by_number.get(&number).unwrap(); 126 &self.values[index] 127 } 128 } 129