mockforge_grpc/reflection/
descriptor.rs

1//! Service and method descriptor handling
2
3use prost_reflect::{MethodDescriptor, ServiceDescriptor};
4use std::collections::HashMap;
5use tonic::Status;
6
7/// A cache of service descriptors
8#[derive(Debug, Clone)]
9pub struct ServiceDescriptorCache {
10    /// Map of service names to service descriptors
11    services: HashMap<String, ServiceDescriptor>,
12    /// Map of (service, method) pairs to method descriptors
13    methods: HashMap<(String, String), MethodDescriptor>,
14}
15
16impl Default for ServiceDescriptorCache {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21
22impl ServiceDescriptorCache {
23    /// Create a new empty cache
24    pub fn new() -> Self {
25        Self {
26            services: HashMap::new(),
27            methods: HashMap::new(),
28        }
29    }
30
31    /// Add a service descriptor to the cache
32    pub fn add_service(&mut self, service: ServiceDescriptor) {
33        let service_name = service.full_name().to_string();
34        self.services.insert(service_name.clone(), service.clone());
35
36        // Cache all methods for this service
37        for method in service.methods() {
38            let method_name = method.name().to_string();
39            self.methods.insert((service_name.clone(), method_name), method);
40        }
41    }
42
43    /// Get a service descriptor by name
44    pub fn get_service(&self, service_name: &str) -> Option<&ServiceDescriptor> {
45        self.services.get(service_name)
46    }
47
48    /// Get a service descriptor by name with proper error handling
49    pub fn get_service_with_error(&self, service_name: &str) -> Result<&ServiceDescriptor, Status> {
50        self.services.get(service_name).ok_or_else(|| {
51            Status::not_found(format!("Service '{}' not found in descriptor cache", service_name))
52        })
53    }
54
55    /// Get a method descriptor by service and method name
56    pub fn get_method(
57        &self,
58        service_name: &str,
59        method_name: &str,
60    ) -> Result<&MethodDescriptor, Status> {
61        self.methods
62            .get(&(service_name.to_string(), method_name.to_string()))
63            .ok_or_else(|| {
64                Status::not_found(format!(
65                    "Method {} not found in service {}",
66                    method_name, service_name
67                ))
68            })
69    }
70
71    /// Check if a service exists in the cache
72    pub fn contains_service(&self, service_name: &str) -> bool {
73        self.services.contains_key(service_name)
74    }
75
76    /// Check if a method exists in the cache
77    pub fn contains_method(&self, service_name: &str, method_name: &str) -> bool {
78        self.methods.contains_key(&(service_name.to_string(), method_name.to_string()))
79    }
80
81    /// Get the number of cached services
82    pub fn service_count(&self) -> usize {
83        self.services.len()
84    }
85
86    /// Get the number of cached methods
87    pub fn method_count(&self) -> usize {
88        self.methods.len()
89    }
90}
91
92#[cfg(test)]
93mod tests {
94
95    #[test]
96    fn test_module_compiles() {}
97}