Skip to main content
Glama

CodeGraph CLI MCP Server

by Jakedismo
archived.rs13.7 kB
//! Archived data structures for CodeGraph //! //! This module defines zero-copy archived versions of core CodeGraph data structures //! that can be directly accessed from serialized form without deserialization. use rkyv::{Archive, Deserialize, Serialize}; use std::collections::HashMap; /// Archived version of a code node with zero-copy access #[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ArchivedCodeNode { pub id: u64, pub name: String, pub node_type: String, pub file_path: String, pub start_line: u32, pub end_line: u32, pub start_column: u32, pub end_column: u32, pub content: String, pub hash: String, pub parent_id: Option<u64>, pub children: Vec<u64>, pub metadata: HashMap<String, String>, } /// Archived version of a code edge representing relationships #[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ArchivedCodeEdge { pub id: u64, pub source_id: u64, pub target_id: u64, pub edge_type: String, pub weight: f32, pub metadata: HashMap<String, String>, } /// Archived version of a code graph containing nodes and edges #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedCodeGraph { pub version: u32, pub timestamp: u64, pub nodes: HashMap<u64, ArchivedCodeNode>, pub edges: Vec<ArchivedCodeEdge>, pub metadata: HashMap<String, String>, pub file_hashes: HashMap<String, String>, } /// Archived version of embedding vectors #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedEmbedding { pub id: u64, pub model: String, pub dimensions: u32, pub vector: Vec<f32>, pub metadata: HashMap<String, String>, } /// Archived version of search results #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedSearchResult { pub query_id: u64, pub results: Vec<ArchivedSearchItem>, pub total_count: usize, pub execution_time_ms: u64, pub metadata: HashMap<String, String>, } /// Individual search result item #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedSearchItem { pub node_id: u64, pub score: f32, pub snippet: String, pub highlights: Vec<ArchivedHighlight>, } /// Text highlight in search results #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedHighlight { pub start: usize, pub end: usize, pub highlight_type: String, } /// Archived cache entry with expiration #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedCacheEntry<T> { pub key: String, pub value: T, pub created_at: u64, pub expires_at: Option<u64>, pub access_count: u64, pub last_accessed: u64, } /// Archived configuration settings #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedConfig { pub version: String, pub database_path: String, pub cache_size: usize, pub max_file_size: usize, pub embedding_model: String, pub chunk_size: usize, pub overlap_size: usize, pub settings: HashMap<String, String>, } /// Archived metrics and statistics #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedMetrics { pub timestamp: u64, pub processing_time: HashMap<String, u64>, pub memory_usage: HashMap<String, u64>, pub cache_stats: ArchivedCacheStats, pub error_counts: HashMap<String, u64>, pub counters: HashMap<String, u64>, } /// Cache statistics #[derive(Archive, Serialize, Deserialize, Debug, Clone)] pub struct ArchivedCacheStats { pub hits: u64, pub misses: u64, pub evictions: u64, pub size: usize, pub capacity: usize, } impl ArchivedCodeNode { /// Check if this node is a function pub fn is_function(&self) -> bool { self.node_type == "function" || self.node_type == "method" } /// Check if this node is a class or struct pub fn is_type_definition(&self) -> bool { matches!( self.node_type.as_str(), "class" | "struct" | "interface" | "enum" ) } /// Get the size in lines pub fn line_count(&self) -> u32 { self.end_line .saturating_sub(self.start_line) .saturating_add(1) } /// Check if this node contains the given line pub fn contains_line(&self, line: u32) -> bool { line >= self.start_line && line <= self.end_line } } impl ArchivedCodeEdge { /// Check if this is a dependency relationship pub fn is_dependency(&self) -> bool { matches!( self.edge_type.as_str(), "depends_on" | "imports" | "requires" ) } /// Check if this is a structural relationship pub fn is_structural(&self) -> bool { matches!( self.edge_type.as_str(), "contains" | "parent_of" | "child_of" ) } /// Check if this is a call relationship pub fn is_call_relationship(&self) -> bool { matches!(self.edge_type.as_str(), "calls" | "invokes" | "references") } } impl ArchivedCodeGraph { /// Get a node by ID pub fn get_node(&self, id: u64) -> Option<&ArchivedCodeNode> { self.nodes.get(&id) } /// Get all edges from a source node pub fn get_edges_from(&self, source_id: u64) -> Vec<&ArchivedCodeEdge> { self.edges .iter() .filter(|edge| edge.source_id == source_id) .collect() } /// Get all edges to a target node pub fn get_edges_to(&self, target_id: u64) -> Vec<&ArchivedCodeEdge> { self.edges .iter() .filter(|edge| edge.target_id == target_id) .collect() } /// Get the total number of nodes pub fn node_count(&self) -> usize { self.nodes.len() } /// Get the total number of edges pub fn edge_count(&self) -> usize { self.edges.len() } /// Find nodes by type pub fn nodes_by_type(&self, node_type: &str) -> Vec<&ArchivedCodeNode> { self.nodes .values() .filter(|node| node.node_type == node_type) .collect() } /// Find nodes in a specific file pub fn nodes_in_file(&self, file_path: &str) -> Vec<&ArchivedCodeNode> { self.nodes .values() .filter(|node| node.file_path == file_path) .collect() } } impl<T> ArchivedCacheEntry<T> { /// Check if the cache entry has expired pub fn is_expired(&self, current_time: u64) -> bool { match self.expires_at { Some(expires_at) => current_time > expires_at, None => false, } } /// Get the age of the cache entry in milliseconds pub fn age(&self, current_time: u64) -> u64 { current_time.saturating_sub(self.created_at) } /// Get time since last access in milliseconds pub fn time_since_access(&self, current_time: u64) -> u64 { current_time.saturating_sub(self.last_accessed) } } impl ArchivedSearchResult { /// Get the top N results pub fn top_results(&self, n: usize) -> &[ArchivedSearchItem] { let end = n.min(self.results.len()); &self.results[..end] } /// Check if there are more results than returned pub fn has_more_results(&self) -> bool { self.total_count > self.results.len() } /// Get results above a certain score threshold pub fn results_above_score(&self, threshold: f32) -> Vec<&ArchivedSearchItem> { self.results .iter() .filter(|item| item.score >= threshold) .collect() } } impl ArchivedMetrics { /// Get cache hit rate as percentage pub fn cache_hit_rate(&self) -> f64 { let total = self.cache_stats.hits + self.cache_stats.misses; if total == 0 { 0.0 } else { (self.cache_stats.hits as f64 / total as f64) * 100.0 } } /// Get cache utilization as percentage pub fn cache_utilization(&self) -> f64 { if self.cache_stats.capacity == 0 { 0.0 } else { (self.cache_stats.size as f64 / self.cache_stats.capacity as f64) * 100.0 } } /// Get total error count pub fn total_errors(&self) -> u64 { self.error_counts.values().sum() } /// Get average processing time for an operation pub fn average_processing_time(&self, operation: &str) -> Option<u64> { self.processing_time.get(operation).copied() } } #[cfg(test)] mod tests { use super::*; use rkyv::{from_bytes, to_bytes}; #[test] fn test_archived_code_node() { let node = ArchivedCodeNode { id: 1, name: "test_function".to_string(), node_type: "function".to_string(), file_path: "src/lib.rs".to_string(), start_line: 10, end_line: 20, start_column: 0, end_column: 10, content: "fn test() {}".to_string(), hash: "abc123".to_string(), parent_id: Some(2), children: vec![3, 4], metadata: HashMap::new(), }; assert!(node.is_function()); assert!(!node.is_type_definition()); assert_eq!(node.line_count(), 11); assert!(node.contains_line(15)); assert!(!node.contains_line(25)); // Test serialization roundtrip let bytes = to_bytes::<rkyv::rancor::Failure>(&node).unwrap(); let deserialized = from_bytes::<ArchivedCodeNode, rkyv::rancor::Failure>(&bytes).unwrap(); assert_eq!(deserialized.id, 1); assert_eq!(deserialized.name, "test_function"); assert_eq!(deserialized.node_type, "function"); } #[test] fn test_archived_code_graph() { let mut nodes = HashMap::new(); nodes.insert( 1, ArchivedCodeNode { id: 1, name: "main".to_string(), node_type: "function".to_string(), file_path: "src/main.rs".to_string(), start_line: 1, end_line: 10, start_column: 0, end_column: 10, content: "fn main() {}".to_string(), hash: "hash1".to_string(), parent_id: None, children: vec![], metadata: HashMap::new(), }, ); let edges = vec![ArchivedCodeEdge { id: 1, source_id: 1, target_id: 2, edge_type: "calls".to_string(), weight: 1.0, metadata: HashMap::new(), }]; let graph = ArchivedCodeGraph { version: 1, timestamp: 1234567890, nodes, edges, metadata: HashMap::new(), file_hashes: HashMap::new(), }; assert_eq!(graph.node_count(), 1); assert_eq!(graph.edge_count(), 1); let node = graph.get_node(1).unwrap(); assert_eq!(node.name, "main"); let functions = graph.nodes_by_type("function"); assert_eq!(functions.len(), 1); // Test serialization let bytes = to_bytes::<rkyv::rancor::Failure>(&graph).unwrap(); let deserialized = from_bytes::<ArchivedCodeGraph, rkyv::rancor::Failure>(&bytes).unwrap(); assert_eq!(deserialized.version, 1); assert_eq!(deserialized.node_count(), 1); } #[test] fn test_archived_cache_entry() { let entry = ArchivedCacheEntry { key: "test_key".to_string(), value: "test_value".to_string(), created_at: 1000, expires_at: Some(2000), access_count: 5, last_accessed: 1500, }; assert!(!entry.is_expired(1800)); assert!(entry.is_expired(2100)); assert_eq!(entry.age(1500), 500); assert_eq!(entry.time_since_access(1700), 200); // Test serialization let bytes = to_bytes::<rkyv::rancor::Failure>(&entry).unwrap(); let deserialized = from_bytes::<ArchivedCacheEntry<String>, rkyv::rancor::Failure>(&bytes).unwrap(); assert_eq!(deserialized.key, "test_key"); assert_eq!(deserialized.value, "test_value"); } #[test] fn test_archived_metrics() { let mut processing_time = HashMap::new(); processing_time.insert("parse".to_string(), 100); processing_time.insert("index".to_string(), 200); let mut error_counts = HashMap::new(); error_counts.insert("parse_error".to_string(), 5); error_counts.insert("io_error".to_string(), 2); let metrics = ArchivedMetrics { timestamp: 1234567890, processing_time, memory_usage: HashMap::new(), cache_stats: ArchivedCacheStats { hits: 80, misses: 20, evictions: 5, size: 100, capacity: 200, }, error_counts, counters: HashMap::new(), }; assert_eq!(metrics.cache_hit_rate(), 80.0); assert_eq!(metrics.cache_utilization(), 50.0); assert_eq!(metrics.total_errors(), 7); assert_eq!(metrics.average_processing_time("parse"), Some(100)); // Test serialization let bytes = to_bytes::<rkyv::rancor::Failure>(&metrics).unwrap(); let deserialized = from_bytes::<ArchivedMetrics, rkyv::rancor::Failure>(&bytes).unwrap(); assert_eq!(deserialized.timestamp, 1234567890); assert_eq!(deserialized.cache_hit_rate(), 80.0); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jakedismo/codegraph-rust'

If you have feedback or need assistance with the MCP directory API, please join our Discord server