use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::RwLock;
use super::gguf_parser::{GgufMetadata, GgufParseError, GgufParser};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ModelHandle(String);
impl ModelHandle {
pub fn name(&self) -> &str {
&self.0
}
}
#[derive(Debug, Clone)]
pub struct ModelInfo {
pub handle: ModelHandle,
pub path: PathBuf,
pub metadata: GgufMetadata,
}
impl ModelInfo {
pub fn embedding_dim(&self) -> Option<usize> {
self.metadata.arch.embedding_length.map(|v| v as usize)
}
pub fn vocab_size(&self) -> Option<usize> {
self.metadata.arch.vocab_size.map(|v| v as usize)
}
}
#[derive(Debug, thiserror::Error)]
pub enum RegistryError {
#[error("model '{0}' already registered")]
AlreadyRegistered(String),
#[error("model '{0}' not found")]
NotFound(String),
#[error("GGUF parse error: {0}")]
ParseError(#[from] GgufParseError),
}
#[derive(Default)]
pub struct ModelRegistry {
models: RwLock<HashMap<String, ModelInfo>>,
}
impl ModelRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&self, name: &str, path: PathBuf) -> Result<ModelHandle, RegistryError> {
let metadata = GgufParser::parse_file(&path)?;
self.register_with_metadata(name, path, metadata)
}
pub fn register_with_metadata(
&self,
name: &str,
path: PathBuf,
metadata: GgufMetadata,
) -> Result<ModelHandle, RegistryError> {
let mut map = self.models.write().expect("registry lock poisoned");
if map.contains_key(name) {
return Err(RegistryError::AlreadyRegistered(name.to_owned()));
}
let handle = ModelHandle(name.to_owned());
let info = ModelInfo {
handle: handle.clone(),
path,
metadata,
};
map.insert(name.to_owned(), info);
Ok(handle)
}
pub fn get(&self, handle: &ModelHandle) -> Option<ModelInfo> {
let map = self.models.read().expect("registry lock poisoned");
map.get(handle.name()).cloned()
}
pub fn get_by_name(&self, name: &str) -> Option<ModelInfo> {
let map = self.models.read().expect("registry lock poisoned");
map.get(name).cloned()
}
pub fn list(&self) -> Vec<ModelHandle> {
let map = self.models.read().expect("registry lock poisoned");
map.values().map(|info| info.handle.clone()).collect()
}
pub fn remove(&self, handle: &ModelHandle) -> bool {
let mut map = self.models.write().expect("registry lock poisoned");
map.remove(handle.name()).is_some()
}
pub fn len(&self) -> usize {
let map = self.models.read().expect("registry lock poisoned");
map.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}