use mathcompile::final_tagless::{ASTEval, ASTMathExpr};
use mathcompile::symbolic::{CompilationStrategy, RustOptLevel, SymbolicOptimizer};
use std::fs;
#[test]
fn test_rust_compilation_and_execution() {
println!("🔧 Testing actual Rust compilation and execution...");
let temp_dir = std::env::temp_dir().join("mathcompile_test");
let source_dir = temp_dir.join("sources");
let lib_dir = temp_dir.join("libs");
fs::create_dir_all(&source_dir).unwrap();
fs::create_dir_all(&lib_dir).unwrap();
let strategy = CompilationStrategy::HotLoadRust {
source_dir: source_dir.clone(),
lib_dir: lib_dir.clone(),
opt_level: RustOptLevel::O2,
};
let optimizer = SymbolicOptimizer::with_strategy(strategy).unwrap();
let expr = ASTEval::add(
ASTEval::pow(ASTEval::var_by_name("x"), ASTEval::constant(2.0)),
ASTEval::constant(1.0),
);
let rust_code = optimizer.generate_rust_source(&expr, "test_func").unwrap();
println!("Generated Rust code:\n{rust_code}");
let source_path = source_dir.join("test_func.rs");
let lib_path = lib_dir.join("libtest_func.so");
let compile_result =
optimizer.compile_rust_dylib(&rust_code, &source_path, &lib_path, &RustOptLevel::O2);
match compile_result {
Ok(()) => {
println!("✅ Rust compilation successful!");
println!("Source file: {}", source_path.display());
println!("Library file: {}", lib_path.display());
if lib_path.exists() {
println!("✅ Dynamic library created successfully!");
#[cfg(feature = "libloading")]
test_dynamic_library_loading(&lib_path);
} else {
println!("❌ Dynamic library file not found");
}
}
Err(e) => {
println!("❌ Rust compilation failed: {e}");
println!("Note: This test requires rustc to be available in PATH");
}
}
let _ = fs::remove_dir_all(&temp_dir);
}
#[cfg(feature = "libloading")]
fn test_dynamic_library_loading(lib_path: &std::path::Path) {
use libloading::{Library, Symbol};
println!("🔗 Testing dynamic library loading...");
match unsafe { Library::new(lib_path) } {
Ok(lib) => {
println!("✅ Library loaded successfully!");
let func: Result<Symbol<unsafe extern "C" fn(f64) -> f64>, _> =
unsafe { lib.get(b"test_func") };
match func {
Ok(f) => {
println!("✅ Function symbol found!");
let result = unsafe { f(3.0) };
println!("test_func(3.0) = {result}");
let expected = 3.0_f64.powf(2.0) + 1.0;
assert!((result - expected).abs() < 1e-10);
println!("✅ Function execution successful and correct!");
}
Err(e) => {
println!("❌ Failed to get function symbol: {e}");
}
}
}
Err(e) => {
println!("❌ Failed to load library: {e}");
}
}
}
#[test]
fn test_optimization_with_compilation_strategy() {
println!("⚡ Testing optimization with compilation strategy selection...");
let mut optimizer = SymbolicOptimizer::new().unwrap();
optimizer.set_compilation_strategy(CompilationStrategy::Adaptive {
call_threshold: 2,
complexity_threshold: 5,
});
let expr = ASTEval::add(
ASTEval::mul(ASTEval::var_by_name("x"), ASTEval::constant(2.0)),
ASTEval::constant(1.0),
);
let mut config = mathcompile::symbolic::OptimizationConfig::default();
config.egglog_optimization = true;
let mut opt = SymbolicOptimizer::with_config(config).unwrap();
let optimized = opt.optimize(&expr).unwrap();
println!("Original: {expr:?}");
println!("Optimized: {optimized:?}");
for i in 0..5 {
let approach = optimizer.choose_compilation_approach(&optimized, "test_expr");
println!("Iteration {i}: Compilation approach: {approach:?}");
optimizer.record_execution("test_expr", 1000 + i * 100);
}
let stats = optimizer.get_expression_stats();
if let Some(expr_stats) = stats.get("test_expr") {
println!("Expression statistics: {expr_stats:?}");
assert!(expr_stats.call_count > 0);
}
}