use std::collections::HashMap;
use std::sync::{OnceLock, RwLock};
use super::TypeNode;
pub struct Lattice {
by_id: &'static HashMap<&'static str, &'static TypeNode>,
cache: RwLock<HashMap<(usize, usize), bool>>,
}
impl Lattice {
pub fn get() -> &'static Lattice {
static LATTICE: OnceLock<Lattice> = OnceLock::new();
LATTICE.get_or_init(|| Lattice {
by_id: super::id_to_node_map(),
cache: RwLock::new(HashMap::new()),
})
}
pub fn is_subtype(&self, child: &'static TypeNode, parent: &'static TypeNode) -> bool {
if std::ptr::eq(child, parent) {
return true;
}
let key = (child as *const _ as usize, parent as *const _ as usize);
if let Some(&hit) = self.cache.read().expect("lattice cache poisoned").get(&key) {
return hit;
}
let mut cursor = child.parent;
let mut found = false;
while let Some(parent_id) = cursor {
let Some(node) = self.by_id.get(parent_id).copied() else {
break;
};
if std::ptr::eq(node, parent) {
found = true;
break;
}
cursor = node.parent;
}
self.cache
.write()
.expect("lattice cache poisoned")
.insert(key, found);
found
}
pub fn lookup(&self, id: &str) -> Option<&'static TypeNode> {
self.by_id.get(id).copied()
}
pub fn nodes(&self) -> impl Iterator<Item = &'static TypeNode> + '_ {
self.by_id.values().copied()
}
}