use super::types::{FunctionInfo, PropertyInfo};
use crate::builtin_metadata::builtin_functions_from_macros;
use crate::stdlib_metadata::{StdlibMetadata, default_stdlib_path};
#[derive(Debug)]
pub struct UnifiedMetadata {
rust_builtins: Vec<FunctionInfo>,
stdlib_functions: Vec<FunctionInfo>,
stdlib_patterns: Vec<crate::stdlib_metadata::PatternInfo>,
type_metadata: Vec<TypeMetadataInfo>,
}
#[derive(Debug, Clone)]
pub struct TypeMetadataInfo {
pub name: String,
pub description: String,
pub properties: Vec<PropertyInfo>,
}
impl UnifiedMetadata {
pub fn load() -> Self {
use crate::builtin_metadata::collect_type_metadata;
let mut rust_builtins = builtin_functions_from_macros();
let stdlib_path = default_stdlib_path();
let stdlib = StdlibMetadata::load(&stdlib_path).unwrap_or_else(|e| {
eprintln!("Warning: Failed to load stdlib metadata: {}", e);
StdlibMetadata::empty()
});
if !stdlib.intrinsic_functions.is_empty() {
let intrinsic_by_name: std::collections::HashMap<_, _> = stdlib
.intrinsic_functions
.iter()
.map(|f| (f.name.clone(), f))
.collect();
for builtin in &mut rust_builtins {
if let Some(intrinsic) = intrinsic_by_name.get(&builtin.name) {
builtin.signature = intrinsic.signature.clone();
builtin.description = intrinsic.description.clone();
builtin.parameters = intrinsic.parameters.clone();
builtin.return_type = intrinsic.return_type.clone();
builtin.comptime_only = intrinsic.comptime_only;
}
}
for intrinsic in &stdlib.intrinsic_functions {
if !rust_builtins.iter().any(|f| f.name == intrinsic.name) {
rust_builtins.push(intrinsic.clone());
}
}
}
let type_metadata = collect_type_metadata()
.into_iter()
.map(|tm| TypeMetadataInfo {
name: tm.name.to_string(),
description: tm.description.to_string(),
properties: tm.to_property_infos(),
})
.collect();
Self {
rust_builtins,
stdlib_functions: stdlib.functions,
stdlib_patterns: stdlib.patterns,
type_metadata,
}
}
pub fn all_functions(&self) -> Vec<&FunctionInfo> {
let mut seen = std::collections::HashSet::new();
let mut result = Vec::new();
for func in &self.rust_builtins {
if seen.insert(&func.name) {
result.push(func);
}
}
for func in &self.stdlib_functions {
if seen.insert(&func.name) {
result.push(func);
}
}
result
}
pub fn get_function(&self, name: &str) -> Option<&FunctionInfo> {
if let Some(func) = self.rust_builtins.iter().find(|f| f.name == name) {
return Some(func);
}
self.stdlib_functions.iter().find(|f| f.name == name)
}
pub fn all_patterns(&self) -> &[crate::stdlib_metadata::PatternInfo] {
&self.stdlib_patterns
}
pub fn stdlib_functions(&self) -> &[FunctionInfo] {
&self.stdlib_functions
}
pub fn rust_builtins(&self) -> &[FunctionInfo] {
&self.rust_builtins
}
pub fn get_type_properties(&self, type_name: &str) -> Option<&[PropertyInfo]> {
self.type_metadata
.iter()
.find(|t| t.name.eq_ignore_ascii_case(type_name))
.map(|t| t.properties.as_slice())
}
pub fn all_types(&self) -> &[TypeMetadataInfo] {
&self.type_metadata
}
}
#[cfg(test)]
mod unified_metadata_tests {
use super::*;
#[test]
fn test_unified_metadata_load() {
let metadata = UnifiedMetadata::load();
let all_funcs: Vec<_> = metadata.all_functions().into_iter().collect();
assert!(!all_funcs.is_empty(), "Should have functions");
assert!(
metadata.get_function("abs").is_some(),
"abs should be present"
);
assert!(
metadata.get_function("sqrt").is_some(),
"sqrt should be present"
);
assert!(
metadata.get_function("snapshot").is_some(),
"snapshot should be present from stdlib"
);
}
#[test]
fn test_metadata_coverage() {
let metadata = UnifiedMetadata::load();
println!("\n=== Metadata Coverage ===");
println!(
"Rust builtins (proc-macro): {}",
metadata.rust_builtins().len()
);
for f in metadata.rust_builtins() {
println!(" - {}", f.name);
}
println!("\nStdlib functions: {}", metadata.stdlib_functions().len());
assert!(
!metadata.stdlib_functions().is_empty(),
"stdlib function metadata should not be empty"
);
let all_funcs = metadata.all_functions();
println!("\nTotal functions available: {}", all_funcs.len());
assert!(
metadata.get_function("abs").is_some(),
"abs should be present from builtins"
);
assert!(
metadata.get_function("sqrt").is_some(),
"sqrt should be present from builtins"
);
assert!(
metadata.get_function("snapshot").is_some(),
"snapshot should be present from stdlib"
);
}
#[test]
fn test_intrinsic_std_core_overrides_builtin_docs() {
let metadata = UnifiedMetadata::load();
let abs = metadata
.get_function("abs")
.expect("abs should be available in unified metadata");
assert_eq!(abs.signature, "abs(value: number) -> number");
assert!(
abs.description.contains("absolute value"),
"abs docs should be sourced from std::core intrinsic declarations"
);
}
#[test]
fn test_intrinsic_std_core_uses_table_signatures() {
let metadata = UnifiedMetadata::load();
let resample = metadata
.get_function("resample")
.expect("resample should be available in unified metadata");
assert!(
resample.signature.contains("Table<"),
"resample signature should use Table<T>, got: {}",
resample.signature
);
}
}