protobuf/reflect/
enums.rs

1use std::collections::HashMap;
2
3use crate::descriptor::EnumDescriptorProto;
4use crate::descriptor::EnumValueDescriptorProto;
5use crate::descriptor::FileDescriptorProto;
6use crate::descriptorx::find_enum_by_rust_name;
7use crate::reflect::find_message_or_enum::find_message_or_enum;
8use crate::reflect::find_message_or_enum::MessageOrEnum;
9use crate::ProtobufEnum;
10
11/// Description for enum variant.
12///
13/// Used in reflection.
14#[derive(Clone, Debug)]
15pub struct EnumValueDescriptor {
16    proto: &'static EnumValueDescriptorProto,
17}
18
19impl Copy for EnumValueDescriptor {}
20
21impl EnumValueDescriptor {
22    /// Name of enum variant as specified in proto file
23    pub fn name(&self) -> &'static str {
24        self.proto.get_name()
25    }
26
27    /// `i32` value of the enum variant
28    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.
36pub 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
44impl EnumDescriptor {
45    /// Enum name as given in `.proto` file
46    pub fn name(&self) -> &'static str {
47        self.proto.get_name()
48    }
49
50    /// `EnumDescriptor` for enum type
51    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    )]
62    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.
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
117    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
124    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}