Skip to main content
Glama
models.rs10.2 kB
use bincode::{Decode, Encode}; use serde::{Deserialize, Serialize}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::path::PathBuf; use std::time::SystemTime; #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize, Encode, Decode)] pub struct SymbolId(pub u64); impl SymbolId { pub fn new(file_path: &PathBuf, start_line: u32, start_column: u32) -> Self { let mut hasher = DefaultHasher::new(); file_path.hash(&mut hasher); start_line.hash(&mut hasher); start_column.hash(&mut hasher); Self(hasher.finish()) } } #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct Symbol { pub id: SymbolId, pub name: String, pub symbol_type: SymbolType, pub location: Location, pub namespace: Option<String>, pub visibility: Visibility, pub source: Option<String>, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Encode, Decode)] pub enum SymbolType { Module, Class, Interface, Method, Function, Constant, Variable, Enum, Struct, Import, } impl SymbolType { pub fn as_str(&self) -> &'static str { match self { SymbolType::Module => "module", SymbolType::Class => "class", SymbolType::Interface => "interface", SymbolType::Method => "method", SymbolType::Function => "function", SymbolType::Constant => "constant", SymbolType::Variable => "variable", SymbolType::Enum => "enum", SymbolType::Struct => "struct", SymbolType::Import => "import", } } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Encode, Decode)] pub enum Visibility { Public, Private, Protected, Internal, } #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct Location { pub file: PathBuf, pub start_line: u32, pub start_column: u32, pub end_line: u32, pub end_column: u32, } impl Location { pub fn new( file: PathBuf, start_line: u32, start_column: u32, end_line: u32, end_column: u32, ) -> Self { Self { file, start_line, start_column, end_line, end_column, } } } #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct Reference { pub location: Location, pub reference_type: ReferenceType, pub target_symbol: SymbolId, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Encode, Decode)] pub enum ReferenceType { Definition, Usage, Import, Call, } #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct FileInfo { pub last_modified: SystemTime, pub content_hash: [u8; 32], pub symbol_count: u32, pub parse_status: ParseStatus, pub file_size: u64, } impl FileInfo { pub fn new(content_hash: [u8; 32], file_size: u64) -> Self { Self { last_modified: SystemTime::now(), content_hash, symbol_count: 0, parse_status: ParseStatus::NotParsed, file_size, } } pub fn from_file_content(content: &str) -> Self { use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); hasher.update(content.as_bytes()); let hash: [u8; 32] = hasher.finalize().into(); Self::new(hash, content.len() as u64) } pub async fn from_file_path(path: &std::path::Path) -> Result<Self, std::io::Error> { let content = tokio::fs::read_to_string(path).await?; let metadata = tokio::fs::metadata(path).await?; let mut file_info = Self::from_file_content(&content); file_info.last_modified = metadata.modified().unwrap_or(SystemTime::now()); file_info.file_size = metadata.len(); Ok(file_info) } pub fn has_changed(&self, other: &FileInfo) -> bool { self.content_hash != other.content_hash || self.last_modified != other.last_modified || self.file_size != other.file_size } pub fn update_parse_status(&mut self, status: ParseStatus, symbol_count: u32) { self.parse_status = status; self.symbol_count = symbol_count; } } #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub enum ParseStatus { Success, PartialSuccess(Vec<String>), Failed(String), NotParsed, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Language { Rust, Python, C, Cpp, Java, Go, JavaScript, TypeScript, Ruby, CSharp, Kotlin, Scala, Swift, PHP, ObjectiveC, } impl Language { pub fn from_extension(ext: &str) -> Option<Self> { match ext.to_lowercase().as_str() { "rs" => Some(Language::Rust), "py" => Some(Language::Python), "c" | "h" => Some(Language::C), "cpp" | "cc" | "cxx" | "hpp" | "hxx" => Some(Language::Cpp), "java" => Some(Language::Java), "go" => Some(Language::Go), "js" | "jsx" => Some(Language::JavaScript), "ts" | "tsx" => Some(Language::TypeScript), "rb" => Some(Language::Ruby), "cs" => Some(Language::CSharp), "kt" | "kts" => Some(Language::Kotlin), "scala" | "sc" => Some(Language::Scala), "swift" => Some(Language::Swift), "php" => Some(Language::PHP), "m" | "mm" => Some(Language::ObjectiveC), _ => None, } } pub fn from_path(path: &std::path::Path) -> Option<Self> { path.extension() .and_then(|ext| ext.to_str()) .and_then(|ext| Self::from_extension(ext)) } pub fn tree_sitter_language(&self) -> tree_sitter::Language { match self { Language::Rust => tree_sitter_rust::LANGUAGE.into(), Language::Python => tree_sitter_python::LANGUAGE.into(), Language::C => tree_sitter_c::LANGUAGE.into(), Language::Cpp => tree_sitter_cpp::LANGUAGE.into(), Language::Java => tree_sitter_java::LANGUAGE.into(), Language::Go => tree_sitter_go::LANGUAGE.into(), Language::JavaScript => tree_sitter_javascript::LANGUAGE.into(), Language::TypeScript => tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(), Language::Ruby => tree_sitter_ruby::LANGUAGE.into(), Language::CSharp => tree_sitter_c_sharp::LANGUAGE.into(), Language::Kotlin => tree_sitter_kotlin_ng::LANGUAGE.into(), Language::Scala => tree_sitter_scala::LANGUAGE.into(), Language::Swift => tree_sitter_swift::LANGUAGE.into(), Language::PHP => tree_sitter_php::LANGUAGE_PHP.into(), Language::ObjectiveC => tree_sitter_objc::LANGUAGE.into(), } } pub fn file_extensions(&self) -> &'static [&'static str] { match self { Language::Rust => &["rs"], Language::Python => &["py"], Language::C => &["c", "h"], Language::Cpp => &["cpp", "cc", "cxx", "hpp", "hxx"], Language::Java => &["java"], Language::Go => &["go"], Language::JavaScript => &["js", "jsx"], Language::TypeScript => &["ts", "tsx"], Language::Ruby => &["rb"], Language::CSharp => &["cs"], Language::Kotlin => &["kt", "kts"], Language::Scala => &["scala", "sc"], Language::Swift => &["swift"], Language::PHP => &["php"], Language::ObjectiveC => &["m", "mm"], } } pub fn is_source_file(path: &std::path::Path) -> bool { Self::from_path(path).is_some() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_symbol_id_generation() { let path = PathBuf::from("test.rs"); let id1 = SymbolId::new(&path, 1, 0); let id2 = SymbolId::new(&path, 1, 0); let id3 = SymbolId::new(&path, 2, 0); assert_eq!(id1, id2); // Same location should generate same ID assert_ne!(id1, id3); // Different location should generate different ID } #[test] fn test_language_detection() { assert_eq!(Language::from_extension("rs"), Some(Language::Rust)); assert_eq!(Language::from_extension("py"), Some(Language::Python)); assert_eq!(Language::from_extension("js"), Some(Language::JavaScript)); assert_eq!(Language::from_extension("cs"), Some(Language::CSharp)); assert_eq!(Language::from_extension("kt"), Some(Language::Kotlin)); assert_eq!(Language::from_extension("scala"), Some(Language::Scala)); assert_eq!(Language::from_extension("swift"), Some(Language::Swift)); assert_eq!(Language::from_extension("php"), Some(Language::PHP)); assert_eq!(Language::from_extension("m"), Some(Language::ObjectiveC)); assert_eq!(Language::from_extension("unknown"), None); } #[test] fn test_symbol_type_string_conversion() { assert_eq!(SymbolType::Function.as_str(), "function"); assert_eq!(SymbolType::Class.as_str(), "class"); assert_eq!(SymbolType::Module.as_str(), "module"); } #[test] fn test_serialization() { let path = PathBuf::from("test.rs"); let location = Location::new(path.clone(), 1, 0, 1, 10); let symbol_id = SymbolId::new(&path, 1, 0); let symbol = Symbol { id: symbol_id, name: "test_function".to_string(), symbol_type: SymbolType::Function, location, namespace: None, visibility: Visibility::Public, source: None, }; // Test serialization/deserialization let serialized = serde_json::to_string(&symbol).unwrap(); let deserialized: Symbol = serde_json::from_str(&serialized).unwrap(); assert_eq!(symbol.name, deserialized.name); assert_eq!(symbol.symbol_type, deserialized.symbol_type); } }

Latest Blog Posts

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/kensave/CodeCortX-MCP'

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