protobuf/reflect/
find_message_or_enum.rs

1use crate::descriptor::DescriptorProto;
2use crate::descriptor::EnumDescriptorProto;
3use crate::descriptor::FileDescriptorProto;
4
5pub(crate) enum MessageOrEnum<'a> {
6    Message(&'a DescriptorProto),
7    Enum(&'a EnumDescriptorProto),
8}
9
10impl<'a> MessageOrEnum<'a> {
11    fn from_two_options(
12        m: Option<&'a DescriptorProto>,
13        e: Option<&'a EnumDescriptorProto>,
14    ) -> Option<MessageOrEnum<'a>> {
15        match (m, e) {
16            (Some(_), Some(_)) => panic!("enum and message with the same name"),
17            (Some(m), None) => Some(MessageOrEnum::Message(m)),
18            (None, Some(e)) => Some(MessageOrEnum::Enum(e)),
19            (None, None) => None,
20        }
21    }
22}
23
24pub(crate) fn find_message_or_enum<'a>(
25    file: &'a FileDescriptorProto,
26    name_to_package: &str,
27) -> Option<(String, MessageOrEnum<'a>)> {
28    assert!(!name_to_package.starts_with("."));
29    assert!(!name_to_package.is_empty());
30
31    let mut path = name_to_package.split('.');
32    let first = path.next().unwrap();
33    let child_message = file.message_type.iter().find(|m| m.name() == first);
34    let child_enum = file.enum_type.iter().find(|e| e.name() == first);
35
36    let mut package_to_name = String::new();
37    let mut me = MessageOrEnum::from_two_options(child_message, child_enum)?;
38
39    for name in path {
40        let message = match me {
41            MessageOrEnum::Message(m) => m,
42            MessageOrEnum::Enum(_) => panic!("enum has no children"),
43        };
44
45        if !package_to_name.is_empty() {
46            package_to_name.push_str(".");
47        }
48        package_to_name.push_str(message.name());
49
50        let child_message = message.nested_type.iter().find(|m| m.name() == name);
51        let child_enum = message.enum_type.iter().find(|e| e.name() == name);
52        me = MessageOrEnum::from_two_options(child_message, child_enum)?;
53    }
54
55    Some((package_to_name, me))
56}