#![deny(missing_docs)]
#![warn(clippy::all)]
mod result;
pub mod traits;
mod handlers;
mod macros;
pub use result::PipexResult;
pub use traits::{PipelineResultHandler, ExtractSuccessful, IntoResult, CreateError};
pub use handlers::{
ErrorHandler, IgnoreHandler, CollectHandler, FailFastHandler, LogAndIgnoreHandler
};
pub use pipex_macros::{error_strategy, pure, memoized};
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub use futures;
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub use tokio;
#[cfg(feature = "parallel")]
#[cfg_attr(docsrs, doc(cfg(feature = "parallel")))]
pub use rayon;
#[cfg(feature = "memoization")]
#[cfg_attr(docsrs, doc(cfg(feature = "memoization")))]
pub use dashmap;
#[cfg(feature = "memoization")]
#[cfg_attr(docsrs, doc(cfg(feature = "memoization")))]
pub use once_cell;
#[cfg(feature = "gpu")]
#[cfg_attr(docsrs, doc(cfg(feature = "gpu")))]
pub mod gpu;
#[cfg(feature = "gpu")]
#[cfg_attr(docsrs, doc(cfg(feature = "gpu")))]
pub use wgpu;
#[cfg(feature = "gpu")]
#[cfg_attr(docsrs, doc(cfg(feature = "gpu")))]
pub use bytemuck;
use std::collections::HashMap;
use std::sync::{Mutex, OnceLock};
use std::any::{Any, TypeId};
static STRATEGY_REGISTRY: OnceLock<Mutex<HashMap<String, Box<dyn Any + Send + Sync>>>> = OnceLock::new();
pub fn register_strategy<T, E>(
name: &str,
handler: fn(Vec<Result<T, E>>) -> Vec<Result<T, E>>
) where
T: 'static,
E: std::fmt::Debug + 'static,
{
let registry = STRATEGY_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()));
let mut registry = registry.lock().unwrap();
let type_id = (TypeId::of::<T>(), TypeId::of::<E>());
let key = format!("{}_{:?}", name, type_id);
registry.insert(key, Box::new(handler));
}
fn try_registered_strategy<T, E>(strategy_name: &str, results: &Vec<Result<T, E>>) -> Option<Vec<Result<T, E>>>
where
T: 'static + Clone,
E: std::fmt::Debug + 'static + Clone,
{
let registry = STRATEGY_REGISTRY.get()?;
let registry = registry.lock().unwrap();
let type_id = (TypeId::of::<T>(), TypeId::of::<E>());
let key = format!("{}_{:?}", strategy_name, type_id);
if let Some(handler_any) = registry.get(&key) {
if let Some(handler) = handler_any.downcast_ref::<fn(Vec<Result<T, E>>) -> Vec<Result<T, E>>>() {
return Some(handler(results.clone()));
}
}
None
}
pub fn apply_strategy<T, E>(strategy_name: &str, results: Vec<Result<T, E>>) -> Vec<Result<T, E>>
where
T: 'static + Clone,
E: std::fmt::Debug + 'static + Clone,
{
if let Some(result) = try_registered_strategy(strategy_name, &results) {
return result;
}
match strategy_name {
"IgnoreHandler" => IgnoreHandler::handle_results(results),
"CollectHandler" => CollectHandler::handle_results(results),
"FailFastHandler" => FailFastHandler::handle_results(results),
"LogAndIgnoreHandler" => LogAndIgnoreHandler::handle_results(results),
_ => {
eprintln!("Warning: Unknown strategy '{}'. Use register_strategy() to register custom handlers.", strategy_name);
results
}
}
}
#[cfg(test)]
mod tests {
use super::*;
pub struct FirstErrorHandler;
impl<T, E> ErrorHandler<T, E> for FirstErrorHandler {
fn handle_results(results: Vec<Result<T, E>>) -> Vec<Result<T, E>> {
results.into_iter()
.find(|r| r.is_err())
.map_or(Vec::new(), |e| vec![e])
}
}
use std::sync::Once;
static INIT: Once = Once::new();
fn setup() {
INIT.call_once(|| {
register_strategies!( FirstErrorHandler for <i32, String> );
});
}
pub fn apply_strategy<T, E>(strategy_name: &str, results: Vec<Result<T, E>>) -> Vec<Result<T, E>>
where
T: 'static + Clone,
E: std::fmt::Debug + 'static + Clone,
{
setup(); crate::apply_strategy(strategy_name, results)
}
async fn simple_double(x: i32) -> Result<i32, String> {
if x == 3 {
Err("failed on 3".to_string())
} else {
Ok(x * 2)
}
}
#[error_strategy(CollectHandler)]
async fn process_and_collect(x: i32) -> Result<i32, String> {
if x == 3 {
Err("failed on 3".to_string())
} else {
Ok(x * 2)
}
}
#[error_strategy(IgnoreHandler)]
async fn process_and_ignore(x: i32) -> Result<i32, String> {
if x == 3 {
Err("failed on 3".to_string())
} else {
Ok(x * 2)
}
}
#[error_strategy(FailFastHandler)]
async fn process_with_failfast(x: i32) -> Result<i32, String> {
if x == 3 {
Err("failed on 3".to_string())
} else {
Ok(x * 2)
}
}
#[error_strategy(LogAndIgnoreHandler)]
async fn process_with_log_and_ignore(x: i32) -> Result<i32, String> {
if x == 3 {
Err("failed on 3".to_string())
} else {
Ok(x * 2)
}
}
#[error_strategy(FirstErrorHandler)]
async fn process_with_first_error(x: i32) -> Result<i32, String> {
if x == 3 {
Err("failed on 3".to_string())
} else {
Ok(x * 2)
}
}
#[tokio::test]
async fn test_basic_async_pipeline() {
let result = pipex!(
vec![1, 2, 4, 5]
=> async |x| { simple_double(x).await }
=> |x| Ok::<i32, String>(x + 1)
);
assert_eq!(result.len(), 4);
assert!(result.iter().all(|r| r.is_ok()));
let values: Vec<i32> = result.into_iter().map(|r| r.unwrap()).collect();
assert_eq!(values, vec![3, 5, 9, 11]); }
#[tokio::test]
async fn test_sync_pipeline() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> |x| Ok::<i32, String>(x * 2)
=> |x| Ok::<i32, String>(x + 1)
);
assert_eq!(result.len(), 5);
assert!(result.iter().all(|r| r.is_ok()));
let values: Vec<i32> = result.into_iter().map(|r| r.unwrap()).collect();
assert_eq!(values, vec![3, 5, 7, 9, 11]); }
#[tokio::test]
async fn test_strategy_collect() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> async |x| { process_and_collect(x).await }
);
assert!(result.iter().any(|r| r.is_err()));
assert_eq!(result.len(), 5);
eprintln!("result: {:?}", result);
}
#[tokio::test]
async fn test_strategy_ignore() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> async |x| { process_and_ignore(x).await }
);
assert_eq!(result.len(), 4); assert!(result.iter().all(|r| r.is_ok()));
eprintln!("result: {:?}", result);
}
#[tokio::test]
async fn test_strategy_log_and_ignore() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> async |x| { process_with_log_and_ignore(x).await }
);
assert_eq!(result.len(), 4); assert!(result.iter().all(|r| r.is_ok()));
let values: Vec<i32> = result.into_iter().map(|r| r.unwrap()).collect();
assert_eq!(values, vec![2, 4, 8, 10]); }
#[tokio::test]
async fn test_strategy_failfast() {
let result = pipex!(
vec![1, 2, 3, 4, 5, 3]
=> async |x| { process_with_failfast(x).await }
);
assert!(result.iter().all(|r| r.is_err()));
assert_eq!(result.len(), 2); eprintln!("result: {:?}", result);
}
#[tokio::test]
async fn test_custom_first_error_handler() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> async |x| { process_with_first_error(x).await }
);
assert_eq!(result.len(), 1);
assert!(result[0].is_err());
eprintln!("FirstErrorHandler result: {:?}", result);
}
#[cfg(feature = "parallel")]
#[tokio::test]
async fn test_parallel_pipeline() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> ||| |x| Ok::<i32, String>(x * 2)
);
assert_eq!(result.len(), 5);
assert!(result.iter().all(|r| r.is_ok()));
eprintln!("result: {:?}", result);
}
#[error_strategy(IgnoreHandler)]
fn sync_process_and_ignore(x: i32) -> Result<i32, String> {
if x == 3 { Err("failed on 3".to_string()) }
else { Ok(x * 2) }
}
#[test]
fn test_sync_step_with_error_strategy() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> |x| sync_process_and_ignore(x)
=> |x| Ok::<i32, String>(x + 1)
);
assert_eq!(result.len(), 4); assert!(result.iter().all(|r| r.is_ok()));
eprintln!("result: {:?}", result);
let values: Vec<i32> = result.into_iter().map(|r| r.unwrap()).collect();
let expected_values = vec![3, 5, 9, 11]; let mut actual_values = values;
actual_values.sort(); assert_eq!(actual_values, expected_values);
}
#[tokio::test]
async fn test_mixed_sync_and_async_pipeline() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> |x| sync_process_and_ignore(x) => |x| Ok::<i32, String>(x - 1)
=> async |x| { process_and_collect(x).await } );
assert_eq!(result.len(), 4, "Expected 4 results after IgnoreHandler dropped one item.");
eprintln!("Mixed sync-async-sync pipeline (Ignore then Collect) result: {:?}", result);
let actual_results: Vec<Result<i32, String>> = result.into_iter().collect();
assert_eq!(actual_results.len(), 4);
}
#[pure]
fn pure_add(a: i32, b: i32) -> i32 {
a + b
}
#[pure]
fn pure_multiply(a: i32, b: i32) -> i32 {
pure_add(a, b) * 2 }
#[pure]
fn pure_transform(x: i32) -> i32 {
x * x + 1 }
#[test]
fn test_pure_functions() {
assert_eq!(pure_add(5, 3), 8);
assert_eq!(pure_multiply(4, 2), 12); assert_eq!(pure_transform(6), 37); }
#[test]
fn test_pure_function_composition() {
let result = pure_multiply(3, 4);
assert_eq!(result, 14);
let step1 = pure_add(2, 3); let step2 = pure_transform(step1); let step3 = pure_add(step2, 4); assert_eq!(step3, 30);
}
#[test]
fn test_pure_functions_in_pipeline() {
let result = pipex!(
vec![1, 2, 3, 4, 5]
=> |x| Ok::<i32, String>(pure_transform(x))
=> |x| Ok::<i32, String>(pure_add(x, 10))
);
assert_eq!(result.len(), 5);
assert!(result.iter().all(|r| r.is_ok()));
let values: Vec<i32> = result.into_iter().map(|r| r.unwrap()).collect();
assert_eq!(values, vec![12, 15, 20, 27, 36]);
}
fn regular_impure_function(x: i32) -> i32 {
x * 2
}
#[pure]
#[memoized]
fn fibonacci_memoized(n: u64) -> u64 {
if n <= 1 {
n
} else {
fibonacci_memoized(n - 1) + fibonacci_memoized(n - 2)
}
}
#[pure]
#[memoized(capacity = 200)]
#[error_strategy(CollectHandler)]
fn advanced_mathematical_operation(x: i32, y: i32) -> Result<i32, String> {
if x < 0 || y < 0 {
return Err(format!("Negative inputs not supported: x={}, y={}", x, y));
}
if x > 100 || y > 100 {
return Err(format!("Inputs too large: x={}, y={}", x, y));
}
let mut result = x * x + y * y;
for i in 1..10 {
result = result + (i * (x + y)) / (i + 1);
}
Ok(result)
}
#[pure]
#[memoized(capacity = 100)]
fn expensive_computation(x: i32, y: i32) -> i32 {
let mut result = x * x + y * y;
for i in 0..1000 {
result = result + (i % 2);
}
result
}
#[pure]
fn fibonacci_regular(n: u64) -> u64 {
if n <= 1 {
n
} else {
fibonacci_regular(n - 1) + fibonacci_regular(n - 2)
}
}
#[test]
fn test_memoized_basic_functionality() {
assert_eq!(fibonacci_memoized(10), 55);
assert_eq!(fibonacci_memoized(15), 610);
let result1 = expensive_computation(3, 4);
let result2 = expensive_computation(5, 12);
assert_eq!(expensive_computation(3, 4), result1);
assert_eq!(expensive_computation(5, 12), result2);
}
#[test]
fn test_memoized_performance_improvement() {
use std::time::Instant;
let start = Instant::now();
let result1 = expensive_computation(10, 20);
let duration1 = start.elapsed();
let start = Instant::now();
let result2 = expensive_computation(10, 20);
let duration2 = start.elapsed();
assert_eq!(result1, result2);
if duration2 > duration1 {
println!("⚠️ Cache wasn't faster this time (timing variance): {:?} vs {:?}", duration2, duration1);
println!(" This is normal in test environments with timing variance");
} else {
println!("✅ Cache was faster: {:?} vs {:?}", duration2, duration1);
}
}
#[test]
fn test_memoized_with_different_parameters() {
let result1 = expensive_computation(1, 1);
let result2 = expensive_computation(2, 2);
let result3 = expensive_computation(3, 3);
assert_eq!(expensive_computation(1, 1), result1); assert_eq!(expensive_computation(2, 2), result2); assert_eq!(expensive_computation(3, 3), result3); }
#[test]
fn test_memoized_in_pipeline() {
let result = pipex!(
vec![(1, 1), (2, 2), (3, 3), (1, 1)] => |pair| Ok::<i32, String>(expensive_computation(pair.0, pair.1))
=> |x| Ok::<i32, String>(x * 2)
);
assert_eq!(result.len(), 4);
assert!(result.iter().all(|r| r.is_ok()));
let values: Vec<i32> = result.into_iter().map(|r| r.unwrap()).collect();
assert_eq!(values.len(), 4);
assert_eq!(values[0], values[3]); }
#[test]
fn test_fibonacci_memoization() {
assert_eq!(fibonacci_memoized(20), 6765);
assert_eq!(fibonacci_memoized(25), 75025);
assert_eq!(fibonacci_memoized(22), 17711);
}
#[test]
fn test_triple_power_error_pure_memoized() {
let result1 = advanced_mathematical_operation(5, 10);
assert!(result1.is_ok());
let value1 = result1.unwrap();
let result2 = advanced_mathematical_operation(5, 10);
assert!(result2.is_ok());
assert_eq!(result2.unwrap(), value1);
let error_result1 = advanced_mathematical_operation(-1, 5);
assert!(error_result1.is_err());
assert!(error_result1.unwrap_err().contains("Negative inputs not supported"));
let error_result2 = advanced_mathematical_operation(150, 10);
assert!(error_result2.is_err());
assert!(error_result2.unwrap_err().contains("Inputs too large"));
let input_data = vec![
(5, 10), (-1, 5), (10, 20), (5, 10), (200, 5), ];
let pipeline_result = pipex!(
input_data
=> |pair| advanced_mathematical_operation(pair.0, pair.1)
=> |x| Ok::<i32, String>(x + 100) );
assert_eq!(pipeline_result.len(), 5);
assert!(pipeline_result[0].is_ok()); assert!(pipeline_result[1].is_err()); assert!(pipeline_result[2].is_ok()); assert!(pipeline_result[3].is_ok()); assert!(pipeline_result[4].is_err());
let first_success = pipeline_result[0].as_ref().unwrap();
let cached_success = pipeline_result[3].as_ref().unwrap();
assert_eq!(first_success, cached_success);
let success_count = pipeline_result.iter().filter(|r| r.is_ok()).count();
let error_count = pipeline_result.iter().filter(|r| r.is_err()).count();
assert_eq!(success_count, 3); assert_eq!(error_count, 2);
println!("✅ Triple Power Test Complete!");
println!(" 🔒 Pure: Compile-time safety guaranteed");
println!(" ⚡ Memoized: Performance optimization active");
println!(" 🛡️ Error Strategy: Automatic error handling");
println!(" 📊 Results: {} success, {} errors", success_count, error_count);
}
#[cfg(feature = "gpu")]
#[tokio::test]
async fn test_basic_gpu_kernel() {
let kernel = r#"
@group(0) @binding(0) var<storage, read> input: array<f32>;
@group(0) @binding(1) var<storage, read_write> output: array<f32>;
@compute @workgroup_size(1)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let index = global_id.x;
if (index >= arrayLength(&input)) { return; }
output[index] = input[index] * 2.0;
}
"#;
let input_data = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];
let expected = vec![2.0f32, 4.0, 6.0, 8.0, 10.0];
match crate::gpu::execute_gpu_kernel(input_data, kernel).await {
Ok(result) => {
assert_eq!(result, expected);
println!("✅ Basic GPU kernel test passed!");
},
Err(e) => {
println!("⚠️ GPU test skipped (no GPU available): {}", e);
}
}
}
#[cfg(feature = "gpu")]
#[tokio::test]
async fn test_gpu_pipeline_integration() {
let input_data = vec![1.0f32, 2.0, 3.0, 4.0];
let result = pipex!(
input_data
=> |x| Ok::<f32, String>(x + 1.0) => gpu r#"
@group(0) @binding(0) var<storage, read> input: array<f32>;
@group(0) @binding(1) var<storage, read_write> output: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let index = global_id.x;
if (index >= arrayLength(&input)) { return; }
output[index] = input[index] * input[index];
}
"# |data: Vec<f32>| { Ok(data) } => |x| Ok::<f32, String>(x - 1.0) );
assert_eq!(result.len(), 4);
if result.iter().all(|r| r.is_ok()) {
let values: Vec<f32> = result.into_iter().map(|r| r.unwrap()).collect();
let expected = vec![3.0f32, 8.0, 15.0, 24.0];
assert_eq!(values, expected);
println!("✅ GPU pipeline integration test passed!");
println!(" 🔄 CPU -> GPU -> CPU pipeline works!");
println!(" 📊 Results: {:?}", values);
} else {
println!("⚠️ GPU pipeline test failed - some operations errored");
for (i, result) in result.iter().enumerate() {
if let Err(e) = result {
println!(" ❌ Item {}: {}", i, e);
}
}
}
}
#[cfg(feature = "gpu")]
#[tokio::test]
async fn test_gpu_with_errors() {
let input_data = vec![1.0f32, 3.0f32, 4.0f32];
let result = pipex!(
input_data
=> |x| if x == 3.0 { Err("error item".to_string()) } else { Ok(x) } => gpu r#"
@group(0) @binding(0) var<storage, read> input: array<f32>;
@group(0) @binding(1) var<storage, read_write> output: array<f32>;
@compute @workgroup_size(1)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let index = global_id.x;
if (index >= arrayLength(&input)) { return; }
output[index] = input[index] * 10.0;
}
"# |data: Vec<f32>| { Ok(data) }
=> |x| Ok::<f32, String>(x + 100.0)
);
assert_eq!(result.len(), 3);
assert!(result[1].is_err());
if result[0].is_ok() && result[2].is_ok() {
assert!((result[0].as_ref().unwrap() - 110.0).abs() < 0.001); assert!((result[2].as_ref().unwrap() - 140.0).abs() < 0.001);
println!("✅ GPU error handling test passed!");
println!(" 🛡️ Errors preserved through GPU pipeline");
println!(" ⚡ GPU computation: [110.0, Error, 140.0]");
} else {
println!("⚠️ GPU error handling test failed");
for (i, result) in result.iter().enumerate() {
match result {
Ok(val) => println!(" ✅ Item {}: {}", i, val),
Err(e) => println!(" ❌ Item {}: {}", i, e),
}
}
}
}
#[cfg(feature = "gpu")]
#[tokio::test]
async fn test_gpu_performance_vs_cpu() {
use std::time::Instant;
let data: Vec<f32> = (0..1000).map(|i| i as f32).collect();
let cpu_start = Instant::now();
let cpu_result = pipex!(
data.clone()
=> |x| Ok::<f32, String>((x * 0.1).sin() * (x * 0.2).cos() + (x + 1.0).sqrt())
);
let cpu_duration = cpu_start.elapsed();
let gpu_start = Instant::now();
let gpu_result = pipex!(
data
=> gpu r#"
@group(0) @binding(0) var<storage, read> input: array<f32>;
@group(0) @binding(1) var<storage, read_write> output: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let index = global_id.x;
if (index >= arrayLength(&input)) { return; }
let x = input[index];
output[index] = sin(x * 0.1) * cos(x * 0.2) + sqrt(x + 1.0);
}
"# |data: Vec<f32>| { Ok(data) }
);
let gpu_duration = gpu_start.elapsed();
if cpu_result.iter().all(|r| r.is_ok()) && gpu_result.iter().all(|r| r.is_ok()) {
let cpu_values: Vec<f32> = cpu_result.into_iter().map(|r| r.unwrap()).collect();
let gpu_values: Vec<f32> = gpu_result.into_iter().map(|r| r.unwrap()).collect();
let all_close = cpu_values.iter().zip(gpu_values.iter())
.all(|(cpu, gpu)| (cpu - gpu).abs() < 0.01);
if all_close {
println!("✅ GPU performance test passed!");
println!(" ⏱️ CPU time: {:?}", cpu_duration);
println!(" 🚀 GPU time: {:?}", gpu_duration);
println!(" 📊 Processing 1000 elements with complex math");
if gpu_duration < cpu_duration {
println!(" 🏆 GPU was faster!");
} else {
println!(" 💻 CPU was faster (expected for small datasets)");
}
} else {
println!("⚠️ GPU/CPU results don't match closely enough");
}
} else {
println!("⚠️ GPU performance test skipped (computation failed)");
}
}
#[cfg(feature = "gpu")]
#[tokio::test]
async fn test_gpu_auto_transpilation() {
let input_data = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];
let result = pipex!(
input_data
=> gpu ||| |x| x * x + 1.0 => |x| Ok::<f32, String>(x - 0.5)
);
assert_eq!(result.len(), 5);
if result.iter().all(|r| r.is_ok()) {
let values: Vec<f32> = result.into_iter().map(|r| r.unwrap()).collect();
let expected = vec![1.5f32, 4.5, 9.5, 16.5, 25.5];
for (actual, expected) in values.iter().zip(expected.iter()) {
assert!((actual - expected).abs() < 0.01,
"Expected {}, got {}", expected, actual);
}
println!("✅ GPU Auto-Transpilation Test PASSED!");
println!(" 🎯 Expression: x * x + 1.0");
println!(" 🔄 Rust -> WGSL -> GPU -> Result");
println!(" 📊 Results: {:?}", values);
println!(" 🚀 DREAM SYNTAX WORKS!");
} else {
println!("⚠️ GPU auto-transpilation failed, but CPU fallback worked!");
for (i, result) in result.iter().enumerate() {
match result {
Ok(val) => println!(" ✅ Item {}: {}", i, val),
Err(e) => println!(" ❌ Item {}: {}", i, e),
}
}
}
}
#[cfg(feature = "gpu")]
#[tokio::test]
async fn test_gpu_auto_complex_expressions() {
let input_data = vec![0.5f32, 1.0, 1.5, 2.0];
let result = pipex!(
input_data
=> gpu ||| |x| (x * x + 1.0) * x.sin() + x.cos() * (x + 3.14159) - x.sqrt()
);
assert_eq!(result.len(), 4);
if result.iter().all(|r| r.is_ok()) {
let values: Vec<f32> = result.into_iter().map(|r| r.unwrap()).collect();
let expected: Vec<f32> = vec![0.5f32, 1.0, 1.5, 2.0]
.into_iter()
.map(|x| (x * x + 1.0) * x.sin() + x.cos() * (x + 3.14159) - x.sqrt())
.collect();
for (actual, expected) in values.iter().zip(expected.iter()) {
assert!((actual - expected).abs() < 0.01,
"Expected {}, got {}", expected, actual);
}
println!("✅ GPU Complex Expression Auto-Transpilation PASSED!");
println!(" 🎯 Expression: (x * x + 1.0) * x.sin() + x.cos() * (x + 3.14159) - x.sqrt()");
println!(" 🧮 Features successfully transpiled:");
println!(" - Parentheses grouping: (x * x + 1.0), (x + 3.14159)");
println!(" - Method calls: x.sin(), x.cos(), x.sqrt()");
println!(" - Mixed operations: *, +, -, respecting precedence");
println!(" - Multiple math functions: sin, cos, sqrt");
println!(" - Constants: 1.0, 3.14159 (π approximation)");
println!(" - Complex mathematical formula");
println!(" 📊 Results: {:?}", values);
println!(" 🚀 TRANSPILER HANDLES REAL-WORLD EXPRESSIONS!");
println!(" ⚠️ Current limitation: Nested method chains like (expr).method().method()");
println!(" → This would fallback to CPU automatically!");
} else {
println!("⚠️ Complex expression too advanced, used CPU fallback");
println!(" This demonstrates the automatic fallback system working!");
}
}
}
#[doc(hidden)]
pub use traits::IntoPipelineItem as __InternalIntoPipelineItem;