xmtp_proto/
proto_cache.rs

1//! Cache for Proto definitions
2
3use prost::Message;
4use prost_types::{FileDescriptorSet, MethodDescriptorProto, ServiceDescriptorProto};
5use std::borrow::Cow;
6use std::collections::HashMap;
7use std::sync::LazyLock;
8
9type Cache = HashMap<(Cow<'static, str>, Cow<'static, str>), Cow<'static, str>>;
10
11// lookup a method path&query based on a type name & package
12pub static METHOD_LOOKUP: LazyLock<Cache> = LazyLock::new(|| {
13    let pnq = |package: &str,
14               service: &ServiceDescriptorProto,
15               method: &MethodDescriptorProto|
16     -> String {
17        String::new() + "/" + package + "." + service.name() + "/" + method.name()
18    };
19    let mut map = HashMap::new();
20    let descriptors: FileDescriptorSet =
21        Message::decode(crate::FILE_DESCRIPTOR_SET).expect("static decode must always succeed");
22    let mut dcs = descriptors.file.iter();
23    loop {
24        let Some(fd) = dcs.next() else {
25            break map;
26        };
27        let Some(ref package) = fd.package else {
28            continue;
29        };
30        for service in fd.service.iter() {
31            for method in service.method.iter() {
32                let Some(input_t) = method.input_type().split('.').next_back() else {
33                    continue;
34                };
35                map.insert(
36                    (Cow::Owned(package.clone()), Cow::Owned(input_t.to_string())),
37                    Cow::Owned(pnq(package, service, method)),
38                );
39            }
40        }
41    }
42});
43
44pub fn path_and_query<Type: prost::Name>() -> Cow<'static, str> {
45    METHOD_LOOKUP
46        .get(&(Cow::Borrowed(Type::PACKAGE), Cow::Borrowed(Type::NAME)))
47        .cloned()
48        .unwrap_or(Cow::Owned(String::new()))
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[xmtp_common::test]
56    fn method_lookup() {
57        println!("{:#?}", METHOD_LOOKUP.iter().collect::<Vec<_>>());
58    }
59}