use std::collections::HashMap; use prometeu_analysis::ids::ProjectId; #[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] pub struct ProjectKey { pub name: String, pub version: String, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct ProjectMeta { pub id: ProjectId, pub name: String, pub version: String, } #[derive(Debug, Default, Clone)] pub struct ProjectRegistry { by_name: HashMap, projects: Vec, } impl ProjectRegistry { pub fn new() -> Self { Self::default() } pub fn intern(&mut self, key: &ProjectKey) -> ProjectId { if let Some(id) = self.by_name.get(key).copied() { return id; } let id = ProjectId(self.projects.len() as u32); self.by_name.insert(key.clone(), id); self.projects.push(ProjectMeta { id, name: key.name.clone(), version: key.version.clone() }); id } pub fn meta(&self, id: ProjectId) -> Option<&ProjectMeta> { self.projects.get(id.as_usize()) } pub fn key_of(&self, id: ProjectId) -> Option { self.meta(id).map(|m| ProjectKey { name: m.name.clone(), version: m.version.clone() }) } pub fn len(&self) -> usize { self.projects.len() } pub fn is_empty(&self) -> bool { self.projects.is_empty() } } #[cfg(test)] mod tests { use super::*; #[test] fn project_registry_stable_ids_for_same_key() { let mut reg = ProjectRegistry::new(); let k = ProjectKey { name: "sdk".into(), version: "1.0.0".into() }; let id1 = reg.intern(&k); let id2 = reg.intern(&k); assert_eq!(id1, id2); // Different version -> different id let k2 = ProjectKey { name: "sdk".into(), version: "1.1.0".into() }; let id3 = reg.intern(&k2); assert_ne!(id1, id3); // Meta lookup let m1 = reg.meta(id1).unwrap(); assert_eq!(m1.name, "sdk"); assert_eq!(m1.version, "1.0.0"); } }