use crate::ir;
use std::sync::Arc;
use super::{CLASS_DICT_CACHE, ClassDict, is_cache_enabled};
static LIBRARY_DICT_CACHE: std::sync::LazyLock<
std::sync::RwLock<std::collections::HashMap<String, Arc<ClassDict>>>,
> = std::sync::LazyLock::new(|| std::sync::RwLock::new(std::collections::HashMap::new()));
pub fn get_or_build_library_dict(name: &str, def: &ir::ast::StoredDefinition) -> Arc<ClassDict> {
if let Some(dict) = LIBRARY_DICT_CACHE
.read()
.expect("library dict cache lock poisoned")
.get(name)
{
return Arc::clone(dict);
}
let mut dict = ClassDict::new();
for (_name, class) in &def.class_list {
build_class_dict_internal(class, "", &mut dict);
}
let dict = Arc::new(dict);
LIBRARY_DICT_CACHE
.write()
.expect("library dict cache lock poisoned")
.insert(name.to_string(), Arc::clone(&dict));
dict
}
pub fn clear_library_dict_cache() {
LIBRARY_DICT_CACHE
.write()
.expect("library dict cache lock poisoned")
.clear();
}
pub fn build_combined_class_dict(
user_def: &ir::ast::StoredDefinition,
library_dicts: &[Arc<ClassDict>],
) -> Arc<ClassDict> {
let mut dict = ClassDict::new();
for lib_dict in library_dicts {
for (name, class_arc) in lib_dict.iter() {
dict.insert(name.clone(), Arc::clone(class_arc));
}
}
for (_name, class) in &user_def.class_list {
build_class_dict_internal(class, "", &mut dict);
}
if let Some(builtin_defs) = crate::ir::transform::builtins::get_builtin_definitions() {
for (name, class) in &builtin_defs.class_list {
if !dict.contains_key(name) {
build_class_dict_internal(class, "", &mut dict);
}
}
}
Arc::new(dict)
}
pub(super) fn build_class_dict_internal(
class: &ir::ast::ClassDefinition,
prefix: &str,
dict: &mut ClassDict,
) {
let full_name = if prefix.is_empty() {
class.name.text.clone()
} else {
format!("{}.{}", prefix, class.name.text)
};
dict.insert(full_name.clone(), Arc::new(class.clone()));
for (_name, nested_class) in &class.classes {
build_class_dict_internal(nested_class, &full_name, dict);
}
}
pub(super) fn get_or_build_class_dict(
def: &ir::ast::StoredDefinition,
def_hash: u64,
) -> Arc<ClassDict> {
if is_cache_enabled()
&& let Some(dict) = CLASS_DICT_CACHE
.read()
.expect("class dict cache lock poisoned")
.get(&def_hash)
{
return Arc::clone(dict);
}
let mut dict = ClassDict::new();
for (_name, class) in &def.class_list {
build_class_dict_internal(class, "", &mut dict);
}
if let Some(builtin_defs) = crate::ir::transform::builtins::get_builtin_definitions() {
for (name, class) in &builtin_defs.class_list {
if !dict.contains_key(name) {
build_class_dict_internal(class, "", &mut dict);
}
}
}
let dict = Arc::new(dict);
if is_cache_enabled() {
CLASS_DICT_CACHE
.write()
.expect("class dict cache lock poisoned")
.insert(def_hash, Arc::clone(&dict));
}
dict
}
pub(super) fn lookup_class(
def: &ir::ast::StoredDefinition,
class_dict: &ClassDict,
path: &str,
) -> Option<Arc<ir::ast::ClassDefinition>> {
if let Some(class) = class_dict.get(path) {
return Some(Arc::clone(class));
}
let parts: Vec<&str> = path.split('.').collect();
if parts.is_empty() {
return None;
}
let root = def.class_list.get(parts[0])?;
if parts.len() == 1 {
return Some(Arc::new(root.clone()));
}
let mut current = root;
for part in &parts[1..] {
current = current.classes.get(*part)?;
}
Some(Arc::new(current.clone()))
}