use std::collections::{HashMap, HashSet};
use crate::core::ir::{EnumDef, TypeDef};
use crate::e2e::codegen::call_ir::named_type;
use super::parse::{parse_path, segment_name};
use super::types::IrEnumMap;
use super::types::PathSegment;
pub(super) fn build_ir_enum_map(type_defs: &[TypeDef], enums: &[EnumDef]) -> IrEnumMap {
let enum_names: HashSet<&str> = enums.iter().map(|e| e.name.as_str()).collect();
let struct_names: HashSet<&str> = type_defs.iter().map(|t| t.name.as_str()).collect();
let mut field_types: HashMap<String, HashMap<String, String>> = HashMap::new();
let mut enum_fields: HashMap<String, HashSet<String>> = HashMap::new();
let mut enum_field_types: HashMap<String, HashMap<String, String>> = HashMap::new();
for type_def in type_defs {
for field in &type_def.fields {
let Some(named) = named_type(&field.ty) else {
continue;
};
if enum_names.contains(named) {
enum_fields
.entry(type_def.name.clone())
.or_default()
.insert(field.name.clone());
enum_field_types
.entry(type_def.name.clone())
.or_default()
.insert(field.name.clone(), named.to_string());
} else if struct_names.contains(named) {
field_types
.entry(type_def.name.clone())
.or_default()
.insert(field.name.clone(), named.to_string());
}
}
}
IrEnumMap {
field_types,
enum_fields,
enum_field_types,
root_type: None,
}
}
fn resolve_owner<'a>(map: &'a IrEnumMap, root: &'a str, prefix: &[PathSegment]) -> Option<&'a str> {
let mut owner = root;
for segment in prefix {
let name = segment_name(segment)?;
let next = map.field_types.get(owner).and_then(|fields| fields.get(name))?;
owner = next.as_str();
}
Some(owner)
}
pub(super) fn is_enum_path(map: &IrEnumMap, path: &str) -> bool {
let Some(root) = map.root_type.as_deref() else {
return false;
};
let segments = parse_path(path);
let Some((last, prefix)) = segments.split_last() else {
return false;
};
let Some(owner) = resolve_owner(map, root, prefix) else {
return false;
};
let Some(name) = segment_name(last) else {
return false;
};
map.enum_fields.get(owner).is_some_and(|fields| fields.contains(name))
}
pub(super) fn enum_type_at_path(map: &IrEnumMap, path: &str) -> Option<String> {
let root = map.root_type.as_deref()?;
let segments = parse_path(path);
let (last, prefix) = segments.split_last()?;
let owner = resolve_owner(map, root, prefix)?;
let name = segment_name(last)?;
map.enum_field_types
.get(owner)
.and_then(|fields| fields.get(name))
.cloned()
}