mockforge_grpc/reflection/
cache.rs

1//! Cache implementation for service and method descriptors
2
3use crate::reflection::descriptor::ServiceDescriptorCache;
4use prost_reflect::{DescriptorPool, ServiceDescriptor};
5use std::sync::Arc;
6use tokio::sync::RwLock;
7use tonic::Status;
8use tracing::{debug, trace};
9
10/// A thread-safe cache of service descriptors
11#[derive(Debug, Clone)]
12pub struct DescriptorCache {
13    /// The underlying cache protected by a RwLock
14    cache: Arc<RwLock<ServiceDescriptorCache>>,
15}
16
17impl Default for DescriptorCache {
18    fn default() -> Self {
19        Self::new()
20    }
21}
22
23impl DescriptorCache {
24    /// Create a new descriptor cache
25    pub fn new() -> Self {
26        Self {
27            cache: Arc::new(RwLock::new(ServiceDescriptorCache::new())),
28        }
29    }
30
31    /// Add a service descriptor to the cache
32    pub async fn add_service(&self, service: ServiceDescriptor) {
33        let service_name = service.full_name().to_string();
34        trace!("Adding service to cache: {}", service_name);
35
36        let mut cache = self.cache.write().await;
37        cache.add_service(service);
38
39        debug!("Added service to cache: {}", service_name);
40    }
41
42    /// Get a method descriptor from the cache
43    pub async fn get_method(
44        &self,
45        service_name: &str,
46        method_name: &str,
47    ) -> Result<prost_reflect::MethodDescriptor, Status> {
48        trace!("Getting method from cache: {}::{}", service_name, method_name);
49
50        let cache = self.cache.read().await;
51        cache.get_method(service_name, method_name).cloned()
52    }
53
54    /// Get a service descriptor from the cache with proper error handling
55    pub async fn get_service(&self, service_name: &str) -> Result<ServiceDescriptor, Status> {
56        trace!("Getting service from cache: {}", service_name);
57
58        let cache = self.cache.read().await;
59        cache.get_service_with_error(service_name).cloned()
60    }
61
62    /// Check if a service exists in the cache
63    pub async fn contains_service(&self, service_name: &str) -> bool {
64        let cache = self.cache.read().await;
65        cache.contains_service(service_name)
66    }
67
68    /// Check if a method exists in the cache
69    pub async fn contains_method(&self, service_name: &str, method_name: &str) -> bool {
70        let cache = self.cache.read().await;
71        cache.contains_method(service_name, method_name)
72    }
73
74    /// Populate the cache from a descriptor pool
75    pub async fn populate_from_pool(&self, pool: Option<&DescriptorPool>) {
76        let pool = match pool {
77            Some(pool) => pool,
78            None => {
79                debug!("No descriptor pool provided, skipping cache population");
80                return;
81            }
82        };
83
84        trace!("Populating cache from descriptor pool");
85
86        let mut cache = self.cache.write().await;
87        for service in pool.services() {
88            cache.add_service(service);
89        }
90
91        debug!("Populated cache with {} services", pool.services().count());
92    }
93
94    /// Get the number of cached services
95    pub async fn service_count(&self) -> usize {
96        let cache = self.cache.read().await;
97        cache.service_count()
98    }
99
100    /// Get the number of cached methods across all services
101    pub async fn method_count(&self) -> usize {
102        let cache = self.cache.read().await;
103        cache.method_count()
104    }
105}
106
107#[cfg(test)]
108mod tests {
109
110    #[test]
111    fn test_module_compiles() {}
112}