diff --git a/README.md b/README.md index 704fa6c..17300b5 100644 --- a/README.md +++ b/README.md @@ -84,10 +84,11 @@ async fn main() { // Add source tasks with no dependencies let x = dag.add_task(Value(2)); - let y = dag.add_task(Value(3)); + let y: TaskHandle<_> = dag.add_task(Value(3)).into(); - // Add task that depends on both x and y - let sum = dag.add_task(Add).depends_on((&x, &y)); + // Add task that depends on both x and y. + // Here, y could be reused as a dependency for other tasks, while x could not. + let sum = dag.add_task(Add).depends_on((x, &y)); // Execute with true parallelism dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); diff --git a/benches/basic/execution.rs b/benches/basic/execution.rs index 15ff351..9296422 100644 --- a/benches/basic/execution.rs +++ b/benches/basic/execution.rs @@ -52,7 +52,7 @@ pub fn bench_dag_execution(c: &mut Criterion) { let t0 = dag.add_task(Value(0)); let t1 = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&t0); + .depends_on(t0); let t2 = dag .add_task(task_fn(|x: i32| async move { x + 1 })) .depends_on(t1); diff --git a/benches/comparisons/deep_chain.rs b/benches/comparisons/deep_chain.rs index a5993ab..0cf5b69 100644 --- a/benches/comparisons/deep_chain.rs +++ b/benches/comparisons/deep_chain.rs @@ -3,6 +3,7 @@ //! Long sequential chain: 100 tasks in sequence use criterion::Criterion; +use dagx::TaskHandle; use futures::FutureExt; pub fn bench_deep_chain(c: &mut Criterion) { @@ -17,10 +18,10 @@ pub fn bench_deep_chain(c: &mut Criterion) { let dag = DagRunner::new(); - let first = dag.add_task(task_fn(|_: ()| async { 0 })); + let first: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 0 })).into(); let mut prev = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&first); + .depends_on(first); for i in 2..100 { prev = dag diff --git a/benches/comparisons/diamond_pattern.rs b/benches/comparisons/diamond_pattern.rs index c7c2e52..a0a8ebb 100644 --- a/benches/comparisons/diamond_pattern.rs +++ b/benches/comparisons/diamond_pattern.rs @@ -3,6 +3,7 @@ //! Classic diamond: A → B,C → D use criterion::Criterion; +use dagx::TaskHandle; use futures::FutureExt; pub fn bench_diamond_pattern(c: &mut Criterion) { @@ -17,13 +18,13 @@ pub fn bench_diamond_pattern(c: &mut Criterion) { let dag = DagRunner::new(); - let a = dag.add_task(task_fn(|_: ()| async { 10 })); + let a: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into(); let b = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&a); + .depends_on(a); let c = dag .add_task(task_fn(|x: i32| async move { x + 5 })) - .depends_on(&a); + .depends_on(a); let d = dag .add_task(task_fn(|(x, y): (i32, i32)| async move { x + y })) .depends_on((&b, &c)); diff --git a/benches/comparisons/etl_pipeline.rs b/benches/comparisons/etl_pipeline.rs index 73bcf5e..50a7be6 100644 --- a/benches/comparisons/etl_pipeline.rs +++ b/benches/comparisons/etl_pipeline.rs @@ -27,19 +27,19 @@ pub fn bench_etl_pipeline(c: &mut Criterion) { .add_task(task_fn(|data: Vec| async move { data.into_iter().map(|x| x * 2).collect::>() })) - .depends_on(&source1); + .depends_on(source1); let transform2 = dag .add_task(task_fn(|data: Vec| async move { data.into_iter().map(|x| x * 2).collect::>() })) - .depends_on(&source2); + .depends_on(source2); let transform3 = dag .add_task(task_fn(|data: Vec| async move { data.into_iter().map(|x| x * 2).collect::>() })) - .depends_on(&source3); + .depends_on(source3); // Merge all transformed data let merge = dag diff --git a/benches/comparisons/linear_pipeline.rs b/benches/comparisons/linear_pipeline.rs index 9df20c5..3b1402c 100644 --- a/benches/comparisons/linear_pipeline.rs +++ b/benches/comparisons/linear_pipeline.rs @@ -20,7 +20,7 @@ pub fn bench_linear_pipeline(c: &mut Criterion) { let a = dag.add_task(task_fn(|_: ()| async { 1 })); let b = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&a); + .depends_on(a); let c = dag .add_task(task_fn(|x: i32| async move { x * 2 })) .depends_on(b); diff --git a/benches/comparisons/wide_fanout.rs b/benches/comparisons/wide_fanout.rs index c80f063..25b0079 100644 --- a/benches/comparisons/wide_fanout.rs +++ b/benches/comparisons/wide_fanout.rs @@ -3,6 +3,7 @@ //! One source task feeding 100 dependent tasks use criterion::Criterion; +use dagx::TaskHandle; use futures::FutureExt; pub fn bench_wide_fanout(c: &mut Criterion) { @@ -16,12 +17,12 @@ pub fn bench_wide_fanout(c: &mut Criterion) { use dagx::{task_fn, DagRunner}; let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { 42 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into(); // Create 100 tasks that all depend on source for i in 0..100 { dag.add_task(task_fn(move |x: i32| async move { x + i })) - .depends_on(&source); + .depends_on(source); } dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) diff --git a/benches/patterns/diamond.rs b/benches/patterns/diamond.rs index f129cc1..cf012b9 100644 --- a/benches/patterns/diamond.rs +++ b/benches/patterns/diamond.rs @@ -1,7 +1,7 @@ //! Diamond pattern benchmarks (fan-out then fan-in) use criterion::Criterion; -use dagx::{task_fn, DagRunner}; +use dagx::{task_fn, DagRunner, TaskHandle}; use futures::FutureExt; pub fn bench_diamond(c: &mut Criterion) { @@ -13,14 +13,15 @@ pub fn bench_diamond(c: &mut Criterion) { let dag = DagRunner::new(); for i in 0..50 { - let source = dag.add_task(task_fn(move |_: ()| async move { i })); + let source: TaskHandle<_> = + dag.add_task(task_fn(move |_: ()| async move { i })).into(); let left = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&source); + .depends_on(source); let right = dag .add_task(task_fn(|x: i32| async move { x * 3 })) - .depends_on(&source); + .depends_on(source); dag.add_task(task_fn(|(l, r): (i32, i32)| async move { l + r })) .depends_on((&left, &right)); diff --git a/benches/patterns/fanout.rs b/benches/patterns/fanout.rs index 7a06f4e..71ee6b9 100644 --- a/benches/patterns/fanout.rs +++ b/benches/patterns/fanout.rs @@ -1,7 +1,7 @@ //! Fan-out pattern benchmarks (1 → N dependencies) use criterion::Criterion; -use dagx::{task_fn, DagRunner}; +use dagx::{task_fn, DagRunner, TaskHandle}; use futures::FutureExt; pub fn bench_fanout(c: &mut Criterion) { @@ -12,11 +12,11 @@ pub fn bench_fanout(c: &mut Criterion) { b.iter(|| { rt.block_on(async { let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { 42 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into(); for i in 0..100 { dag.add_task(task_fn(move |x: i32| async move { x + i })) - .depends_on(&source); + .depends_on(source); } dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) @@ -31,17 +31,19 @@ pub fn bench_fanout(c: &mut Criterion) { b.iter(|| { rt.block_on(async { let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { - // Create 1000 strings - framework wraps in Arc automatically - (0..1000).map(|i| format!("Item {}", i)).collect::>() - })); + let source: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { + // Create 1000 strings - framework wraps in Arc automatically + (0..1000).map(|i| format!("Item {}", i)).collect::>() + })) + .into(); for i in 0..100 { dag.add_task(task_fn(move |data: Vec| async move { // Each consumer gets data extracted from Arc data.iter().filter(|s| s.contains(&i.to_string())).count() })) - .depends_on(&source); + .depends_on(source); } dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) @@ -61,12 +63,12 @@ pub fn bench_fanout(c: &mut Criterion) { // Source produces a simple Copy type (usize) // Framework wraps in Arc internally - let source = dag.add_task(task_fn(|_: ()| async { 42usize })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42usize })).into(); // 100 dependents - Arc overhead visible on Copy types for i in 0..100 { dag.add_task(task_fn(move |x: usize| async move { x + i })) - .depends_on(&source); + .depends_on(source); } dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) diff --git a/benches/realistic/config_broadcast.rs b/benches/realistic/config_broadcast.rs index 2bce80f..0be4802 100644 --- a/benches/realistic/config_broadcast.rs +++ b/benches/realistic/config_broadcast.rs @@ -1,7 +1,7 @@ //! Configuration broadcast pattern benchmark - one config shared across many workers use criterion::{BenchmarkId, Criterion}; -use dagx::{task_fn, DagRunner}; +use dagx::{task_fn, DagRunner, TaskHandle}; use futures::FutureExt; use std::collections::HashMap; use std::hint::black_box; @@ -20,18 +20,20 @@ pub fn bench_config_broadcast(c: &mut Criterion) { let dag = DagRunner::new(); // Configuration source - framework wraps HashMap in Arc automatically - let config = dag.add_task(task_fn(|_: ()| async { - HashMap::from([ - ("max_connections".to_string(), "100".to_string()), - ("timeout_ms".to_string(), "5000".to_string()), - ("batch_size".to_string(), "50".to_string()), - ("retry_count".to_string(), "3".to_string()), - ("worker_threads".to_string(), "4".to_string()), - ("buffer_size".to_string(), "8192".to_string()), - ("compression".to_string(), "true".to_string()), - ("log_level".to_string(), "info".to_string()), - ]) - })); + let config: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { + HashMap::from([ + ("max_connections".to_string(), "100".to_string()), + ("timeout_ms".to_string(), "5000".to_string()), + ("batch_size".to_string(), "50".to_string()), + ("retry_count".to_string(), "3".to_string()), + ("worker_threads".to_string(), "4".to_string()), + ("buffer_size".to_string(), "8192".to_string()), + ("compression".to_string(), "true".to_string()), + ("log_level".to_string(), "info".to_string()), + ]) + })) + .into(); // Workers receive and process based on shared config for worker_id in 0..workers { @@ -49,7 +51,7 @@ pub fn bench_config_broadcast(c: &mut Criterion) { // Simulate some computation black_box(worker_id * batch_size + timeout / 100) })) - .depends_on(&config); + .depends_on(config); } dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) diff --git a/benches/realistic/etl.rs b/benches/realistic/etl.rs index d0a39b8..6810787 100644 --- a/benches/realistic/etl.rs +++ b/benches/realistic/etl.rs @@ -1,7 +1,7 @@ //! ETL (Extract, Transform, Load) pipeline benchmark use criterion::{BenchmarkId, Criterion}; -use dagx::{task_fn, DagRunner}; +use dagx::{task_fn, DagRunner, TaskHandle}; use futures::FutureExt; pub fn bench_etl_pipeline(c: &mut Criterion) { @@ -21,7 +21,7 @@ pub fn bench_etl_pipeline(c: &mut Criterion) { let dag = DagRunner::new(); // Extract: Load JSON-like data (framework wraps in Arc automatically) - let extract = dag.add_task(task_fn(move |_: ()| async move { + let extract: TaskHandle<_> = dag.add_task(task_fn(move |_: ()| async move { (0..count) .map(|i| { format!( @@ -32,7 +32,7 @@ pub fn bench_etl_pipeline(c: &mut Criterion) { ) }) .collect::>() - })); + })).into(); // Transform: Three parallel transformations @@ -47,7 +47,7 @@ pub fn bench_etl_pipeline(c: &mut Criterion) { }) .count() })) - .depends_on(&extract); + .depends_on(extract); // T2: Extract scores let scores = dag @@ -60,7 +60,7 @@ pub fn bench_etl_pipeline(c: &mut Criterion) { }) .collect::>() })) - .depends_on(&extract); + .depends_on(extract); // T3: Extract names let names = dag @@ -74,7 +74,7 @@ pub fn bench_etl_pipeline(c: &mut Criterion) { }) .collect::>() })) - .depends_on(&extract); + .depends_on(extract); // Load: Aggregate all transformations dag.add_task(task_fn( diff --git a/benches/realistic/memory_efficiency.rs b/benches/realistic/memory_efficiency.rs index 1d6a548..8670ab6 100644 --- a/benches/realistic/memory_efficiency.rs +++ b/benches/realistic/memory_efficiency.rs @@ -1,7 +1,7 @@ //! Memory efficiency benchmark with large data structures use criterion::{BenchmarkId, Criterion}; -use dagx::{task_fn, DagRunner}; +use dagx::{task_fn, DagRunner, TaskHandle}; use futures::FutureExt; use std::hint::black_box; @@ -19,10 +19,12 @@ pub fn bench_memory_efficiency(c: &mut Criterion) { rt.block_on(async { let dag = DagRunner::new(); - let source = dag.add_task(task_fn(move |_: ()| async move { - // Create MB of data - framework wraps in Arc automatically - vec![0u8; mb * 1024 * 1024] - })); + let source: TaskHandle<_> = dag + .add_task(task_fn(move |_: ()| async move { + // Create MB of data - framework wraps in Arc automatically + vec![0u8; mb * 1024 * 1024] + })) + .into(); // 20 consumers share the data via automatic Arc wrapping for i in 0..20 { @@ -36,7 +38,7 @@ pub fn bench_memory_efficiency(c: &mut Criterion) { .sum(); black_box(sample_sum) })) - .depends_on(&source); + .depends_on(source); } dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) diff --git a/benches/realistic/mixed.rs b/benches/realistic/mixed.rs index c1110c1..445eb41 100644 --- a/benches/realistic/mixed.rs +++ b/benches/realistic/mixed.rs @@ -1,7 +1,7 @@ //! Mixed realistic patterns - fan-out, fan-in, and processing use criterion::Criterion; -use dagx::{task_fn, DagRunner}; +use dagx::{task_fn, DagRunner, TaskHandle}; use futures::FutureExt; pub fn bench_mixed_patterns(c: &mut Criterion) { @@ -13,28 +13,30 @@ pub fn bench_mixed_patterns(c: &mut Criterion) { let dag = DagRunner::new(); // Stage 1: Load data (framework wraps in Arc automatically) - let data = dag.add_task(task_fn(|_: ()| async { - (0..1000) - .map(|i| format!("Record-{:04}", i)) - .collect::>() - })); + let data: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { + (0..1000) + .map(|i| format!("Record-{:04}", i)) + .collect::>() + })) + .into(); // Stage 2: Fan-out for parallel analysis let analysis1 = dag .add_task(task_fn(|d: Vec| async move { d.iter().filter(|s| s.contains("00")).count() })) - .depends_on(&data); + .depends_on(data); let analysis2 = dag .add_task(task_fn(|d: Vec| async move { d.iter().map(|s| s.len()).sum::() })) - .depends_on(&data); + .depends_on(data); let analysis3 = dag .add_task(task_fn(|d: Vec| async move { d.len() })) - .depends_on(&data); + .depends_on(data); // Stage 3: Fan-in to aggregate let summary = dag diff --git a/docs/COMPARISONS.md b/docs/COMPARISONS.md index 0386632..dd7ed7a 100644 --- a/docs/COMPARISONS.md +++ b/docs/COMPARISONS.md @@ -18,7 +18,7 @@ impl Add { async fn run(a: &i32, b: &i32) -> i32 { a + b } } let dag = DagRunner::new(); let x = dag.add_task(Value(2)); let y = dag.add_task(Value(3)); -let sum = dag.add_task(Add).depends_on((&x, &y)); +let sum = dag.add_task(Add).depends_on((x, y)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; ``` diff --git a/examples/01_basic.rs b/examples/01_basic.rs index 4034700..6065b42 100644 --- a/examples/01_basic.rs +++ b/examples/01_basic.rs @@ -83,8 +83,8 @@ async fn main() { // Step 4: Add source tasks (tasks with no dependencies) // // add_task() returns a TaskHandle where T is the task's output type - let x = dag.add_task(Value::new(2)); // TaskHandle - let y = dag.add_task(Value::new(3)); // TaskHandle + let x = dag.add_task(Value::new(2)).into(); // TaskHandle + let y = dag.add_task(Value::new(3)).into(); // TaskHandle // Step 5: Add a task with dependencies // diff --git a/examples/02_fan_out.rs b/examples/02_fan_out.rs index 2fb6aad..d4f4723 100644 --- a/examples/02_fan_out.rs +++ b/examples/02_fan_out.rs @@ -55,7 +55,7 @@ //! Squared: 100 //! ``` -use dagx::{task, DagRunner}; +use dagx::{task, DagRunner, TaskHandle}; use futures::FutureExt; // Source task with a value field @@ -131,13 +131,13 @@ async fn main() { let dag = DagRunner::new(); // Single source task - constructed with ::new() - let source = dag.add_task(Source::new(10)); + let source: TaskHandle<_> = dag.add_task(Source::new(10)).into(); // Multiple downstream tasks consuming the same value // Each constructed differently to show flexibility - let plus_one = dag.add_task(AddOffset::new(1)).depends_on(&source); - let times_two = dag.add_task(Multiply::new(2)).depends_on(&source); - let squared = dag.add_task(Power { exponent: 2 }).depends_on(&source); + let plus_one = dag.add_task(AddOffset::new(1)).depends_on(source); + let times_two = dag.add_task(Multiply::new(2)).depends_on(source); + let squared = dag.add_task(Power { exponent: 2 }).depends_on(source); // Run the DAG println!("Running fan-out DAG...\n"); diff --git a/examples/03_fan_in.rs b/examples/03_fan_in.rs index d5fe8f4..b0ae2cf 100644 --- a/examples/03_fan_in.rs +++ b/examples/03_fan_in.rs @@ -130,7 +130,7 @@ async fn main() { // Single downstream task consuming all values let profile = dag .add_task(BuildProfile) - .depends_on((&name, &age, &city, &active)); + .depends_on((name, age, city, active)); // Run the DAG println!("Running fan-in DAG...\n"); diff --git a/examples/04_parallel_computation.rs b/examples/04_parallel_computation.rs index 7329591..abbca1f 100644 --- a/examples/04_parallel_computation.rs +++ b/examples/04_parallel_computation.rs @@ -123,9 +123,7 @@ async fn main() -> DagResult<()> { let sum3 = dag.add_task(ComputeSum::new(501, 751, WORK_DELAY)); let sum4 = dag.add_task(ComputeSum::new(751, 1001, WORK_DELAY)); - let total = dag - .add_task(Aggregate) - .depends_on((&sum1, &sum2, &sum3, &sum4)); + let total = dag.add_task(Aggregate).depends_on((sum1, sum2, sum3, sum4)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; diff --git a/examples/circuit_breaker.rs b/examples/circuit_breaker.rs index 52fcecf..b2c5f4c 100644 --- a/examples/circuit_breaker.rs +++ b/examples/circuit_breaker.rs @@ -448,7 +448,7 @@ async fn main() { let fallback5 = dag .add_task(FallbackService::new("ServiceCall-5")) - .depends_on(&call5); + .depends_on(call5); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/examples/complex_dag.rs b/examples/complex_dag.rs index 12b071c..50810ec 100644 --- a/examples/complex_dag.rs +++ b/examples/complex_dag.rs @@ -184,8 +184,8 @@ async fn main() -> DagResult<()> { let source_b = dag.add_task(LoadData::new("B")); // Transform: Process each source (parallel) - let transform_a = dag.add_task(Transform::new(2)).depends_on(&source_a); - let transform_b = dag.add_task(Transform::new(3)).depends_on(&source_b); + let transform_a = dag.add_task(Transform::new(2)).depends_on(source_a); + let transform_b = dag.add_task(Transform::new(3)).depends_on(source_b); // Combine: Merge the transformed datasets let combined = dag diff --git a/examples/conditional_workflow.rs b/examples/conditional_workflow.rs index c87151f..f9aacfe 100644 --- a/examples/conditional_workflow.rs +++ b/examples/conditional_workflow.rs @@ -128,9 +128,9 @@ async fn main() -> DagResult<()> { let processed3 = dag.add_task(ValidateAndDouble::new(20)); // Valid: 40 // Categorize each result (also parallel, threshold = 25) - let cat1 = dag.add_task(Categorize::new(25)).depends_on(&processed1); // 20 < 25 = "low" - let cat2 = dag.add_task(Categorize::new(25)).depends_on(&processed2); // 0 = "invalid" - let cat3 = dag.add_task(Categorize::new(25)).depends_on(&processed3); // 40 >= 25 = "high" + let cat1 = dag.add_task(Categorize::new(25)).depends_on(processed1); // 20 < 25 = "low" + let cat2 = dag.add_task(Categorize::new(25)).depends_on(processed2); // 0 = "invalid" + let cat3 = dag.add_task(Categorize::new(25)).depends_on(processed3); // 40 >= 25 = "high" // Combine results let summary = dag diff --git a/examples/custom_types.rs b/examples/custom_types.rs index e8ff188..60f8198 100644 --- a/examples/custom_types.rs +++ b/examples/custom_types.rs @@ -36,7 +36,7 @@ //! Validation: Alice is valid (age 30 >= 18) //! ``` -use dagx::{task, DagRunner}; +use dagx::{task, DagRunner, TaskHandle}; use futures::FutureExt; // Custom type - just derive Clone! @@ -97,15 +97,17 @@ async fn main() { let dag = DagRunner::new(); // Create a task that produces a custom User type - let user_task = dag.add_task(CreateUser { - name: "Alice".to_string(), - age: 30, - }); + let user_task: TaskHandle<_> = dag + .add_task(CreateUser { + name: "Alice".to_string(), + age: 30, + }) + .into(); // Two different tasks consume the same custom User type // dagx automatically handles Arc wrapping, so both tasks get &User - let greeting = dag.add_task(GreetUser).depends_on(&user_task); - let validation = dag.add_task(ValidateUser).depends_on(&user_task); + let greeting = dag.add_task(GreetUser).depends_on(user_task); + let validation = dag.add_task(ValidateUser).depends_on(user_task); // Execute the DAG dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) diff --git a/examples/data_pipeline.rs b/examples/data_pipeline.rs index afc6187..75b7d9d 100644 --- a/examples/data_pipeline.rs +++ b/examples/data_pipeline.rs @@ -191,15 +191,15 @@ async fn main() { // Stage 2: Data transformation (with stateful tasks) let transformed_1 = dag .add_task(DataTransformer::new(1.5)) - .depends_on(&raw_value_1); + .depends_on(raw_value_1); let transformed_2 = dag .add_task(DataTransformer::new(2.0)) - .depends_on(&raw_value_2); + .depends_on(raw_value_2); let transformed_3 = dag .add_task(DataTransformer::new(0.5)) - .depends_on(&raw_value_3); + .depends_on(raw_value_3); // Stage 3: Statistical analysis (parallel operations on transformed data) let sum = dag diff --git a/examples/debug_tracing.rs b/examples/debug_tracing.rs index cf9a416..9525f5c 100644 --- a/examples/debug_tracing.rs +++ b/examples/debug_tracing.rs @@ -398,7 +398,7 @@ async fn main() { // Aggregate traces let summary = dag .add_task(TraceAggregator::new(correlation_id)) - .depends_on((&inventory, &payment, &shipping)); + .depends_on((inventory, payment, shipping)); // Run the DAG dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) diff --git a/examples/error_handling.rs b/examples/error_handling.rs index 766c511..c6aa7ab 100644 --- a/examples/error_handling.rs +++ b/examples/error_handling.rs @@ -214,7 +214,7 @@ async fn main() { let input = dag.add_task(StringSource("42")); - let parsed = dag.add_task(ParseInt).depends_on(&input); + let parsed = dag.add_task(ParseInt).depends_on(input); let validated = dag .add_task(ValidateRange { min: 0, max: 100 }) @@ -240,7 +240,7 @@ async fn main() { let input = dag.add_task(StringSource("not a number")); - let parsed = dag.add_task(ParseInt).depends_on(&input); + let parsed = dag.add_task(ParseInt).depends_on(input); let validated = dag .add_task(ValidateRange { min: 0, max: 100 }) @@ -266,7 +266,7 @@ async fn main() { let input = dag.add_task(StringSource("150")); - let parsed = dag.add_task(ParseInt).depends_on(&input); + let parsed = dag.add_task(ParseInt).depends_on(input); let validated = dag .add_task(ValidateRange { min: 0, max: 100 }) @@ -292,7 +292,7 @@ async fn main() { let input = dag.add_task(StringSource("invalid")); - let parsed = dag.add_task(ParseInt).depends_on(&input); + let parsed = dag.add_task(ParseInt).depends_on(input); let with_fallback = dag .add_task(WithFallback { fallback: 0 }) diff --git a/examples/large_dag.rs b/examples/large_dag.rs index 069caba..d8478cc 100644 --- a/examples/large_dag.rs +++ b/examples/large_dag.rs @@ -192,7 +192,7 @@ async fn main() { // Verify a few results let sum: i32 = tasks - .iter() + .into_iter() .take(10) .map(|t| dag.get(t).unwrap()) .fold(0i32, |acc, x| acc.wrapping_add(x)); @@ -208,7 +208,7 @@ async fn main() { // Create a deep chain by combining adjacent task pairs let tasks: Vec<_> = (0..100) - .map(|i| dag.add_task(Compute { value: i })) + .map(|i| dag.add_task(Compute { value: i }).into()) .collect(); let mut chain_tasks = vec![]; for i in 0..99 { @@ -246,7 +246,7 @@ async fn main() { // Process all levels reducing by combining pairs let mut level = 0; let mut layer: Vec> = - current_level.iter().map(|b| b.into()).collect(); + current_level.into_iter().map(|b| b.into()).collect(); while layer.len() > 1 { level += 1; @@ -291,7 +291,7 @@ async fn main() { // Layer 1: 50 source tasks let sources: Vec<_> = (0..50) - .map(|i| dag.add_task(Compute { value: i })) + .map(|i| dag.add_task(Compute { value: i }).into()) .collect(); // Layer 2: 50 tasks, each depends on all sources @@ -361,11 +361,11 @@ async fn main() { // Verify results are accessible let i32_sum: i32 = small_tasks - .iter() + .into_iter() .map(|t| dag.get(t).unwrap()) .fold(0i32, |acc, x| acc.wrapping_add(x)); let string_count = string_tasks - .iter() + .into_iter() .map(|t| dag.get(t).unwrap().len()) .sum::(); diff --git a/examples/parallelism_proof.rs b/examples/parallelism_proof.rs index a9d5ba7..97e7964 100644 --- a/examples/parallelism_proof.rs +++ b/examples/parallelism_proof.rs @@ -93,7 +93,7 @@ async fn main() { let elapsed = start.elapsed(); // Verify all tasks completed correctly - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), i as u32); } diff --git a/examples/timeout.rs b/examples/timeout.rs index 78f8198..6e9f9d5 100644 --- a/examples/timeout.rs +++ b/examples/timeout.rs @@ -98,7 +98,7 @@ //! === Timeout Example Complete === //! ``` -use dagx::{task, DagRunner}; +use dagx::{task, DagRunner, TaskHandle}; use futures::FutureExt; use tokio::time::{sleep, timeout, Duration}; @@ -196,7 +196,7 @@ async fn main() { timeout_ms: 200, }); - let processed = dag.add_task(ProcessResult).depends_on(&timed); + let processed = dag.add_task(ProcessResult).depends_on(timed); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -241,13 +241,15 @@ async fn main() { { let dag = DagRunner::new(); - let source = dag.add_task(TaskWithTimeout { - work_duration_ms: 500, - timeout_ms: 100, - }); + let source: TaskHandle<_> = dag + .add_task(TaskWithTimeout { + work_duration_ms: 500, + timeout_ms: 100, + }) + .into(); - let processed1 = dag.add_task(ProcessResult).depends_on(&source); - let processed2 = dag.add_task(ProcessResult).depends_on(&source); + let processed1 = dag.add_task(ProcessResult).depends_on(source); + let processed2 = dag.add_task(ProcessResult).depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/examples/tracing_example.rs b/examples/tracing_example.rs index 6eaec33..96cb5b1 100644 --- a/examples/tracing_example.rs +++ b/examples/tracing_example.rs @@ -87,7 +87,7 @@ async fn main() { let dag = DagRunner::new(); // Layer 0: Source - let source = dag.add_task(Value(10)); + let source = dag.add_task(Value(10)).into(); // Layer 1: Two parallel computations let left = dag.add_task(Add).depends_on((&source, &source)); @@ -112,7 +112,7 @@ async fn main() { // Create a linear chain - each layer has only one task // This should trigger inline execution optimization - let a = dag.add_task(Value(1)); + let a = dag.add_task(Value(1)).into(); let b = dag.add_task(Add).depends_on((&a, &a)); let c = dag.add_task(Multiply).depends_on((&b, &b)); let d = dag.add_task(Add).depends_on((&c, &c)); @@ -132,10 +132,10 @@ async fn main() { let dag = DagRunner::new(); // Layer 0: Multiple sources - let v1 = dag.add_task(Value(1)); - let v2 = dag.add_task(Value(2)); - let v3 = dag.add_task(Value(3)); - let v4 = dag.add_task(Value(4)); + let v1 = dag.add_task(Value(1)).into(); + let v2 = dag.add_task(Value(2)).into(); + let v3 = dag.add_task(Value(3)).into(); + let v4 = dag.add_task(Value(4)).into(); // Layer 1: Multiple parallel computations let sum12 = dag.add_task(Add).depends_on((&v1, &v2)); diff --git a/src/builder.rs b/src/builder.rs index 8818db3..ab339ec 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -63,11 +63,11 @@ impl IsUnitType for () {} /// let b = dag.add_task(Multiplier::new(2)); /// // b is TaskBuilder<_, Pending> until we call depends_on() /// -/// let b = b.depends_on(&a); +/// let b = b.depends_on(a); /// // Now b is a TaskHandle /// /// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); -/// assert_eq!(dag.get(&b).unwrap(), 20); +/// assert_eq!(dag.get(b).unwrap(), 20); /// # }; /// ``` pub struct TaskBuilder<'a, Tk: Task, Deps> { @@ -118,14 +118,14 @@ impl<'a, Tk: Task, Deps> TaskBuilder<'a, Tk, Deps> { /// # async { /// let dag = DagRunner::new(); /// - /// let x = dag.add_task(Value(2)); + /// let x = dag.add_task(Value(2)).into(); /// let y = dag.add_task(Value(3)); /// /// // Single dependency /// let double = dag.add_task(Scale(2)).depends_on(&x); /// /// // Multiple dependencies: tuple form - /// let sum = dag.add_task(Add).depends_on((&x, &y)); + /// let sum = dag.add_task(Add).depends_on((&x, y)); /// /// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); /// # }; @@ -169,7 +169,3 @@ impl<'a, Tk: Task, Deps> TaskBuilder<'a, Tk, Deps> { #[cfg(test)] mod tests; - -// Note: We cannot safely implement AsRef> for TaskBuilder -// because Handle is Copy and returning a reference to a temporary would be unsound. -// Instead, users should use From/Into conversions or call .into() explicitly. diff --git a/src/builder/tests.rs b/src/builder/tests.rs index 7aef57f..c9aca0d 100644 --- a/src/builder/tests.rs +++ b/src/builder/tests.rs @@ -76,7 +76,7 @@ fn test_task_builder_depends_on_returns_handle() { let dag = DagRunner::new(); let source = dag.add_task(TestTask { value: 10 }); - let dependent = dag.add_task(TestTaskWithInput).depends_on(&source); + let dependent = dag.add_task(TestTaskWithInput).depends_on(source); // depends_on should return a TaskHandle let _handle: TaskHandle = dependent; @@ -87,12 +87,12 @@ fn test_task_builder_chain() { let dag = DagRunner::new(); // Test chaining multiple tasks - let t1 = dag.add_task(TestTask { value: 1 }); - let t2 = dag.add_task(TestTaskWithInput).depends_on(&t1); + let t1 = dag.add_task(TestTask { value: 1 }).into(); + let t2 = dag.add_task(TestTaskWithInput).depends_on(t1); let t3 = dag.add_task(TestTaskWithInput).depends_on(t2); // All should return TaskHandles - let _: TaskHandle = t1.into(); + let _: TaskHandle = t1; let _: TaskHandle = t2; let _: TaskHandle = t3; } @@ -115,7 +115,7 @@ fn test_multiple_dependencies() { let b = dag.add_task(TestTask { value: 20 }); // Test multiple dependencies - let sum = dag.add_task(AddTask).depends_on((&a, &b)); + let sum = dag.add_task(AddTask).depends_on((a, b)); // Should return a TaskHandle let _: TaskHandle = sum; diff --git a/src/deps.rs b/src/deps.rs index d2497ce..5d70b36 100644 --- a/src/deps.rs +++ b/src/deps.rs @@ -11,52 +11,60 @@ use crate::builder::TaskBuilder; use crate::task::Task; use crate::types::{NodeId, TaskHandle}; +trait IntoNodeRef { + type Output; + fn into_node_ref(self) -> NodeId; +} + +impl IntoNodeRef for &TaskHandle { + type Output = T; + fn into_node_ref(self) -> NodeId { + self.id + } +} + +impl IntoNodeRef for TaskHandle { + type Output = T; + fn into_node_ref(self) -> NodeId { + self.id + } +} + +impl<'runner, Tk: Task, Deps> IntoNodeRef for TaskBuilder<'runner, Tk, Deps> { + type Output = Tk::Output; + + fn into_node_ref(self) -> NodeId { + self.id + } +} + pub(crate) trait DepsTuple { - fn to_node_ids(&self) -> Vec; + fn to_node_ids(self) -> Vec; } // Implementation for unit (no dependencies) impl DepsTuple<()> for () { - fn to_node_ids(&self) -> Vec { + fn to_node_ids(self) -> Vec { Vec::new() } } // Implementation for single dependency (all forms) -impl DepsTuple for &TaskHandle { - fn to_node_ids(&self) -> Vec { - vec![self.id] +impl DepsTuple for T +where + T: IntoNodeRef, +{ + fn to_node_ids(self) -> Vec { + vec![self.into_node_ref()] } } -impl DepsTuple for TaskHandle { - fn to_node_ids(&self) -> Vec { - vec![self.id] - } -} - -impl DepsTuple for (&TaskHandle,) { - fn to_node_ids(&self) -> Vec { - vec![self.0.id] - } -} - -impl DepsTuple for (TaskHandle,) { - fn to_node_ids(&self) -> Vec { - vec![self.0.id] - } -} - -// Support for &TaskBuilder -impl<'a, Tk: Task, Deps> DepsTuple for &TaskBuilder<'a, Tk, Deps> { - fn to_node_ids(&self) -> Vec { - vec![self.id] - } -} - -impl<'a, Tk: Task, Deps> DepsTuple for (&TaskBuilder<'a, Tk, Deps>,) { - fn to_node_ids(&self) -> Vec { - vec![self.0.id] +impl DepsTuple for (T,) +where + T: IntoNodeRef, +{ + fn to_node_ids(self) -> Vec { + vec![self.0.into_node_ref()] } } @@ -65,10 +73,6 @@ impl<'a, Tk: Task, Deps> DepsTuple for (&TaskBuilder<'a, Tk, Deps>,) /// This macro exists because Rust lacks variadic generics - we need separate implementations /// for each tuple size. /// -/// For each tuple size, generates two implementations: -/// - `(&TaskHandle, &TaskHandle, ...)` → `DepsTuple<(A, B, ...)>` -/// - `(&TaskBuilder, &TaskBuilder, ...)` → `DepsTuple<(TkA::Output, TkB::Output, ...)>` -/// /// This allows flexible dependency specification: /// ```ignore /// // Using handles @@ -78,37 +82,27 @@ impl<'a, Tk: Task, Deps> DepsTuple for (&TaskBuilder<'a, Tk, Deps>,) /// task.depends_on((&dag.add_task(TaskA), &dag.add_task(TaskB))) /// ``` macro_rules! impl_deps_tuple { - ($($T:ident : $Tk:ident : $D:ident),+) => { - // For &TaskHandle tuples - impl<$($T),+> DepsTuple<($($T,)+)> for ($(&TaskHandle<$T>,)+) { + ($($T:ident),+) => { + // For tuples of any combination of &TaskHandle, TaskHandle, and TaskBuilder + impl<$($T: IntoNodeRef),+> DepsTuple<($($T::Output,)+)> for ($($T,)+) { #[allow(non_snake_case)] - fn to_node_ids(&self) -> Vec { + fn to_node_ids(self) -> Vec { let ($($T,)+) = self; - vec![$($T.id,)+] - } - } - - // For &TaskBuilder tuples - impl<'a, $($Tk: Task, $D),+> DepsTuple<($($Tk::Output,)+)> for ($(&TaskBuilder<'a, $Tk, $D>,)+) { - #[allow(non_snake_case)] - fn to_node_ids(&self) -> Vec { - let ($($T,)+) = self; - vec![$($T.id,)+] + vec![$($T.into_node_ref(),)+] } } }; } // Generate DepsTuple implementations for tuples of size 2-8. -// Each invocation generates 2 implementations (TaskHandle refs and TaskBuilder refs). // Supporting up to 8 elements covers the vast majority of use cases. -impl_deps_tuple!(A:TkA:DA, B:TkB:DB); -impl_deps_tuple!(A:TkA:DA, B:TkB:DB, C:TkC:DC); -impl_deps_tuple!(A:TkA:DA, B:TkB:DB, C:TkC:DC, D:TkD:DD); -impl_deps_tuple!(A:TkA:DA, B:TkB:DB, C:TkC:DC, D:TkD:DD, E:TkE:DE); -impl_deps_tuple!(A:TkA:DA, B:TkB:DB, C:TkC:DC, D:TkD:DD, E:TkE:DE, F:TkF:DF); -impl_deps_tuple!(A:TkA:DA, B:TkB:DB, C:TkC:DC, D:TkD:DD, E:TkE:DE, F:TkF:DF, G:TkG:DG); -impl_deps_tuple!(A:TkA:DA, B:TkB:DB, C:TkC:DC, D:TkD:DD, E:TkE:DE, F:TkF:DF, G:TkG:DG, H:TkH:DH); +impl_deps_tuple!(T1, T2); +impl_deps_tuple!(T1, T2, T3); +impl_deps_tuple!(T1, T2, T3, T4); +impl_deps_tuple!(T1, T2, T3, T4, T5); +impl_deps_tuple!(T1, T2, T3, T4, T5, T6); +impl_deps_tuple!(T1, T2, T3, T4, T5, T6, T7); +impl_deps_tuple!(T1, T2, T3, T4, T5, T6, T7, T8); #[cfg(test)] mod tests; diff --git a/src/deps/tests.rs b/src/deps/tests.rs index 60ae5d0..a22e328 100644 --- a/src/deps/tests.rs +++ b/src/deps/tests.rs @@ -91,12 +91,13 @@ fn test_deps_tuple_task_builder_ref() { // Test lines 51-55 in deps.rs - &TaskBuilder let dag = DagRunner::new(); let builder = dag.add_task(TestTask { value: 42 }); + let builder_id = builder.id; // We need to test the DepsTuple implementation directly // The builder has an id field we can check - let node_ids = (&builder).to_node_ids(); + let node_ids = builder.to_node_ids(); assert_eq!(node_ids.len(), 1); - assert_eq!(node_ids[0], builder.id); + assert_eq!(node_ids[0], builder_id); } #[test] @@ -104,10 +105,11 @@ fn test_deps_tuple_task_builder_tuple() { // Test lines 57-61 in deps.rs - (&TaskBuilder,) let dag = DagRunner::new(); let builder = dag.add_task(TestTask { value: 100 }); + let builder_id = builder.id; - let node_ids = (&builder,).to_node_ids(); + let node_ids = (builder,).to_node_ids(); assert_eq!(node_ids.len(), 1); - assert_eq!(node_ids[0], builder.id); + assert_eq!(node_ids[0], builder_id); } #[test] @@ -145,21 +147,18 @@ fn test_deps_tuple_multiple_builders() { // Test macro-generated implementations for multiple builders let dag = DagRunner::new(); let builder1 = dag.add_task(TestTask { value: 10 }); + let builder1_id = builder1.id; let builder2 = dag.add_task(TestTask { value: 20 }); + let builder2_id = builder2.id; let builder3 = dag.add_task(TestTask { value: 30 }); - - // Test 2-tuple of builders - let node_ids = (&builder1, &builder2).to_node_ids(); - assert_eq!(node_ids.len(), 2); - assert_eq!(node_ids[0], builder1.id); - assert_eq!(node_ids[1], builder2.id); + let builder3_id = builder3.id; // Test 3-tuple of builders - let node_ids = (&builder1, &builder2, &builder3).to_node_ids(); + let node_ids = (builder1, builder2, builder3).to_node_ids(); assert_eq!(node_ids.len(), 3); - assert_eq!(node_ids[0], builder1.id); - assert_eq!(node_ids[1], builder2.id); - assert_eq!(node_ids[2], builder3.id); + assert_eq!(node_ids[0], builder1_id); + assert_eq!(node_ids[1], builder2_id); + assert_eq!(node_ids[2], builder3_id); } #[test] diff --git a/src/lib.rs b/src/lib.rs index 73b5f83..938ecdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ //! # Quick Start //! //! ```no_run -//! use dagx::{task, DagRunner, Task}; +//! use dagx::{task, DagRunner, Task, TaskHandle}; //! use futures::FutureExt; // for FutureExt::map //! //! // Source task with read-only state (tuple struct) @@ -47,10 +47,10 @@ //! //! // Add source tasks //! let x = dag.add_task(Value(2)); -//! let y = dag.add_task(Value(3)); +//! let y: TaskHandle<_> = dag.add_task(Value(3)).into(); // Allows y to be reused as a dependency //! //! // Add task with dependencies -//! let sum = dag.add_task(Add).depends_on((&x, &y)); +//! let sum = dag.add_task(Add).depends_on((x, &y)); //! //! // Execute and retrieve results //! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); @@ -255,7 +255,7 @@ //! # async { //! # let dag = DagRunner::new(); //! # let source = dag.add_task(Value(42)); -//! let doubled = dag.add_task(Double).depends_on(&source); +//! let doubled = dag.add_task(Double).depends_on(source); //! # }; //! ``` //! @@ -279,7 +279,7 @@ //! # let dag = DagRunner::new(); //! # let x = dag.add_task(Value(2)); //! # let y = dag.add_task(Value(3)); -//! let sum = dag.add_task(Add).depends_on((&x, &y)); +//! let sum = dag.add_task(Add).depends_on((x, y)); //! # }; //! ``` //! @@ -320,7 +320,7 @@ //! # async { //! let dag = DagRunner::new(); //! -//! let base = dag.add_task(Value(10)); +//! let base = dag.add_task(Value(10)).into(); //! let plus1 = dag.add_task(Add(1)).depends_on(&base); //! let times2 = dag.add_task(Scale(2)).depends_on(&base); //! @@ -379,7 +379,7 @@ //! let name = dag.add_task(Name("Alice".to_string())); //! let age = dag.add_task(Age(30)); //! let active = dag.add_task(Active(true)); -//! let result = dag.add_task(FormatUser).depends_on((&name, &age, &active)); +//! let result = dag.add_task(FormatUser).depends_on((name, age, active)); //! //! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); //! @@ -424,12 +424,12 @@ //! //! // Layer 1: Sources //! let x = dag.add_task(Value(2)); -//! let y = dag.add_task(Value(3)); +//! let y = dag.add_task(Value(3)).into(); //! let z = dag.add_task(Value(5)); //! //! // Layer 2: Intermediate computations -//! let sum_xy = dag.add_task(Add).depends_on((&x, &y)); // 2 + 3 = 5 -//! let prod_yz = dag.add_task(Multiply).depends_on((&y, &z)); // 3 * 5 = 15 +//! let sum_xy = dag.add_task(Add).depends_on((x, &y)); // 2 + 3 = 5 +//! let prod_yz = dag.add_task(Multiply).depends_on((&y, z)); // 3 * 5 = 15 //! //! // Layer 3: Final result //! let total = dag.add_task(Add).depends_on((&sum_xy, &prod_yz)); // 5 + 15 = 20 @@ -476,7 +476,7 @@ //! let dag = DagRunner::new(); //! //! let user = dag.add_task(CreateUser); -//! let formatted = dag.add_task(FormatUser).depends_on(&user); +//! let formatted = dag.add_task(FormatUser).depends_on(user); //! //! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); //! @@ -656,7 +656,7 @@ //! //! # async { //! let dag = DagRunner::new(); -//! let data = dag.add_task(FetchData); +//! let data = dag.add_task(FetchData).into(); //! //! // All three tasks get efficient Arc-wrapped sharing automatically //! let task1 = dag.add_task(ProcessData).depends_on(&data); diff --git a/src/runner.rs b/src/runner.rs index 1a30457..faa9da9 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -83,7 +83,7 @@ impl<'a> Drop for RunGuard<'a> { /// // Construct instances using ::new() pattern /// let x = dag.add_task(LoadValue::new(2)); /// let y = dag.add_task(LoadValue::new(3)); -/// let sum = dag.add_task(Add).depends_on((&x, &y)); +/// let sum = dag.add_task(Add).depends_on((x, y)); /// /// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); /// @@ -190,10 +190,10 @@ impl DagRunner { /// let base = dag.add_task(LoadValue::new(10)); /// /// // Construct task with offset of 1 - /// let inc = dag.add_task(AddOffset::new(1)).depends_on(&base); + /// let inc = dag.add_task(AddOffset::new(1)).depends_on(base); /// /// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); - /// assert_eq!(dag.get(&inc).unwrap(), 11); + /// assert_eq!(dag.get(inc).unwrap(), 11); /// # }; /// ``` pub fn add_task(&self, task: Tk) -> TaskBuilder<'_, Tk, Pending> @@ -278,7 +278,7 @@ impl DagRunner { /// /// let a = dag.add_task(Value(1)); /// let b = dag.add_task(Value(2)); - /// let sum = dag.add_task(Add).depends_on((&a, &b)); + /// let sum = dag.add_task(Add).depends_on((a, b)); /// /// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); // Executes all tasks /// # }; diff --git a/src/runner/tests.rs b/src/runner/tests.rs index 51fd191..4ffae00 100644 --- a/src/runner/tests.rs +++ b/src/runner/tests.rs @@ -190,16 +190,16 @@ async fn test_multiple_get_calls() { init_tracing(); // Test that get() can be called multiple times for the same handle let dag = DagRunner::new(); - let handle = dag.add_task(TestTask { value: 100 }); + let handle: TaskHandle<_> = dag.add_task(TestTask { value: 100 }).into(); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await .unwrap(); // Multiple get calls should all return the same value - let result1 = dag.get(&handle).unwrap(); - let result2 = dag.get(&handle).unwrap(); - let result3 = dag.get(&handle).unwrap(); + let result1 = dag.get(handle).unwrap(); + let result2 = dag.get(handle).unwrap(); + let result3 = dag.get(handle).unwrap(); assert_eq!(result1, 100); assert_eq!(result2, 100); @@ -264,11 +264,11 @@ async fn test_task_panic_in_multi_task_layer() { } let dag = DagRunner::new(); - let source = dag.add_task(Source); + let source: TaskHandle<_> = dag.add_task(Source).into(); // Create two tasks in the same layer - one panics, one doesn't - let _panic_task = dag.add_task(PanicTask).depends_on(&source); - let _good_task = dag.add_task(GoodTask).depends_on(&source); + let _panic_task = dag.add_task(PanicTask).depends_on(source); + let _good_task = dag.add_task(GoodTask).depends_on(source); // Run the DAG - the panic should be caught let result = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; diff --git a/src/types.rs b/src/types.rs index 70a1467..4c6b115 100644 --- a/src/types.rs +++ b/src/types.rs @@ -75,18 +75,6 @@ where } } -impl<'a, Tk: Task, Deps> From<&TaskBuilder<'a, Tk, Deps>> for TaskHandle -where - Tk::Input: IsUnitType, -{ - fn from(node: &TaskBuilder<'a, Tk, Deps>) -> Self { - TaskHandle { - id: node.id, - _phantom: std::marker::PhantomData, - } - } -} - // TaskHandle can be converted from &TaskHandle (for .get() calls) impl From<&TaskHandle> for TaskHandle { fn from(handle: &TaskHandle) -> Self { diff --git a/src/types/tests.rs b/src/types/tests.rs index 2a63044..862121c 100644 --- a/src/types/tests.rs +++ b/src/types/tests.rs @@ -147,25 +147,3 @@ fn test_task_handle_ref_from_conversion() { assert_eq!(converted.id.0, 123); assert_eq!(handle.id, converted.id); } - -#[test] -fn test_task_builder_ref_from_conversion() { - use crate::runner::DagRunner; - - // Test From<&TaskBuilder> for TaskHandle (line 77-87, specifically line 83) - struct SimpleTask2; - #[crate::task] - impl SimpleTask2 { - async fn run(&self) -> String { - "test".to_string() - } - } - - let dag = DagRunner::new(); - let builder = dag.add_task(SimpleTask2); - let builder_id = builder.id; - - // This conversion uses the From<&TaskBuilder> implementation - let handle: TaskHandle = (&builder).into(); - assert_eq!(handle.id, builder_id); -} diff --git a/tests/arc_tests.rs b/tests/arc_tests.rs index 7ea5420..95b360e 100644 --- a/tests/arc_tests.rs +++ b/tests/arc_tests.rs @@ -9,7 +9,7 @@ //! //! These tests serve as both validation and documentation for proper Arc usage. -use dagx::{task, DagRunner}; +use dagx::{task, DagRunner, TaskHandle}; use futures::FutureExt; use std::collections::{HashMap, HashSet}; use std::sync::Arc; @@ -42,7 +42,7 @@ async fn test_arc_basic_pipeline() { let dag = DagRunner::new(); let producer = dag.add_task(Producer); - let consumer = dag.add_task(Consumer).depends_on(&producer); + let consumer = dag.add_task(Consumer).depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -98,7 +98,7 @@ async fn test_arc_with_primitives() { let bool_prod = dag.add_task(BoolProducer); let consumer = dag .add_task(AllConsumer) - .depends_on((&i32_prod, &f64_prod, &bool_prod)); + .depends_on((i32_prod, f64_prod, bool_prod)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -172,7 +172,7 @@ async fn test_arc_with_collections() { let set_prod = dag.add_task(SetProducer); let consumer = dag .add_task(CollectionConsumer) - .depends_on((&vec_prod, &map_prod, &set_prod)); + .depends_on((vec_prod, map_prod, set_prod)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -240,10 +240,10 @@ async fn test_arc_with_custom_structs() { } let dag = DagRunner::new(); - let person_prod = dag.add_task(PersonProducer); - let name_ext = dag.add_task(NameExtractor).depends_on(&person_prod); - let age_ext = dag.add_task(AgeExtractor).depends_on(&person_prod); - let email_ext = dag.add_task(EmailCountExtractor).depends_on(&person_prod); + let person_prod: TaskHandle<_> = dag.add_task(PersonProducer).into(); + let name_ext = dag.add_task(NameExtractor).depends_on(person_prod); + let age_ext = dag.add_task(AgeExtractor).depends_on(person_prod); + let email_ext = dag.add_task(EmailCountExtractor).depends_on(person_prod); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -306,10 +306,10 @@ async fn test_arc_fan_out_three_consumers() { } let dag = DagRunner::new(); - let producer = dag.add_task(DataProducer); - let c1 = dag.add_task(CountConsumer).depends_on(&producer); - let c2 = dag.add_task(FirstConsumer).depends_on(&producer); - let c3 = dag.add_task(JoinConsumer).depends_on(&producer); + let producer: TaskHandle<_> = dag.add_task(DataProducer).into(); + let c1 = dag.add_task(CountConsumer).depends_on(producer); + let c2 = dag.add_task(FirstConsumer).depends_on(producer); + let c3 = dag.add_task(JoinConsumer).depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -378,12 +378,12 @@ async fn test_arc_fan_out_five_consumers_large_data() { } let dag = DagRunner::new(); - let producer = dag.add_task(LargeDataProducer); - let c1 = dag.add_task(First100Analyzer).depends_on(&producer); - let c2 = dag.add_task(Last100Analyzer).depends_on(&producer); - let c3 = dag.add_task(LongestFinder).depends_on(&producer); - let c4 = dag.add_task(PatternCounter).depends_on(&producer); - let c5 = dag.add_task(TotalBytesComputer).depends_on(&producer); + let producer: TaskHandle<_> = dag.add_task(LargeDataProducer).into(); + let c1 = dag.add_task(First100Analyzer).depends_on(producer); + let c2 = dag.add_task(Last100Analyzer).depends_on(producer); + let c3 = dag.add_task(LongestFinder).depends_on(producer); + let c4 = dag.add_task(PatternCounter).depends_on(producer); + let c5 = dag.add_task(TotalBytesComputer).depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -467,9 +467,9 @@ async fn test_arc_nested_fan_out_tree() { } let dag = DagRunner::new(); - let root = dag.add_task(RootProducer); - let l1_sum = dag.add_task(Level1Sum).depends_on(&root); - let l1_prod = dag.add_task(Level1Product).depends_on(&root); + let root: TaskHandle<_> = dag.add_task(RootProducer).into(); + let l1_sum = dag.add_task(Level1Sum).depends_on(root); + let l1_prod = dag.add_task(Level1Product).depends_on(root); let l2_double = dag.add_task(Level2Double).depends_on(l1_sum); let l2_square = dag.add_task(Level2Square).depends_on(l1_sum); let l2_negate = dag.add_task(Level2Negate).depends_on(l1_prod); @@ -536,10 +536,10 @@ async fn test_arc_performance_vs_clone() { } let dag = DagRunner::new(); - let producer = dag.add_task(LargeProducer); - let p1 = dag.add_task(Process1).depends_on(&producer); - let p2 = dag.add_task(Process2).depends_on(&producer); - let p3 = dag.add_task(Process3).depends_on(&producer); + let producer: TaskHandle<_> = dag.add_task(LargeProducer).into(); + let p1 = dag.add_task(Process1).depends_on(producer); + let p2 = dag.add_task(Process2).depends_on(producer); + let p3 = dag.add_task(Process3).depends_on(producer); let start = Instant::now(); @@ -625,8 +625,8 @@ async fn test_arc_with_result() { let result_arc_ok = dag.add_task(ResultArcOk); let arc_result_err = dag.add_task(ArcResultErr); - let consumer1 = dag.add_task(ArcResultConsumer).depends_on(&arc_result_ok); - let consumer2 = dag.add_task(ResultArcConsumer).depends_on(&result_arc_ok); + let consumer1 = dag.add_task(ArcResultConsumer).depends_on(arc_result_ok); + let consumer2 = dag.add_task(ResultArcConsumer).depends_on(result_arc_ok); // Create a new instance for the error case struct ArcResultConsumer2; @@ -641,7 +641,7 @@ async fn test_arc_with_result() { } } - let consumer3 = dag.add_task(ArcResultConsumer2).depends_on(&arc_result_err); + let consumer3 = dag.add_task(ArcResultConsumer2).depends_on(arc_result_err); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -745,10 +745,10 @@ async fn test_arc_with_option() { let opt_arc_some = dag.add_task(OptionArcSome); let opt_arc_none = dag.add_task(OptionArcNone); - let c1 = dag.add_task(ArcOptionConsumer1).depends_on(&arc_opt_some); - let c2 = dag.add_task(ArcOptionConsumer2).depends_on(&arc_opt_none); - let c3 = dag.add_task(OptionArcConsumer1).depends_on(&opt_arc_some); - let c4 = dag.add_task(OptionArcConsumer2).depends_on(&opt_arc_none); + let c1 = dag.add_task(ArcOptionConsumer1).depends_on(arc_opt_some); + let c2 = dag.add_task(ArcOptionConsumer2).depends_on(arc_opt_none); + let c3 = dag.add_task(OptionArcConsumer1).depends_on(opt_arc_some); + let c4 = dag.add_task(OptionArcConsumer2).depends_on(opt_arc_none); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -800,9 +800,9 @@ async fn test_arc_diamond_dependency() { } let dag = DagRunner::new(); - let top = dag.add_task(Top); - let left = dag.add_task(LeftBranch).depends_on(&top); - let right = dag.add_task(RightBranch).depends_on(&top); + let top: TaskHandle<_> = dag.add_task(Top).into(); + let left = dag.add_task(LeftBranch).depends_on(top); + let right = dag.add_task(RightBranch).depends_on(top); let bottom = dag.add_task(Bottom).depends_on((&left, &right)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) @@ -871,7 +871,7 @@ async fn test_arc_empty_collections() { let map_task = dag.add_task(EmptyHashMap); let consumer = dag .add_task(EmptyConsumer) - .depends_on((&vec_task, &string_task, &map_task)); + .depends_on((vec_task, string_task, map_task)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -938,11 +938,11 @@ async fn test_arc_very_large_data() { } let dag = DagRunner::new(); - let producer = dag.add_task(HugeProducer); - let counter = dag.add_task(ItemCounter).depends_on(&producer); - let first = dag.add_task(FirstSampler).depends_on(&producer); - let last = dag.add_task(LastSampler).depends_on(&producer); - let middle = dag.add_task(MiddleSampler).depends_on(&producer); + let producer: TaskHandle<_> = dag.add_task(HugeProducer).into(); + let counter = dag.add_task(ItemCounter).depends_on(producer); + let first = dag.add_task(FirstSampler).depends_on(producer); + let last = dag.add_task(LastSampler).depends_on(producer); + let middle = dag.add_task(MiddleSampler).depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -979,7 +979,7 @@ async fn test_arc_of_arc() { let dag = DagRunner::new(); let producer = dag.add_task(NestedProducer); - let consumer = dag.add_task(NestedConsumer).depends_on(&producer); + let consumer = dag.add_task(NestedConsumer).depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -1037,13 +1037,13 @@ async fn test_arc_mixed_with_non_arc() { } let dag = DagRunner::new(); - let arc_prod = dag.add_task(ArcProducer); - let non_arc_prod = dag.add_task(NonArcProducer); + let arc_prod = dag.add_task(ArcProducer).into(); + let non_arc_prod = dag.add_task(NonArcProducer).into(); let mixed = dag .add_task(MixedConsumer) .depends_on((&arc_prod, &non_arc_prod)); - let unwrap = dag.add_task(Unwrapper).depends_on(&arc_prod); - let wrap = dag.add_task(Wrapper).depends_on(&non_arc_prod); + let unwrap = dag.add_task(Unwrapper).depends_on(arc_prod); + let wrap = dag.add_task(Wrapper).depends_on(non_arc_prod); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -1106,10 +1106,10 @@ async fn test_arc_parallel_execution() { } let dag = DagRunner::new(); - let producer = dag.add_task(SharedProducer); - let t1 = dag.add_task(ParallelTask1).depends_on(&producer); - let t2 = dag.add_task(ParallelTask2).depends_on(&producer); - let t3 = dag.add_task(ParallelTask3).depends_on(&producer); + let producer: TaskHandle<_> = dag.add_task(SharedProducer).into(); + let t1 = dag.add_task(ParallelTask1).depends_on(producer); + let t2 = dag.add_task(ParallelTask2).depends_on(producer); + let t3 = dag.add_task(ParallelTask3).depends_on(producer); let start = Instant::now(); @@ -1160,7 +1160,7 @@ async fn test_arc_reference_counting() { let dag = DagRunner::new(); let producer = dag.add_task(RefCountProducer); - let checker = dag.add_task(RefCountChecker).depends_on(&producer); + let checker = dag.add_task(RefCountChecker).depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -1223,16 +1223,18 @@ async fn test_arc_massive_fanout_performance_comparison() { } let dag_without_arc = DagRunner::new(); - let producer = dag_without_arc.add_task(ProducerWithoutArc { - data: random_data.clone(), - }); + let producer: TaskHandle<_> = dag_without_arc + .add_task(ProducerWithoutArc { + data: random_data.clone(), + }) + .into(); // Create consumer tasks for fan-out pattern let consumers_without_arc: Vec<_> = (0..FAN_OUT_COUNT) .map(|_| { dag_without_arc .add_task(ConsumerWithoutArc) - .depends_on(&producer) + .depends_on(producer) }) .collect(); @@ -1275,16 +1277,18 @@ async fn test_arc_massive_fanout_performance_comparison() { } let dag_with_arc = DagRunner::new(); - let producer_arc = dag_with_arc.add_task(ProducerWithArc { - data: random_data.clone(), - }); + let producer_arc: TaskHandle<_> = dag_with_arc + .add_task(ProducerWithArc { + data: random_data.clone(), + }) + .into(); // Create consumer tasks for fan-out pattern let consumers_with_arc: Vec<_> = (0..FAN_OUT_COUNT) .map(|_| { dag_with_arc .add_task(ConsumerWithArc) - .depends_on(&producer_arc) + .depends_on(producer_arc) }) .collect(); diff --git a/tests/boundaries/deep_chains.rs b/tests/boundaries/deep_chains.rs index 28fb521..26d0826 100644 --- a/tests/boundaries/deep_chains.rs +++ b/tests/boundaries/deep_chains.rs @@ -12,7 +12,7 @@ async fn test_1000_level_deep_chain() -> DagResult<()> { let dag = DagRunner::new(); let first = dag.add_task(task_fn(|_: ()| async { 0 })); - let mut current = (&first).into(); // Convert to TaskHandle + let mut current = first.into(); // Convert to TaskHandle for _i in 1..1000 { current = dag @@ -32,7 +32,7 @@ async fn test_deep_chain_with_branches() -> DagResult<()> { let dag = DagRunner::new(); let first = dag.add_task(task_fn(|_: ()| async { 0 })); - let mut main_chain: dagx::TaskHandle = (&first).into(); + let mut main_chain: dagx::TaskHandle = first.into(); let mut branches = Vec::new(); for i in 1..500 { @@ -72,7 +72,7 @@ async fn test_multiple_parallel_deep_chains() -> DagResult<()> { for chain_id in 0..8 { let first = dag.add_task(task_fn(move |_: ()| async move { chain_id * 1000 })); - let mut current: dagx::TaskHandle = (&first).into(); + let mut current: dagx::TaskHandle = first.into(); for _ in 0..500 { current = dag @@ -136,7 +136,7 @@ async fn test_deep_chain_execution_order() -> DagResult<()> { } } })); - let mut current: dagx::TaskHandle = (&first).into(); + let mut current: dagx::TaskHandle = first.into(); for expected in 1..100 { current = dag @@ -169,7 +169,7 @@ async fn test_deep_binary_tree() -> DagResult<()> { fn build_tree(dag: &DagRunner, depth: usize, value: i32) -> dagx::TaskHandle { if depth == 0 { let task = dag.add_task(task_fn(move |_: ()| async move { value })); - (&task).into() // Convert TaskBuilder to TaskHandle + task.into() // Convert TaskBuilder to TaskHandle } else { let left = build_tree(dag, depth - 1, value * 2); let right = build_tree(dag, depth - 1, value * 2 + 1); @@ -199,8 +199,8 @@ async fn test_fibonacci_chain() -> DagResult<()> { let f0_builder = dag.add_task(task_fn(|_: ()| async { 0i64 })); let f1_builder = dag.add_task(task_fn(|_: ()| async { 1i64 })); - let mut prev2: dagx::TaskHandle = (&f0_builder).into(); - let mut prev1: dagx::TaskHandle = (&f1_builder).into(); + let mut prev2: dagx::TaskHandle = f0_builder.into(); + let mut prev1: dagx::TaskHandle = f1_builder.into(); for _ in 2..50 { let next = dag @@ -226,7 +226,7 @@ async fn test_deep_chain_with_accumulator() -> DagResult<()> { // Use a simpler accumulation pattern - just sum let first = dag.add_task(task_fn(|_: ()| async { 0i64 })); - let mut current: dagx::TaskHandle = (&first).into(); + let mut current: dagx::TaskHandle = first.into(); for i in 1..=200 { current = dag @@ -250,8 +250,8 @@ async fn test_zigzag_dependencies() -> DagResult<()> { let a_first = dag.add_task(task_fn(|_: ()| async { 1 })); let b_first = dag.add_task(task_fn(|_: ()| async { 2 })); - let mut chain_a: dagx::TaskHandle = (&a_first).into(); - let mut chain_b: dagx::TaskHandle = (&b_first).into(); + let mut chain_a: dagx::TaskHandle = a_first.into(); + let mut chain_b: dagx::TaskHandle = b_first.into(); for i in 0..100 { if i % 2 == 0 { @@ -287,7 +287,7 @@ async fn test_10000_level_chain_stress() -> DagResult<()> { let dag = DagRunner::new(); let first = dag.add_task(task_fn(|_: ()| async { 0u64 })); - let mut current: dagx::TaskHandle = (&first).into(); + let mut current: dagx::TaskHandle = first.into(); for _ in 1..10_000 { current = dag diff --git a/tests/boundaries/large_scale.rs b/tests/boundaries/large_scale.rs index 36c5e01..6e32c2b 100644 --- a/tests/boundaries/large_scale.rs +++ b/tests/boundaries/large_scale.rs @@ -13,7 +13,7 @@ async fn test_10000_independent_tasks() -> DagResult<()> { let counter = Arc::new(AtomicUsize::new(0)); - let tasks: Vec<_> = (0..10_000) + let mut tasks: Vec<_> = (0..10_000) .map(|i| { let counter = counter.clone(); dag.add_task(task_fn(move |_: ()| { @@ -32,9 +32,9 @@ async fn test_10000_independent_tasks() -> DagResult<()> { assert_eq!(counter.load(Ordering::Relaxed), 10_000); // Spot check some results - assert_eq!(dag.get(&tasks[0])?, 0); - assert_eq!(dag.get(&tasks[9_999])?, 9_999); - assert_eq!(dag.get(&tasks[5_000])?, 5_000); + assert_eq!(dag.get(tasks.swap_remove(9_999))?, 9_999); + assert_eq!(dag.get(tasks.swap_remove(5_000))?, 5_000); + assert_eq!(dag.get(tasks.swap_remove(0))?, 0); Ok(()) } @@ -55,7 +55,7 @@ async fn test_5000_node_pyramid() -> DagResult<()> { 0 } })); - (&task).into() + task.into() }) .collect(); @@ -126,7 +126,7 @@ async fn test_5000_node_pyramid_single_threaded() -> DagResult<()> { 0 } })); - (&task).into() + task.into() }) .collect(); @@ -188,7 +188,10 @@ async fn test_wide_dag_1000_sources_1000_sinks() -> DagResult<()> { // Create 1000 source tasks let sources: Vec<_> = (0..1000) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { i % 10 }))) + .map(|i| { + dag.add_task(task_fn(move |_: ()| async move { i % 10 })) + .into() + }) .collect(); // Create 1000 sink tasks, each depending on 3 random sources @@ -238,7 +241,7 @@ async fn test_10000_node_linear_chain_segments() -> DagResult<()> { } } })); - let mut current: dagx::TaskHandle = (&first).into(); + let mut current: dagx::TaskHandle = first.into(); for _i in 1..100 { current = dag diff --git a/tests/boundaries/type_limits.rs b/tests/boundaries/type_limits.rs index 173aa62..f795009 100644 --- a/tests/boundaries/type_limits.rs +++ b/tests/boundaries/type_limits.rs @@ -1,7 +1,7 @@ //! Tests for type system edge cases and limits use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::marker::PhantomData; @@ -22,7 +22,7 @@ async fn test_zero_sized_types_throughout() -> DagResult<()> { let t1 = dag.add_task(task_fn(|_: ()| async { Empty })); // Task that also produces ZST (independent since we can't extract custom types) - let t2 = dag.add_task(task_fn(|_: ()| async { 42 })); + let t2: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into(); // Task with PhantomData let _t3 = dag.add_task(task_fn(|_: ()| async { @@ -37,7 +37,7 @@ async fn test_zero_sized_types_throughout() -> DagResult<()> { assert_eq!(val, 42); "success" })) - .depends_on(&t2); + .depends_on(t2); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -72,7 +72,7 @@ async fn test_large_value_types() -> DagResult<()> { .add_task(task_fn(|val: usize| async move { val // Just pass through to verify })) - .depends_on(&t1); + .depends_on(t1); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -86,12 +86,12 @@ async fn test_unit_type_chains() -> DagResult<()> { // Test chains of unit type operations let dag = DagRunner::new(); - let t1 = dag.add_task(task_fn(|_: ()| async {})); - let t2 = dag.add_task(task_fn(|_: ()| async {})).depends_on(&t1); + let t1: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async {})).into(); + let t2 = dag.add_task(task_fn(|_: ()| async {})).depends_on(t1); let t3 = dag.add_task(task_fn(|_: ()| async {})).depends_on(t2); let t4 = dag .add_task(task_fn(|_: ()| async { "done" })) - .depends_on(&t3); + .depends_on(t3); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -122,7 +122,7 @@ async fn test_nested_option_result_types() -> DagResult<()> { _ => 0, } })) - .depends_on(&t1); + .depends_on(t1); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -146,7 +146,7 @@ async fn test_tuple_of_tuples() -> DagResult<()> { a + b + c + d + e + f + g + h }, )) - .depends_on((&t1, &t2)); + .depends_on((t1, t2)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -180,7 +180,7 @@ async fn test_string_types_variety() -> DagResult<()> { std::sync::Arc<&str>, )| async move { format!("{} {} {} {} {} {}", s1, s2, s3, s4, s5, s6) }, )) - .depends_on((&t1, &t2, &t3, &t4, &t5, &t6)); + .depends_on((t1, t2, t3, t4, t5, t6)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -209,7 +209,7 @@ async fn test_generic_type_constraints() -> DagResult<()> { format!("{:?} {:?} {:?}", w1, w2, w3) }, )) - .depends_on((&t1, &t2, &t3)); + .depends_on((t1, t2, t3)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -235,7 +235,7 @@ async fn test_reference_wrapper_types() -> DagResult<()> { let t2 = dag .add_task(task_fn(|val: i32| async move { val * 2 })) - .depends_on(&t1); + .depends_on(t1); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -260,7 +260,7 @@ async fn test_array_types() -> DagResult<()> { } sum })) - .depends_on((&t1, &t2)); + .depends_on((t1, t2)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -299,7 +299,7 @@ async fn test_enum_variants() -> DagResult<()> { && matches!(e4, MyEnum::LargeVariant(_)) }, )) - .depends_on((&t1, &t2, &t3, &t4)); + .depends_on((t1, t2, t3, t4)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; diff --git a/tests/boundaries/zero_tasks.rs b/tests/boundaries/zero_tasks.rs index b43e7c4..24abe3e 100644 --- a/tests/boundaries/zero_tasks.rs +++ b/tests/boundaries/zero_tasks.rs @@ -64,7 +64,7 @@ async fn test_zero_sized_type_task() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; - assert_eq!(dag.get(&task)?, ZeroSized); + assert_eq!(dag.get(task)?, ZeroSized); Ok(()) } @@ -91,7 +91,7 @@ async fn test_dag_with_only_source_tasks() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task)?, i); } @@ -155,7 +155,7 @@ async fn test_dag_with_never_type_simulation() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; - assert_eq!(dag.get(&task)?, Ok(42)); + assert_eq!(dag.get(task)?, Ok(42)); Ok(()) } diff --git a/tests/custom_type_test.rs b/tests/custom_type_test.rs index adc54d1..c9a7c4d 100644 --- a/tests/custom_type_test.rs +++ b/tests/custom_type_test.rs @@ -1,5 +1,5 @@ // Test that custom types work without any trait implementations -use dagx::{task, DagRunner}; +use dagx::{task, DagRunner, TaskHandle}; use futures::FutureExt; #[derive(Clone, Debug, PartialEq)] @@ -55,7 +55,7 @@ async fn test_custom_type_single_dependency() { let dag = DagRunner::new(); let fetch = dag.add_task(FetchPerson); - let process = dag.add_task(ProcessPerson).depends_on(&fetch); + let process = dag.add_task(ProcessPerson).depends_on(fetch); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -69,9 +69,9 @@ async fn test_custom_type_single_dependency() { async fn test_custom_type_passthrough() { let dag = DagRunner::new(); - let fetch = dag.add_task(FetchPerson); - let transform = dag.add_task(PersonToCompany).depends_on(&fetch); - let process = dag.add_task(ProcessPerson).depends_on(&fetch); + let fetch: TaskHandle<_> = dag.add_task(FetchPerson).into(); + let transform = dag.add_task(PersonToCompany).depends_on(fetch); + let process = dag.add_task(ProcessPerson).depends_on(fetch); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -90,11 +90,11 @@ async fn test_custom_type_diamond_pattern() { let dag = DagRunner::new(); // Source - let fetch = dag.add_task(FetchPerson); + let fetch: TaskHandle<_> = dag.add_task(FetchPerson).into(); // Two paths from source - let path_a = dag.add_task(ProcessPerson).depends_on(&fetch); - let path_b = dag.add_task(PersonToCompany).depends_on(&fetch); + let path_a = dag.add_task(ProcessPerson).depends_on(fetch); + let path_b = dag.add_task(PersonToCompany).depends_on(fetch); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -111,10 +111,10 @@ async fn test_custom_type_diamond_pattern() { async fn test_custom_type_fan_out() { let dag = DagRunner::new(); - let fetch = dag.add_task(FetchPerson); - let process1 = dag.add_task(ProcessPerson).depends_on(&fetch); - let process2 = dag.add_task(ProcessPerson).depends_on(&fetch); - let process3 = dag.add_task(ProcessPerson).depends_on(&fetch); + let fetch: TaskHandle<_> = dag.add_task(FetchPerson).into(); + let process1 = dag.add_task(ProcessPerson).depends_on(fetch); + let process2 = dag.add_task(ProcessPerson).depends_on(fetch); + let process3 = dag.add_task(ProcessPerson).depends_on(fetch); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/tests/cycle_prevention.rs b/tests/cycle_prevention.rs index 5e71747..843410d 100644 --- a/tests/cycle_prevention.rs +++ b/tests/cycle_prevention.rs @@ -31,11 +31,11 @@ fn test_builder_consumed_by_depends_on() { let consumer_builder = dag.add_task(Consumer); // This consumes consumer_builder and returns a TaskHandle - let _consumer_handle = consumer_builder.depends_on(&source); + let _consumer_handle = consumer_builder.depends_on(source); // We CANNOT use consumer_builder again because it was moved // This would fail to compile: - // let _consumer2 = consumer_builder.depends_on(&source); // ERROR: use of moved value + // let _consumer2 = consumer_builder.depends_on(source); // ERROR: use of moved value } /// Demonstrates that you can only get a TaskHandle by finalizing a builder, @@ -64,7 +64,7 @@ fn test_handle_is_immutable_reference() { // But TaskHandle has NO methods to modify the DAG // There's no way to add dependencies to it // This would fail to compile: - // handle.depends_on(&something); // ERROR: no method named `depends_on` + // handle.depends_on(something); // ERROR: no method named `depends_on` } /// Documents the ordering constraint that prevents cycles @@ -110,7 +110,7 @@ fn test_ordering_prevents_cycles() { // Let's create a valid DAG instead: A→B (B depends on A) let a_handle: TaskHandle = a_builder.into(); // A has no deps (unit input) let _b_handle = b_builder.depends_on(a_handle); - // Now we could try: a_handle.depends_on(&b_handle)? + // Now we could try: a_handle.depends_on(b_handle)? // But TaskHandle has no such method! } @@ -147,7 +147,7 @@ fn test_unit_tasks_cannot_create_cycles() { // And once you've converted to TaskHandle, you can't go back // This would fail to compile: - // _handle1.depends_on(&_handle2); // ERROR: no method named `depends_on` + // _handle1.depends_on(_handle2); // ERROR: no method named `depends_on` } /// Demonstrates the catch-22 of three-way cycles @@ -183,9 +183,9 @@ fn test_three_way_cycle_impossible() { let _c_builder = dag.add_task(C); // To create A→C→B→A: - // 1. a_builder.depends_on(&c_handle) // Need c_handle - // 2. c_builder.depends_on(&b_handle) // Need b_handle - // 3. b_builder.depends_on(&a_handle) // Need a_handle (from step 1!) + // 1. a_builder.depends_on(c_handle) // Need c_handle + // 2. c_builder.depends_on(b_handle) // Need b_handle + // 3. b_builder.depends_on(a_handle) // Need a_handle (from step 1!) // // But step 3 needs a_handle which doesn't exist until step 1 completes. // And step 1 needs c_handle which doesn't exist until step 2 completes. @@ -210,7 +210,7 @@ fn test_self_loop_prevented() { let _builder = dag.add_task(SelfReferential); // To create A→A (self-loop): - // builder.depends_on(&builder) + // builder.depends_on(builder) // // But this would fail because: // 1. depends_on() takes `self` by value (moves builder) @@ -218,7 +218,7 @@ fn test_self_loop_prevented() { // 3. We can't also use &builder as an argument because it's being moved // // This would fail to compile: - // let _handle = builder.depends_on(&builder); // ERROR: use of moved value + // let _handle = builder.depends_on(builder); // ERROR: use of moved value } /// Comprehensive test showing all the guardrails @@ -264,8 +264,8 @@ async fn test_type_safety_prevents_invalid_graphs() { let s2 = dag.add_task(Source); // Transform depends on sources - let t1 = dag.add_task(Transform).depends_on(&s1); - let t2 = dag.add_task(Transform).depends_on(&s2); + let t1 = dag.add_task(Transform).depends_on(s1); + let t2 = dag.add_task(Transform).depends_on(s2); // Aggregate depends on transforms let result = dag.add_task(Aggregate).depends_on((&t1, &t2)); diff --git a/tests/dependencies/resolution.rs b/tests/dependencies/resolution.rs index c68317b..f29d1aa 100644 --- a/tests/dependencies/resolution.rs +++ b/tests/dependencies/resolution.rs @@ -1,7 +1,7 @@ //! Tests for dependency resolution order and transitive dependencies use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::{Arc, Mutex}; @@ -37,7 +37,7 @@ async fn test_dependency_resolution_order() -> DagResult<()> { x + 1 } })) - .depends_on(&a) + .depends_on(a) }; let c = { @@ -108,17 +108,17 @@ async fn test_transitive_dependencies() -> DagResult<()> { // A -> B -> C (creates transitive A -> C relationship) let dag = DagRunner::new(); - let a = dag.add_task(task_fn(|_: ()| async { 10 })); + let a: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into(); let b = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&a); + .depends_on(a); let c = dag .add_task(task_fn(|x: i32| async move { x + 5 })) .depends_on(b); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; - assert_eq!(dag.get(&a)?, 10); + assert_eq!(dag.get(a)?, 10); assert_eq!(dag.get(b)?, 20); assert_eq!(dag.get(c)?, 25); // 20 + 5 @@ -130,7 +130,7 @@ async fn test_deep_chain_50_levels() -> DagResult<()> { let dag = DagRunner::new(); let first = dag.add_task(task_fn(|_: ()| async { 0 })); - let mut handles = vec![(&first).into()]; + let mut handles = vec![first.into()]; for _i in 1..=50 { let next = dag @@ -150,7 +150,7 @@ async fn test_deep_chain_200_levels() -> DagResult<()> { let dag = DagRunner::new(); let first = dag.add_task(task_fn(|_: ()| async { 1 })); - let mut current = (&first).into(); + let mut current = first.into(); for _ in 0..200 { current = dag diff --git a/tests/dependencies/single.rs b/tests/dependencies/single.rs index cff5237..8191d8d 100644 --- a/tests/dependencies/single.rs +++ b/tests/dependencies/single.rs @@ -1,7 +1,7 @@ //! Tests for single dependencies and basic dependency data flow use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; #[tokio::test] @@ -11,7 +11,7 @@ async fn test_single_dependency() -> DagResult<()> { let source = dag.add_task(task_fn(|_: ()| async { 42 })); let dependent = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&source); + .depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -24,17 +24,19 @@ async fn test_dependency_data_flow() -> DagResult<()> { // Test that data flows correctly through dependencies let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { vec![1, 2, 3, 4, 5] })); + let source: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { vec![1, 2, 3, 4, 5] })) + .into(); let sum = dag .add_task(task_fn(|v: Vec| async move { v.iter().sum::() })) - .depends_on(&source); + .depends_on(source); let product = dag .add_task(task_fn( |v: Vec| async move { v.iter().product::() }, )) - .depends_on(&source); + .depends_on(source); let final_result = dag .add_task(task_fn(|(s, p): (i32, i32)| async move { s + p })) @@ -62,7 +64,7 @@ async fn test_dependencies_with_different_types() -> DagResult<()> { .add_task(task_fn(|(i, s, b): (i32, String, bool)| async move { format!("{}: {} ({})", s, i, b) })) - .depends_on((&int_source, &string_source, &bool_source)); + .depends_on((int_source, string_source, bool_source)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -75,13 +77,13 @@ async fn test_shared_dependencies() -> DagResult<()> { // Test that a single node can be a dependency for multiple downstream nodes let dag = DagRunner::new(); - let shared = dag.add_task(task_fn(|_: ()| async { 42 })); + let shared: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into(); // Create 10 tasks that all depend on the shared node let dependents: Vec<_> = (0..10) .map(|i| { dag.add_task(task_fn(move |x: i32| async move { x * (i + 1) })) - .depends_on(&shared) + .depends_on(shared) }) .collect(); @@ -106,7 +108,7 @@ async fn test_multiple_source_nodes() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; - for (i, source) in sources.iter().enumerate() { + for (i, source) in sources.into_iter().enumerate() { assert_eq!(dag.get(source)?, i as i32 * 10); } diff --git a/tests/dependencies/tuples.rs b/tests/dependencies/tuples.rs index 1126334..299c22e 100644 --- a/tests/dependencies/tuples.rs +++ b/tests/dependencies/tuples.rs @@ -12,7 +12,7 @@ async fn test_two_dependencies() -> DagResult<()> { let b = dag.add_task(task_fn(|_: ()| async { 20 })); let sum = dag .add_task(task_fn(|(x, y): (i32, i32)| async move { x + y })) - .depends_on((&a, &b)); + .depends_on((a, b)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -31,7 +31,7 @@ async fn test_three_dependencies() -> DagResult<()> { .add_task(task_fn( |(x, y, z): (i32, i32, i32)| async move { x + y + z }, )) - .depends_on((&a, &b, &c)); + .depends_on((a, b, c)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -44,7 +44,7 @@ async fn test_four_dependencies() -> DagResult<()> { let dag = DagRunner::new(); let deps: Vec<_> = (1..=4) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { i }))) + .map(|i| dag.add_task(task_fn(move |_: ()| async move { i })).into()) .collect(); let sum = dag @@ -64,7 +64,7 @@ async fn test_five_dependencies() -> DagResult<()> { let dag = DagRunner::new(); let deps: Vec<_> = (1..=5) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { i }))) + .map(|i| dag.add_task(task_fn(move |_: ()| async move { i })).into()) .collect(); let sum = dag @@ -84,7 +84,7 @@ async fn test_six_dependencies() -> DagResult<()> { let dag = DagRunner::new(); let deps: Vec<_> = (1..=6) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { i }))) + .map(|i| dag.add_task(task_fn(move |_: ()| async move { i })).into()) .collect(); let sum = dag.add_task(task_fn( @@ -106,7 +106,7 @@ async fn test_seven_dependencies() -> DagResult<()> { let dag = DagRunner::new(); let deps: Vec<_> = (1..=7) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { i }))) + .map(|i| dag.add_task(task_fn(move |_: ()| async move { i })).into()) .collect(); let sum = dag @@ -130,7 +130,7 @@ async fn test_eight_dependencies() -> DagResult<()> { let dag = DagRunner::new(); let deps: Vec<_> = (1..=8) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { i }))) + .map(|i| dag.add_task(task_fn(move |_: ()| async move { i })).into()) .collect(); let sum = dag diff --git a/tests/errors/error_types.rs b/tests/errors/error_types.rs index 68e9fc1..affe88c 100644 --- a/tests/errors/error_types.rs +++ b/tests/errors/error_types.rs @@ -1,17 +1,17 @@ //! Tests for different error types and error handling use crate::common::task_fn; -use dagx::{DagError, DagRunner}; +use dagx::{DagError, DagRunner, TaskHandle}; use futures::FutureExt; #[tokio::test] async fn test_result_not_found_error() { let dag = DagRunner::new(); - let t1 = dag.add_task(task_fn(|_: ()| async { 42 })); + let t1: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into(); // Try to get result before running - let result = dag.get(&t1); + let result = dag.get(t1); assert!(matches!(result, Err(DagError::ResultNotFound { .. }))); // Run and verify it works after @@ -19,7 +19,7 @@ async fn test_result_not_found_error() { .await .unwrap(); - assert_eq!(dag.get(&t1).unwrap(), 42); + assert_eq!(dag.get(t1).unwrap(), 42); } #[tokio::test] @@ -38,8 +38,8 @@ async fn test_nested_result_error_handling() { .unwrap(); // Both tasks complete successfully (they return Results) - assert_eq!(dag.get(&task1).unwrap(), Err("Internal error".to_string())); - assert_eq!(dag.get(&task2).unwrap(), Ok(42)); + assert_eq!(dag.get(task1).unwrap(), Err("Internal error".to_string())); + assert_eq!(dag.get(task2).unwrap(), Ok(42)); } #[tokio::test] @@ -53,7 +53,7 @@ async fn test_option_none_not_error() { .unwrap(); // None is a valid result, not an error - assert_eq!(dag.get(&task).unwrap(), None); + assert_eq!(dag.get(task).unwrap(), None); } #[tokio::test] @@ -82,12 +82,12 @@ async fn test_custom_error_types() { .unwrap(); // Check custom errors are preserved - match dag.get(&task1).unwrap() { + match dag.get(task1).unwrap() { Err(CustomError::ValidationError(msg)) => assert_eq!(msg, "Invalid input"), _ => panic!("Wrong error type"), } - match dag.get(&task2).unwrap() { + match dag.get(task2).unwrap() { Err(CustomError::ProcessingError { code, .. }) => assert_eq!(code, 500), _ => panic!("Wrong error type"), } @@ -104,7 +104,7 @@ async fn test_error_in_tuple_dependency() { let dependent = dag .add_task(task_fn(|(a, b): (i32, i32)| async move { a + b })) - .depends_on((&ok_task, &err_task)); + .depends_on((ok_task, err_task)); let result = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; @@ -127,8 +127,8 @@ async fn test_string_panic_vs_structured_panic() { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; // Both should result in errors - assert!(dag.get(&string_panic).is_err()); - assert!(dag.get(&formatted_panic).is_err()); + assert!(dag.get(string_panic).is_err()); + assert!(dag.get(formatted_panic).is_err()); } #[tokio::test] @@ -149,7 +149,7 @@ async fn test_anyhow_like_error_chain() { .unwrap(); // Get the chained error - let result = dag.get(&task).unwrap(); + let result = dag.get(task).unwrap(); assert!(result.is_err()); if let Err(e) = result { diff --git a/tests/errors/propagation.rs b/tests/errors/propagation.rs index be3c01a..80e832b 100644 --- a/tests/errors/propagation.rs +++ b/tests/errors/propagation.rs @@ -1,7 +1,7 @@ //! Tests for error propagation through the DAG use crate::common::task_fn; -use dagx::DagRunner; +use dagx::{DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -10,12 +10,12 @@ use std::sync::Arc; async fn test_linear_error_propagation() { let dag = DagRunner::new(); - let t1 = dag.add_task(task_fn(|_: ()| async { 1 })); + let t1: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 1 })).into(); let t2 = dag .add_task(task_fn(|x: i32| async move { panic!("Error at t2 with input {}", x); })) - .depends_on(&t1); + .depends_on(t1); let t3 = dag .add_task(task_fn(|x: i32| async move { x + 1 })) .depends_on(t2); @@ -26,7 +26,7 @@ async fn test_linear_error_propagation() { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; // t1 succeeds - assert_eq!(dag.get(&t1).unwrap(), 1); + assert_eq!(dag.get(t1).unwrap(), 1); // t2 fails assert!(dag.get(t2).is_err()); @@ -46,17 +46,17 @@ async fn test_diamond_error_propagation() { // \ / // sink - let source = dag.add_task(task_fn(|_: ()| async { 100 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 100 })).into(); let left = dag .add_task(task_fn(|x: i32| async move { x / 2 })) - .depends_on(&source); + .depends_on(source); let right = dag .add_task(task_fn(|x: i32| async move { panic!("Right path fails with {}", x); })) - .depends_on(&source); + .depends_on(source); let sink = dag .add_task(task_fn(|(l, r): (i32, i32)| async move { l + r })) @@ -64,7 +64,7 @@ async fn test_diamond_error_propagation() { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; - assert_eq!(dag.get(&source).unwrap(), 100); + assert_eq!(dag.get(source).unwrap(), 100); assert_eq!(dag.get(left).unwrap(), 50); assert!(dag.get(right).is_err()); assert!(dag.get(sink).is_err()); // Fails due to right dependency @@ -76,16 +76,18 @@ async fn test_error_stops_at_boundary() { let execution_tracker = Arc::new(AtomicUsize::new(0)); // Branch with error - let error_source = dag.add_task(task_fn({ - let tracker = execution_tracker.clone(); - move |_: ()| { - let tracker = tracker.clone(); - async move { - tracker.fetch_add(1, Ordering::SeqCst); - panic!("Error source"); + let error_source: TaskHandle<_> = dag + .add_task(task_fn({ + let tracker = execution_tracker.clone(); + move |_: ()| { + let tracker = tracker.clone(); + async move { + tracker.fetch_add(1, Ordering::SeqCst); + panic!("Error source"); + } } - } - })); + })) + .into(); let error_dependent = dag .add_task(task_fn({ @@ -98,7 +100,7 @@ async fn test_error_stops_at_boundary() { } } })) - .depends_on(&error_source); + .depends_on(error_source); // Independent branch let independent = dag.add_task(task_fn({ @@ -115,11 +117,11 @@ async fn test_error_stops_at_boundary() { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; // Error branch: source runs but dependent doesn't - assert!(dag.get(&error_source).is_err()); + assert!(dag.get(error_source).is_err()); assert!(dag.get(error_dependent).is_err()); // Independent branch runs - assert_eq!(dag.get(&independent).unwrap(), 10); + assert_eq!(dag.get(independent).unwrap(), 10); // Check execution: 1 (error_source) + 10 (independent) = 11 assert_eq!(execution_tracker.load(Ordering::SeqCst), 11); @@ -130,15 +132,19 @@ async fn test_multiple_error_sources_convergence() { let dag = DagRunner::new(); // Multiple error sources - let error1 = dag.add_task(task_fn(|_: ()| async { - panic!("Error source 1"); - })); + let error1 = dag + .add_task(task_fn(|_: ()| async { + panic!("Error source 1"); + })) + .into(); - let error2 = dag.add_task(task_fn(|_: ()| async { - panic!("Error source 2"); - })); + let error2 = dag + .add_task(task_fn(|_: ()| async { + panic!("Error source 2"); + })) + .into(); - let success = dag.add_task(task_fn(|_: ()| async { 42 })); + let success = dag.add_task(task_fn(|_: ()| async { 42 })).into(); // Convergence point depends on all three let convergence = dag @@ -148,11 +154,11 @@ async fn test_multiple_error_sources_convergence() { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; // All error sources fail - assert!(dag.get(&error1).is_err()); - assert!(dag.get(&error2).is_err()); + assert!(dag.get(error1).is_err()); + assert!(dag.get(error2).is_err()); // Success task works - assert_eq!(dag.get(&success).unwrap(), 42); + assert_eq!(dag.get(success).unwrap(), 42); // Convergence fails due to any error dependency assert!(dag.get(convergence).is_err()); @@ -162,22 +168,24 @@ async fn test_multiple_error_sources_convergence() { async fn test_error_in_wide_fanout() { let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { - panic!("Source fails"); - })); + let source: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { + panic!("Source fails"); + })) + .into(); // Create wide fanout from failing source let dependents: Vec<_> = (0..20) .map(|i| { dag.add_task(task_fn(move |x: i32| async move { x + i })) - .depends_on(&source) + .depends_on(source) }) .collect(); let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; // Source fails - assert!(dag.get(&source).is_err()); + assert!(dag.get(source).is_err()); // All dependents fail for dependent in &dependents { @@ -190,9 +198,11 @@ async fn test_selective_error_propagation() { let dag = DagRunner::new(); // Source that produces a Result - let source = dag.add_task(task_fn(|_: ()| async { - Result::::Err("Source error".to_string()) - })); + let source: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { + Result::::Err("Source error".to_string()) + })) + .into(); // Handler that processes the Result let handler = dag @@ -202,7 +212,7 @@ async fn test_selective_error_propagation() { Err(_) => -1, // Default value on error } })) - .depends_on(&source); + .depends_on(source); // Further processing let final_task = dag @@ -220,7 +230,7 @@ async fn test_selective_error_propagation() { .unwrap(); // Source returns an Err variant (not a panic) - assert_eq!(dag.get(&source).unwrap(), Err("Source error".to_string())); + assert_eq!(dag.get(source).unwrap(), Err("Source error".to_string())); // Handler processes it assert_eq!(dag.get(handler).unwrap(), -1); @@ -258,7 +268,7 @@ async fn test_error_propagation_timing() { } } })) - .depends_on(&t1); + .depends_on(t1); let _t3 = dag .add_task(task_fn({ @@ -271,7 +281,7 @@ async fn test_error_propagation_timing() { } } })) - .depends_on(&t2); + .depends_on(t2); let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; @@ -297,12 +307,12 @@ async fn test_partial_branch_failure_propagation() { // \ | / // sink - let root = dag.add_task(task_fn(|_: ()| async { 100 })); + let root: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 100 })).into(); // Branch A let a1 = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&root); + .depends_on(root); let a2 = dag .add_task(task_fn(|x: i32| async move { x + 2 })) .depends_on(a1); @@ -313,22 +323,22 @@ async fn test_partial_branch_failure_propagation() { // Branch B (with error) - use Result instead of panic let b1 = dag .add_task(task_fn(|x: i32| async move { Ok(x * 2) })) - .depends_on(&root); + .depends_on(root); let b2 = dag .add_task(task_fn(|_x: Result| async move { Err("Branch B fails at b2") })) - .depends_on(&b1); + .depends_on(b1); let b3 = dag .add_task(task_fn( |x: Result| async move { x.map(|v| v * 3) }, )) - .depends_on(&b2); + .depends_on(b2); // Branch C let c1 = dag .add_task(task_fn(|x: i32| async move { x - 1 })) - .depends_on(&root); + .depends_on(root); let c2 = dag .add_task(task_fn(|x: i32| async move { x - 2 })) .depends_on(c1); diff --git a/tests/errors/recovery.rs b/tests/errors/recovery.rs index 84e63a5..d6226b2 100644 --- a/tests/errors/recovery.rs +++ b/tests/errors/recovery.rs @@ -27,10 +27,10 @@ async fn test_fallback_on_error() -> DagResult<()> { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; // Primary should fail - assert!(dag.get(&primary).is_err()); + assert!(dag.get(primary).is_err()); // Fallback should succeed - assert_eq!(dag.get(&fallback)?, 100); + assert_eq!(dag.get(fallback)?, 100); Ok(()) } @@ -63,7 +63,7 @@ async fn test_retry_pattern_simulation() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; // Task completes with error on first "attempt" - assert_eq!(dag.get(&task)?, Err("Simulated failure")); + assert_eq!(dag.get(task)?, Err("Simulated failure")); Ok(()) } @@ -106,7 +106,7 @@ async fn test_circuit_breaker_pattern() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; // First few tasks fail and open circuit - for task in &tasks[0..3] { + for task in tasks.into_iter().take(4) { assert!(dag.get(task)?.is_err()); } @@ -137,7 +137,7 @@ async fn test_partial_recovery_with_defaults() -> DagResult<()> { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; - let result = dag.get(&aggregator)?; + let result = dag.get(aggregator)?; assert_eq!(result.len(), 10); Ok(()) @@ -149,7 +149,7 @@ async fn test_error_accumulation_pattern() -> DagResult<()> { let errors = Arc::new(parking_lot::Mutex::new(Vec::new())); // Tasks that may produce errors - let tasks: Vec<_> = (0..10) + let mut tasks: Vec<_> = (0..10) .map(|i| { let errors = errors.clone(); dag.add_task(task_fn(move |_: ()| { @@ -171,9 +171,13 @@ async fn test_error_accumulation_pattern() -> DagResult<()> { let error_list = errors.lock().clone(); assert_eq!(error_list.len(), 5); // Even numbered tasks + tasks.truncate(2); + + let [first, second] = <[_; 2]>::try_from(tasks).map_err(|_e| ()).unwrap(); + // Verify specific results - assert!(dag.get(&tasks[0])?.is_err()); - assert_eq!(dag.get(&tasks[1])?, Ok(1)); + assert!(dag.get(first)?.is_err()); + assert_eq!(dag.get(second)?, Ok(1)); Ok(()) } @@ -197,7 +201,7 @@ async fn test_graceful_degradation() -> DagResult<()> { // Here just uses base base.iter().sum::() })) - .depends_on(&critical); + .depends_on(critical); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -217,13 +221,13 @@ async fn test_error_boundary_isolation() -> DagResult<()> { .add_task(task_fn(|_x: i32| async move { Err::("Group A error") })) - .depends_on(&a1); + .depends_on(a1); // Group B: should be isolated from Group A's error let b1 = dag.add_task(task_fn(|_: ()| async { 20 })); let b2 = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&b1); + .depends_on(b1); // Group C: depends on B but not A let c1 = dag @@ -268,10 +272,10 @@ async fn test_compensation_action() -> DagResult<()> { let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; // Action failed - assert!(dag.get(&action).is_err()); + assert!(dag.get(action).is_err()); // Compensation ran successfully - assert_eq!(dag.get(&compensation)?, "Compensation executed"); + assert_eq!(dag.get(compensation)?, "Compensation executed"); assert!(compensation_triggered.load(Ordering::SeqCst)); Ok(()) diff --git a/tests/execution/basic.rs b/tests/execution/basic.rs index f94185d..caade69 100644 --- a/tests/execution/basic.rs +++ b/tests/execution/basic.rs @@ -29,7 +29,7 @@ async fn test_deep_chain() { let a = dag.add_task(task_fn(|_: ()| async { 1 })); let b = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&a); + .depends_on(a); let c = dag .add_task(task_fn(|x: i32| async move { x + 1 })) .depends_on(b); @@ -61,7 +61,7 @@ async fn test_wide_parallel() { .await .unwrap(); - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), i * 2); } } @@ -70,13 +70,13 @@ async fn test_wide_parallel() { async fn test_diamond_dependency() { let dag = DagRunner::new(); - let a = dag.add_task(task_fn(|_: ()| async { 10 })); + let a: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into(); let b = dag .add_task(task_fn(|x: i32| async move { x + 5 })) - .depends_on(&a); + .depends_on(a); let c = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&a); + .depends_on(a); let d = dag .add_task(task_fn(|(x, y): (i32, i32)| async move { x + y })) .depends_on((&b, &c)); @@ -124,12 +124,12 @@ async fn test_different_output_types() { async fn test_multiple_sinks() { let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { 10 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into(); // Branch 1 let branch1 = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&source); + .depends_on(source); let sink1 = dag .add_task(task_fn(|x: i32| async move { x + 1 })) .depends_on(branch1); @@ -137,7 +137,7 @@ async fn test_multiple_sinks() { // Branch 2 let branch2 = dag .add_task(task_fn(|x: i32| async move { x + 5 })) - .depends_on(&source); + .depends_on(source); let sink2 = dag .add_task(task_fn(|x: i32| async move { x * 3 })) .depends_on(branch2); @@ -156,10 +156,10 @@ async fn test_single_task_inline_path() { let dag = DagRunner::new(); // Single task in its own layer - let t1 = dag.add_task(task_fn(|_: ()| async { 10 })); + let t1: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into(); let t2 = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&t1); + .depends_on(t1); let t3 = dag .add_task(task_fn(|x: i32| async move { x + 5 })) .depends_on(t2); @@ -176,18 +176,18 @@ async fn test_multi_task_spawn_path() { // Test multi-task layer spawn path (line 411-456 in runner.rs) let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { 100 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 100 })).into(); // Create multiple tasks in the same layer (all depend on source) let t1 = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&source); + .depends_on(source); let t2 = dag .add_task(task_fn(|x: i32| async move { x + 2 })) - .depends_on(&source); + .depends_on(source); let t3 = dag .add_task(task_fn(|x: i32| async move { x + 3 })) - .depends_on(&source); + .depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -204,14 +204,16 @@ async fn test_producer_consumer_channels() { let dag = DagRunner::new(); // Producer - let producer = dag.add_task(task_fn(|_: ()| async { vec![1, 2, 3, 4, 5] })); + let producer: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { vec![1, 2, 3, 4, 5] })) + .into(); // Consumer let consumer = dag .add_task(task_fn( |data: Vec| async move { data.iter().sum::() }, )) - .depends_on(&producer); + .depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -225,18 +227,18 @@ async fn test_multi_consumer_fanout() { // Test fanout with multiple consumers from one producer let dag = DagRunner::new(); - let producer = dag.add_task(task_fn(|_: ()| async { 42 })); + let producer: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into(); // Multiple consumers let c1 = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&producer); + .depends_on(producer); let c2 = dag .add_task(task_fn(|x: i32| async move { x + 10 })) - .depends_on(&producer); + .depends_on(producer); let c3 = dag .add_task(task_fn(|x: i32| async move { x - 5 })) - .depends_on(&producer); + .depends_on(producer); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -253,14 +255,14 @@ async fn test_compute_layers_with_dependents_tracking() { let dag = DagRunner::new(); // Create diamond pattern to ensure dependents are tracked correctly - let source = dag.add_task(task_fn(|_: ()| async { 1 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 1 })).into(); let left = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&source); + .depends_on(source); let right = dag .add_task(task_fn(|x: i32| async move { x + 2 })) - .depends_on(&source); + .depends_on(source); let sink = dag .add_task(task_fn(|(l, r): (i32, i32)| async move { l + r })) @@ -301,7 +303,7 @@ async fn test_layer_execution_order() { x + 1 } })) - .depends_on(&t1); + .depends_on(t1); let order3 = execution_order.clone(); let t3 = dag diff --git a/tests/execution/examples.rs b/tests/execution/examples.rs index 79b8abb..a7b2147 100644 --- a/tests/execution/examples.rs +++ b/tests/execution/examples.rs @@ -9,9 +9,9 @@ use futures::FutureExt; async fn test_example_a_fan_out() { let dag = DagRunner::new(); - let base = dag.add_task(Seed::new(10)); // Input=() → no depends_on, returns TaskHandle - let plus1 = dag.add_task(Inc::new()).depends_on(&base); // 11 - let plus2 = dag.add_task(Inc::new()).depends_on(&base); // 11 + let base: TaskHandle<_> = dag.add_task(Seed::new(10)).into(); // Input=() → no depends_on, returns TaskHandle + let plus1 = dag.add_task(Inc::new()).depends_on(base); // 11 + let plus2 = dag.add_task(Inc::new()).depends_on(base); // 11 dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -29,7 +29,7 @@ async fn test_example_b_fan_in() { let n = dag.add_task(task_fn(|_: ()| async { 42usize })); let f = dag.add_task(task_fn(|_: ()| async { true })); - let output = dag.add_task(OutputResult::new()).depends_on((&s, &n, &f)); + let output = dag.add_task(OutputResult::new()).depends_on((s, n, f)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -42,11 +42,11 @@ async fn test_example_c_many_to_many() { let dag = DagRunner::new(); let x = dag.add_task(Seed::new(2)); - let y = dag.add_task(Seed::new(3)); + let y = dag.add_task(Seed::new(3)).into(); let z = dag.add_task(Seed::new(5)); - let sum_xy = dag.add_task(Add::new()).depends_on((&x, &y)); // 5 - let prod_yz = dag.add_task(Mul::new()).depends_on((&y, &z)); // 15 + let sum_xy = dag.add_task(Add::new()).depends_on((x, &y)); // 5 + let prod_yz = dag.add_task(Mul::new()).depends_on((&y, z)); // 15 let total = dag.add_task(Add::new()).depends_on((&sum_xy, &prod_yz)); // 20 dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) @@ -59,12 +59,14 @@ async fn test_example_c_many_to_many() { async fn test_single_input_forms() { let dag = DagRunner::new(); - let s = dag.add_task(task_fn(|_: ()| async { "hello".to_owned() })); + let s = dag + .add_task(task_fn(|_: ()| async { "hello".to_owned() })) + .into(); // Preferred form: &node let upper1 = dag .add_task(task_fn(|s: String| async move { s.to_uppercase() })) - .depends_on(&s); + .depends_on(s); // Also allowed: (&node,) let upper2 = dag diff --git a/tests/execution/integration.rs b/tests/execution/integration.rs index 1aa7955..fe51891 100644 --- a/tests/execution/integration.rs +++ b/tests/execution/integration.rs @@ -59,9 +59,9 @@ async fn integration_test_etl_pipeline() -> DagResult<()> { let source3 = dag.add_task(LoadValue::new(30)); // Transform: Process each source - let transform1 = dag.add_task(Multiply::new(2)).depends_on(&source1); - let transform2 = dag.add_task(Multiply::new(3)).depends_on(&source2); - let transform3 = dag.add_task(Multiply::new(4)).depends_on(&source3); + let transform1 = dag.add_task(Multiply::new(2)).depends_on(source1); + let transform2 = dag.add_task(Multiply::new(3)).depends_on(source2); + let transform3 = dag.add_task(Multiply::new(4)).depends_on(source3); // Load: Aggregate results let combine12 = dag.add_task(Add).depends_on((&transform1, &transform2)); @@ -115,9 +115,9 @@ async fn integration_test_multiple_sinks() -> DagResult<()> { let source = dag.add_task(LoadValue::new(10)); // Multiple independent branches - let branch1 = dag.add_task(Multiply::new(2)).depends_on(&source); - let branch2 = dag.add_task(Multiply::new(3)).depends_on(&source); - let branch3 = dag.add_task(Multiply::new(4)).depends_on(&source); + let branch1 = dag.add_task(Multiply::new(2)).depends_on(source); + let branch2 = dag.add_task(Multiply::new(3)).depends_on(source); + let branch3 = dag.add_task(Multiply::new(4)).depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -136,8 +136,8 @@ async fn integration_test_diamond_cascade() -> DagResult<()> { // Diamond 1 let source1 = dag.add_task(LoadValue::new(10)); - let left1 = dag.add_task(Multiply::new(2)).depends_on(&source1); - let right1 = dag.add_task(Multiply::new(3)).depends_on(&source1); + let left1 = dag.add_task(Multiply::new(2)).depends_on(source1); + let right1 = dag.add_task(Multiply::new(3)).depends_on(source1); let sink1 = dag.add_task(Add).depends_on((&left1, &right1)); // Diamond 2 (depends on Diamond 1) @@ -193,7 +193,7 @@ async fn integration_test_error_recovery() -> DagResult<()> { let dag = DagRunner::new(); let source = dag.add_task(LoadValue::new(42)); - let transform = dag.add_task(Multiply::new(2)).depends_on(&source); + let transform = dag.add_task(Multiply::new(2)).depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -248,9 +248,9 @@ async fn integration_test_reused_values() -> DagResult<()> { let source = dag.add_task(LoadValue::new(100)); // Use source in multiple different ways - let double = dag.add_task(Multiply::new(2)).depends_on(&source); - let triple = dag.add_task(Multiply::new(3)).depends_on(&source); - let quadruple = dag.add_task(Multiply::new(4)).depends_on(&source); + let double = dag.add_task(Multiply::new(2)).depends_on(source); + let triple = dag.add_task(Multiply::new(3)).depends_on(source); + let quadruple = dag.add_task(Multiply::new(4)).depends_on(source); // Combine some of the results let combined = dag.add_task(Add).depends_on((&double, &triple)); @@ -328,7 +328,7 @@ async fn integration_test_parallel_vs_sequential_timing() -> DagResult<()> { sleep(sleep_duration).await; x + 1 })) - .depends_on(¶llel_tasks[0]); + .depends_on(parallel_tasks[0]); let seq2 = dag .add_task(task_fn(move |x: i32| async move { diff --git a/tests/execution/results.rs b/tests/execution/results.rs index e32f4b3..ce0b81f 100644 --- a/tests/execution/results.rs +++ b/tests/execution/results.rs @@ -85,7 +85,7 @@ async fn test_stateful_tasks() { let dag = DagRunner::new(); let input = dag.add_task(task_fn(|_: ()| async { 5 })); - let counter = dag.add_task(Counter::new(10)).depends_on(&input); + let counter = dag.add_task(Counter::new(10)).depends_on(input); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -105,7 +105,7 @@ async fn test_task_fn_with_captured_state() { let base = dag.add_task(task_fn(|_: ()| async { 5 })); let scaled = dag .add_task(task_fn(move |x: i32| async move { x * multiplier })) - .depends_on(&base); + .depends_on(base); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/tests/parallelism/concurrent.rs b/tests/parallelism/concurrent.rs index 3119e4b..d4f4ddf 100644 --- a/tests/parallelism/concurrent.rs +++ b/tests/parallelism/concurrent.rs @@ -47,7 +47,7 @@ async fn test_concurrent_run_calls() { assert_eq!(error_count, 4); // Verify results are consistent from the successful run - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), i); } } @@ -71,7 +71,7 @@ async fn test_concurrent_execution_and_building() { let mut handles = JoinSet::new(); // Reader tasks - for task in &initial { + for task in initial { let dag = Arc::clone(&dag); let task_handle: dagx::TaskHandle = task.into(); handles.spawn(async move { dag.get(task_handle).unwrap() }); @@ -116,7 +116,7 @@ async fn test_dag_builder_thread_safety() { let transform1 = dag .add_task(task_fn(move |x: i32| async move { x * 10 })) - .depends_on(&source); + .depends_on(source); let transform2 = dag .add_task(task_fn(move |x: i32| async move { x + thread_id })) @@ -165,7 +165,7 @@ async fn test_concurrent_get_operations() { // Now access results concurrently let mut handles = JoinSet::new(); - for task in tasks.iter() { + for task in tasks.into_iter() { let dag = Arc::clone(&dag); let task_handle: dagx::TaskHandle = task.into(); handles.spawn(async move { dag.get(task_handle).unwrap() }); @@ -193,7 +193,7 @@ async fn test_no_race_in_dependency_tracking() { let mut handles = JoinSet::new(); // Multiple threads create tasks depending on the same source - let source_handle: dagx::TaskHandle = (&source).into(); + let source_handle: dagx::TaskHandle = source.into(); for i in 0..50 { let dag = Arc::clone(&dag); let source_clone = source_handle; @@ -245,14 +245,14 @@ async fn test_high_concurrency_stress() { // Add a task with a simple dependency let source = dag.add_task(task_fn(move |_: ()| async move { i })); dag.add_task(task_fn(move |x: i32| async move { x * 2 })) - .depends_on(&source); + .depends_on(source); } 2 => { // Add a more complex subgraph let a = dag.add_task(task_fn(move |_: ()| async move { i })); let b = dag.add_task(task_fn(move |_: ()| async move { i + 1 })); dag.add_task(task_fn(move |(x, y): (i32, i32)| async move { x + y })) - .depends_on((&a, &b)); + .depends_on((a, b)); } _ => unreachable!(), } @@ -332,7 +332,7 @@ async fn test_atomic_dag_operations() { let mut handles = JoinSet::new(); let success_count = Arc::new(AtomicUsize::new(0)); - let base_handle: dagx::TaskHandle = (&base).into(); + let base_handle: dagx::TaskHandle = base.into(); for i in 0..50 { let dag = Arc::clone(&dag); let base_clone = base_handle; @@ -382,7 +382,7 @@ async fn test_no_deadlock_on_circular_waiting() { handles.spawn(async move { // Each thread creates a chain of tasks let first = dag.add_task(task_fn(move |_: ()| async move { i })); - let mut chain = vec![(&first).into()]; + let mut chain = vec![first.into()]; for j in 0..5 { let next = dag diff --git a/tests/parallelism/execution.rs b/tests/parallelism/execution.rs index cb63cb8..5dfcbf8 100644 --- a/tests/parallelism/execution.rs +++ b/tests/parallelism/execution.rs @@ -1,7 +1,7 @@ //! Tests for execution correctness and parallelism use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; @@ -32,7 +32,7 @@ async fn test_layers_execute_in_parallel() -> DagResult<()> { // Layer 1: Tasks depending on layer 0 let layer1: Vec<_> = sources - .iter() + .into_iter() .enumerate() .map(|(i, source)| { let timing = layer_timing.clone(); @@ -168,7 +168,7 @@ async fn test_completion_order_matches_dependencies() -> DagResult<()> { x + y } })) - .depends_on((&a, &b)) + .depends_on((a, b)) }; let d = { @@ -216,7 +216,7 @@ async fn test_dependent_tasks_respect_ordering() -> DagResult<()> { let execution_order = Arc::new(Mutex::new(Vec::new())); // Create a chain: A -> B -> C -> D - let a = { + let a: TaskHandle<_> = { let order = execution_order.clone(); dag.add_task(task_fn(move |_: ()| { let order = order.clone(); @@ -226,7 +226,8 @@ async fn test_dependent_tasks_respect_ordering() -> DagResult<()> { 1 } })) - }; + } + .into(); let b = { let order = execution_order.clone(); @@ -238,7 +239,7 @@ async fn test_dependent_tasks_respect_ordering() -> DagResult<()> { x + 1 } })) - .depends_on(&a) + .depends_on(a) }; let c = { diff --git a/tests/parallelism/proof.rs b/tests/parallelism/proof.rs index 98a56e3..77d5db8 100644 --- a/tests/parallelism/proof.rs +++ b/tests/parallelism/proof.rs @@ -29,7 +29,7 @@ async fn test_parallelism_proof_1000_tasks() -> DagResult<()> { let elapsed = start.elapsed(); // Verify all tasks completed - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task)?, i as u32); } diff --git a/tests/parallelism/spawning.rs b/tests/parallelism/spawning.rs index 0bebe59..0273175 100644 --- a/tests/parallelism/spawning.rs +++ b/tests/parallelism/spawning.rs @@ -35,7 +35,7 @@ async fn test_spawner_actually_spawns_tasks() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; // Verify all tasks were spawned - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task)?, i as i32); } @@ -81,7 +81,7 @@ async fn test_tasks_not_running_inline() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; // Verify results - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task)?, i as i32); } diff --git a/tests/parallelism/threads.rs b/tests/parallelism/threads.rs index 0b7e5d1..39b8743 100644 --- a/tests/parallelism/threads.rs +++ b/tests/parallelism/threads.rs @@ -1,7 +1,7 @@ //! Tests for multi-threading and concurrent execution use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -44,7 +44,7 @@ async fn test_tasks_run_on_different_threads() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; // Verify all tasks completed - for task in tasks.iter() { + for task in tasks.into_iter() { let _ = dag.get(task)?; } @@ -113,7 +113,7 @@ async fn test_concurrent_execution_with_atomic_counter() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; // Verify all tasks completed - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task)?, i); } @@ -141,7 +141,7 @@ async fn test_diamond_parallel_execution() -> DagResult<()> { let concurrent_middle = Arc::new(AtomicUsize::new(0)); - let source = dag.add_task(task_fn(|_: ()| async { 100 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 100 })).into(); // These should run in parallel let parallel1 = { @@ -157,7 +157,7 @@ async fn test_diamond_parallel_execution() -> DagResult<()> { x * 2 } })) - .depends_on(&source) + .depends_on(source) }; let parallel2 = { @@ -174,7 +174,7 @@ async fn test_diamond_parallel_execution() -> DagResult<()> { x * 3 } })) - .depends_on(&source) + .depends_on(source) }; let sink = dag @@ -196,7 +196,7 @@ async fn test_parallel_branches_with_dependencies() -> DagResult<()> { let branch_progress = Arc::new(Mutex::new(Vec::new())); // Source node - let source = dag.add_task(task_fn(|_: ()| async { 10 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into(); // Branch 1: source -> b1_1 -> b1_2 let b1_1 = { @@ -213,7 +213,7 @@ async fn test_parallel_branches_with_dependencies() -> DagResult<()> { x * 2 } })) - .depends_on(&source) + .depends_on(source) }; let b1_2 = { @@ -248,7 +248,7 @@ async fn test_parallel_branches_with_dependencies() -> DagResult<()> { x * 3 } })) - .depends_on(&source) + .depends_on(source) }; let b2_2 = { @@ -320,7 +320,7 @@ async fn test_wide_fanout_parallel_execution() -> DagResult<()> { let max_concurrent = Arc::new(AtomicUsize::new(0)); let current_concurrent = Arc::new(AtomicUsize::new(0)); - let source = dag.add_task(task_fn(|_: ()| async { 42 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into(); // Create 50 tasks that all depend on the source let dependents: Vec<_> = (0..50) @@ -356,7 +356,7 @@ async fn test_wide_fanout_parallel_execution() -> DagResult<()> { x + i } })) - .depends_on(&source) + .depends_on(source) }) .collect(); @@ -388,7 +388,7 @@ async fn test_massive_parallel_fanout() -> DagResult<()> { let max_concurrent = Arc::new(AtomicUsize::new(0)); let current = Arc::new(AtomicUsize::new(0)); - let source = dag.add_task(task_fn(|_: ()| async { 1 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 1 })).into(); // Create 1000 tasks all depending on the same source let tasks: Vec<_> = (0..1000) @@ -426,7 +426,7 @@ async fn test_massive_parallel_fanout() -> DagResult<()> { x + i } })) - .depends_on(&source) + .depends_on(source) }) .collect(); diff --git a/tests/parallelism/timing.rs b/tests/parallelism/timing.rs index c388cc6..1cba4ea 100644 --- a/tests/parallelism/timing.rs +++ b/tests/parallelism/timing.rs @@ -2,7 +2,7 @@ use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::Arc; use std::sync::Mutex; @@ -32,7 +32,7 @@ async fn test_parallel_execution_speedup() -> DagResult<()> { let elapsed = start.elapsed(); // Verify all tasks completed - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task)?, i); } @@ -84,15 +84,15 @@ async fn test_sync_tasks_dont_block_async_runtime() -> DagResult<()> { let start_times = Arc::new(Mutex::new(Vec::new())); // Mix of sync and async tasks - let source = dag.add_task(task_fn(|_: ()| async { 10 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into(); // Sync tasks - let sync1 = dag.add_task(SyncTask).depends_on(&source); - let sync2 = dag.add_task(SyncTask).depends_on(&source); + let sync1 = dag.add_task(SyncTask).depends_on(source); + let sync2 = dag.add_task(SyncTask).depends_on(source); // Async tasks - let async1 = dag.add_task(AsyncTask).depends_on(&source); - let async2 = dag.add_task(AsyncTask).depends_on(&source); + let async1 = dag.add_task(AsyncTask).depends_on(source); + let async2 = dag.add_task(AsyncTask).depends_on(source); // Track timing let timing_task = { diff --git a/tests/patterns/butterfly.rs b/tests/patterns/butterfly.rs index 81aa07a..17d26e5 100644 --- a/tests/patterns/butterfly.rs +++ b/tests/patterns/butterfly.rs @@ -1,7 +1,7 @@ //! Butterfly pattern DAG tests use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -13,7 +13,10 @@ async fn test_butterfly_network() -> DagResult<()> { // Simplified butterfly network - avoid tuples entirely // Layer 0: inputs let inputs: Vec<_> = (0..8) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { i as f64 }))) + .map(|i| { + dag.add_task(task_fn(move |_: ()| async move { i as f64 })) + .into() + }) .collect(); // Layer 1: butterfly operations (compute pairs separately) @@ -92,7 +95,7 @@ async fn test_recursive_butterfly() -> DagResult<()> { .into_iter() .map(|val| { let task = dag.add_task(task_fn(move |_: ()| async move { val })); - (&task).into() + task.into() }) .collect(); @@ -115,7 +118,10 @@ async fn test_benes_network() -> DagResult<()> { // 4 inputs let inputs: Vec<_> = (0..4) - .map(|i| dag.add_task(task_fn(move |_: ()| async move { 1 << i }))) // Powers of 2 + .map(|i| { + dag.add_task(task_fn(move |_: ()| async move { 1 << i })) + .into() + }) // Powers of 2 .collect(); // First stage: sort pairs @@ -153,7 +159,7 @@ async fn test_shuffle_exchange_network() -> DagResult<()> { let counter = Arc::new(AtomicUsize::new(0)); // Create 8 inputs - let inputs: Vec<_> = (0..8) + let inputs: Vec> = (0..8) .map(|i| { let counter = counter.clone(); dag.add_task(task_fn(move |_: ()| { @@ -163,6 +169,7 @@ async fn test_shuffle_exchange_network() -> DagResult<()> { i } })) + .into() }) .collect(); @@ -172,7 +179,7 @@ async fn test_shuffle_exchange_network() -> DagResult<()> { // Shuffle pattern: rotate bits let source = ((i << 1) | (i >> 2)) & 0x7; dag.add_task(task_fn(move |x: i32| async move { x })) - .depends_on(&inputs[source]) + .depends_on(inputs[source]) }) .collect(); diff --git a/tests/patterns/complex.rs b/tests/patterns/complex.rs index abb6c86..f052eac 100644 --- a/tests/patterns/complex.rs +++ b/tests/patterns/complex.rs @@ -1,7 +1,7 @@ //! Complex DAG pattern tests use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -21,7 +21,7 @@ async fn test_workflow_with_conditional_paths() -> DagResult<()> { Err("Invalid input") } })) - .depends_on(&input); + .depends_on(input); // Process valid input let process = dag @@ -31,7 +31,7 @@ async fn test_workflow_with_conditional_paths() -> DagResult<()> { Err(_) => -1, } })) - .depends_on(&validate); + .depends_on(validate); // Parallel enhancement steps let enhance1 = dag @@ -80,7 +80,7 @@ async fn test_map_reduce_pattern() -> DagResult<()> { // Simulate word count vec![("word1", i % 3), ("word2", i % 5), ("word3", i % 7)] })); - (&task).into() + task.into() }) .collect(); @@ -166,7 +166,7 @@ async fn test_pipeline_with_feedback() -> DagResult<()> { } } })) - .depends_on(&init); + .depends_on(init); // Stage 2: Filter let stage2 = dag @@ -209,9 +209,11 @@ async fn test_scatter_gather_pattern() -> DagResult<()> { let dag = DagRunner::new(); // Scatter: distribute work to multiple workers - let source = dag.add_task(task_fn(|_: ()| async { - vec![10, 20, 30, 40, 50, 60, 70, 80] - })); + let source: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { + vec![10, 20, 30, 40, 50, 60, 70, 80] + })) + .into(); // Workers process chunks let workers: Vec<_> = (0..4) @@ -228,7 +230,7 @@ async fn test_scatter_gather_pattern() -> DagResult<()> { data[start..end].iter().sum::() })) - .depends_on(&source) + .depends_on(source) }) .collect(); @@ -266,7 +268,7 @@ async fn test_fork_join_with_barriers() -> DagResult<()> { // Multiple parallel paths let mut path1 = Vec::new(); - let parent_handle: dagx::TaskHandle = (&parent).into(); + let parent_handle: dagx::TaskHandle = parent.into(); let mut prev1 = parent_handle; for i in 0..3 { let counter = phase_counter.clone(); diff --git a/tests/patterns/grid.rs b/tests/patterns/grid.rs index 11fdd74..27c8c8e 100644 --- a/tests/patterns/grid.rs +++ b/tests/patterns/grid.rs @@ -15,10 +15,10 @@ async fn test_2d_grid_pattern() -> DagResult<()> { #[allow(clippy::needless_range_loop)] for i in 0..4 { let task = dag.add_task(task_fn(move |_: ()| async move { i as i32 })); - grid[0][i] = Some((&task).into()); + grid[0][i] = Some(task.into()); if i > 0 { let task = dag.add_task(task_fn(move |_: ()| async move { i as i32 * 10 })); - grid[i][0] = Some((&task).into()); + grid[i][0] = Some(task.into()); } } @@ -55,7 +55,7 @@ async fn test_3d_grid_pattern() -> DagResult<()> { // Initialize origin let origin = dag.add_task(task_fn(|_: ()| async { 1 })); - grid[0][0][0] = Some((&origin).into()); + grid[0][0][0] = Some(origin.into()); // Fill the 3D grid for x in 0..size { @@ -77,7 +77,7 @@ async fn test_3d_grid_pattern() -> DagResult<()> { let task_handle: dagx::TaskHandle = match deps.len() { 0 => { let t = dag.add_task(task_fn(move |_: ()| async move { x + y + z })); - (&t).into() + t.into() } 1 => dag .add_task(task_fn(move |prev: usize| async move { prev + 1 })) @@ -121,7 +121,7 @@ async fn test_hexagonal_grid() -> DagResult<()> { // Center hex let center_builder = dag.add_task(task_fn(|_: ()| async { 100 })); - let center: dagx::TaskHandle = (¢er_builder).into(); + let center: dagx::TaskHandle = center_builder.into(); hex_grid.insert((0, 0), center); // Ring 1 (6 hexes around center) @@ -168,7 +168,7 @@ async fn test_hexagonal_grid() -> DagResult<()> { .depends_on(neighbors[0]) } else { let t = dag.add_task(task_fn(move |_: ()| async move { q + r })); - (&t).into() + t.into() }; hex_grid.insert((q, r), task); @@ -194,7 +194,7 @@ async fn test_toroidal_grid() -> DagResult<()> { for i in 0..SIZE { for j in 0..SIZE { let task = dag.add_task(task_fn(move |_: ()| async move { (i * SIZE + j) as i32 })); - grid[i][j] = Some((&task).into()); + grid[i][j] = Some(task.into()); } } diff --git a/tests/patterns/tree.rs b/tests/patterns/tree.rs index 448b004..a970d60 100644 --- a/tests/patterns/tree.rs +++ b/tests/patterns/tree.rs @@ -1,7 +1,7 @@ //! Tree pattern DAG tests use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; #[tokio::test] @@ -15,7 +15,7 @@ async fn test_binary_tree_reduction() -> DagResult<()> { // Build binary tree reduction let mut current_level: Vec> = - leaves.into_iter().map(|t| (&t).into()).collect(); + leaves.into_iter().map(|t| t.into()).collect(); while current_level.len() > 1 { let mut next_level = Vec::new(); @@ -52,7 +52,7 @@ async fn test_n_ary_tree() -> DagResult<()> { fn build_tree(dag: &DagRunner, depth: usize, value: i32) -> dagx::TaskHandle { if depth == 0 { let task = dag.add_task(task_fn(move |_: ()| async move { value })); - return (&task).into(); + return task.into(); } let children: Vec<_> = (0..3) @@ -88,19 +88,19 @@ async fn test_unbalanced_tree() -> DagResult<()> { // / \ // f g - let f = dag.add_task(task_fn(|_: ()| async { 1 })); + let f: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 1 })).into(); let g = dag.add_task(task_fn(|_: ()| async { 2 })); let c = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&f); + .depends_on(f); let d_builder = dag.add_task(task_fn(|_: ()| async { 3 })); - let d: dagx::TaskHandle = (&d_builder).into(); + let d: dagx::TaskHandle = d_builder.into(); let e = dag .add_task(task_fn(|x: i32| async move { x * 3 })) - .depends_on(&g); + .depends_on(g); let a = dag .add_task(task_fn(|(c, d): (i32, i32)| async move { c + d })) @@ -116,7 +116,7 @@ async fn test_unbalanced_tree() -> DagResult<()> { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; - assert_eq!(dag.get(&f)?, 1); + assert_eq!(dag.get(f)?, 1); assert_eq!(dag.get(c)?, 2); assert_eq!(dag.get(a)?, 5); // 2 + 3 assert_eq!(dag.get(b)?, 16); // 6 + 10 @@ -130,20 +130,22 @@ async fn test_trie_like_structure() -> DagResult<()> { let dag = DagRunner::new(); // Build a trie-like structure for paths - let root = dag.add_task(task_fn(|_: ()| async { "root".to_string() })); + let root: TaskHandle<_> = dag + .add_task(task_fn(|_: ()| async { "root".to_string() })) + .into(); // First level let usr = dag .add_task(task_fn(|r: String| async move { format!("{}/usr", r) })) - .depends_on(&root); + .depends_on(root); let etc = dag .add_task(task_fn(|r: String| async move { format!("{}/etc", r) })) - .depends_on(&root); + .depends_on(root); let var = dag .add_task(task_fn(|r: String| async move { format!("{}/var", r) })) - .depends_on(&root); + .depends_on(root); // Second level let usr_bin = dag @@ -188,7 +190,7 @@ async fn test_balanced_k_ary_tree() -> DagResult<()> { ) -> dagx::TaskHandle { if depth == 0 { let task = dag.add_task(task_fn(move |_: ()| async move { node_id })); - return (&task).into(); + return task.into(); } let children: Vec<_> = (0..k) @@ -243,7 +245,7 @@ async fn test_merkle_tree_pattern() -> DagResult<()> { // Convert to TaskHandles let mut current_level: Vec> = - data_blocks.into_iter().map(|t| (&t).into()).collect(); + data_blocks.into_iter().map(|t| t.into()).collect(); while current_level.len() > 1 { let mut next_level = Vec::new(); diff --git a/tests/performance/memory.rs b/tests/performance/memory.rs index 6528461..6f5c49c 100644 --- a/tests/performance/memory.rs +++ b/tests/performance/memory.rs @@ -14,7 +14,7 @@ async fn test_memory_usage_10000_nodes() { let before_build = memory_usage_hint(); // Create 10,000 nodes - let tasks: Vec<_> = (0..10_000) + let mut tasks: Vec<_> = (0..10_000) .map(|i| dag.add_task(task_fn(move |_: ()| async move { i }))) .collect(); @@ -34,8 +34,8 @@ async fn test_memory_usage_10000_nodes() { println!("Additional memory for execution: ~{} bytes", exec_memory); // Verify some results - assert_eq!(dag.get(&tasks[0]).unwrap(), 0); - assert_eq!(dag.get(&tasks[9999]).unwrap(), 9999); + assert_eq!(dag.get(tasks.swap_remove(9999)).unwrap(), 9999); + assert_eq!(dag.get(tasks.swap_remove(0)).unwrap(), 0); // Memory should be reasonable (< 100MB for 10k simple nodes) assert!( diff --git a/tests/performance/stress.rs b/tests/performance/stress.rs index 1fa63a1..6f96275 100644 --- a/tests/performance/stress.rs +++ b/tests/performance/stress.rs @@ -13,7 +13,7 @@ async fn test_deep_chain_100_levels() { // Create a chain 100 levels deep let start = Instant::now(); let first = dag.add_task(task_fn(|_: ()| async { 0 })); - let mut handles = vec![(&first).into()]; + let mut handles = vec![first.into()]; for _ in 1..=100 { let next = dag @@ -52,7 +52,7 @@ async fn test_stress_mixed_patterns() { for i in 0..10 { // Linear chains let first = dag.add_task(task_fn(move |_: ()| async move { i * 1000 })); - let mut chain_handles = vec![(&first).into()]; + let mut chain_handles = vec![first.into()]; for j in 1..10 { let next = dag .add_task(task_fn(move |x: i32| async move { x + j })) @@ -63,7 +63,7 @@ async fn test_stress_mixed_patterns() { // Diamonds let source = dag.add_task(task_fn(move |_: ()| async move { i * 100 })); - let source_handle: dagx::TaskHandle = (&source).into(); + let source_handle: dagx::TaskHandle = source.into(); let left = dag .add_task(task_fn(|x: i32| async move { x * 2 })) .depends_on(source_handle); @@ -77,7 +77,7 @@ async fn test_stress_mixed_patterns() { // Fan-outs let hub = dag.add_task(task_fn(move |_: ()| async move { i })); - let hub_handle: dagx::TaskHandle = (&hub).into(); + let hub_handle: dagx::TaskHandle = hub.into(); for j in 0..5 { let fan = dag .add_task(task_fn(move |x: i32| async move { x + j * 10 })) diff --git a/tests/runtimes/async_std.rs b/tests/runtimes/async_std.rs index 56b6915..028e15d 100644 --- a/tests/runtimes/async_std.rs +++ b/tests/runtimes/async_std.rs @@ -25,7 +25,7 @@ async fn test_basic_dag_async_std() { let x = dag.add_task(Value(2)); let y = dag.add_task(Value(3)); - let sum = dag.add_task(Add).depends_on((&x, &y)); + let sum = dag.add_task(Add).depends_on((x, y)); dag.run(async_std::task::spawn).await.unwrap(); @@ -42,7 +42,7 @@ async fn test_parallel_execution_async_std() { dag.run(async_std::task::spawn).await.unwrap(); - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), i * 2); } } @@ -53,7 +53,7 @@ async fn test_complex_dependencies_async_std() { let a = dag.add_task(Value(10)); let b = dag.add_task(Value(20)); - let sum = dag.add_task(Add).depends_on((&a, &b)); + let sum = dag.add_task(Add).depends_on((a, b)); let double = dag .add_task(task_fn(|x: i32| async move { x * 2 })) .depends_on(sum); diff --git a/tests/runtimes/compatibility.rs b/tests/runtimes/compatibility.rs index be48b56..dd206af 100644 --- a/tests/runtimes/compatibility.rs +++ b/tests/runtimes/compatibility.rs @@ -25,7 +25,7 @@ async fn runtime_integration_tokio() -> DagResult<()> { let a = dag.add_task(Value(10)); let b = dag.add_task(Value(20)); - let sum = dag.add_task(Add).depends_on((&a, &b)); + let sum = dag.add_task(Add).depends_on((a, b)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; diff --git a/tests/runtimes/quirky.rs b/tests/runtimes/quirky.rs index 6e8f0f4..9bf6a1a 100644 --- a/tests/runtimes/quirky.rs +++ b/tests/runtimes/quirky.rs @@ -14,7 +14,7 @@ #![allow(unused_must_use)] use crate::common::task_fn; -use dagx::DagRunner; +use dagx::{DagRunner, TaskHandle}; use futures::task::SpawnExt; use futures_executor::ThreadPool; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -36,7 +36,7 @@ fn test_async_executor_basic() { let y = dag.add_task(task_fn(|_: ()| async { 20 })); let sum = dag .add_task(task_fn(|(a, b): (i32, i32)| async move { a + b })) - .depends_on((&x, &y)); + .depends_on((x, y)); dag.run(|fut| executor.spawn(fut)).await.unwrap(); @@ -54,15 +54,15 @@ fn test_async_executor_complex_dag() { let dag = DagRunner::new(); // Create a diamond pattern - let source = dag.add_task(task_fn(|_: ()| async { 5 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 5 })).into(); let left = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&source); + .depends_on(source); let right = dag .add_task(task_fn(|x: i32| async move { x * 3 })) - .depends_on(&source); + .depends_on(source); let sink = dag .add_task(task_fn(|(l, r): (i32, i32)| async move { l + r })) @@ -104,7 +104,7 @@ fn test_async_executor_parallel_tasks() { assert_eq!(counter.load(Ordering::SeqCst), 10); // Verify results - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), i as i32); } }; @@ -141,7 +141,7 @@ fn test_async_executor_deep_chain() { let start = dag.add_task(task_fn(|_: ()| async { 0 })); let mut current = dag .add_task(task_fn(|x: i32| async move { x + 1 })) - .depends_on(&start); + .depends_on(start); for _ in 1..50 { current = dag @@ -170,7 +170,7 @@ fn test_pollster_basic() { let x = dag.add_task(task_fn(|_: ()| async { 100 })); let doubled = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&x); + .depends_on(x); dag.run(|fut| async { pollster::block_on(fut) }) .await @@ -186,12 +186,12 @@ fn test_pollster_complex() { let dag = DagRunner::new(); // Fan-out pattern - let source = dag.add_task(task_fn(|_: ()| async { 7 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 7 })).into(); let tasks: Vec<_> = (0..5) .map(|i| { dag.add_task(task_fn(move |x: i32| async move { x * i })) - .depends_on(&source) + .depends_on(source) }) .collect(); @@ -234,7 +234,7 @@ fn test_futures_executor_basic() { let y = dag.add_task(task_fn(|_: ()| async { 25 })); let product = dag .add_task(task_fn(|(a, b): (i32, i32)| async move { a * b })) - .depends_on((&x, &y)); + .depends_on((x, y)); let spawner = ThreadPool::new().unwrap(); @@ -263,7 +263,7 @@ fn test_futures_executor_threadpool() { .await .unwrap(); - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), (i * i) as i32); } }); @@ -281,15 +281,15 @@ fn test_futures_executor_diamond_pattern() { futures_executor::block_on(async { let dag = DagRunner::new(); - let a = dag.add_task(task_fn(|_: ()| async { 8 })); + let a: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 8 })).into(); let b = dag .add_task(task_fn(|x: i32| async move { x + 2 })) - .depends_on(&a); + .depends_on(a); let c = dag .add_task(task_fn(|x: i32| async move { x - 2 })) - .depends_on(&a); + .depends_on(a); let d = dag .add_task(task_fn(|(x, y): (i32, i32)| async move { x * y })) @@ -395,7 +395,7 @@ fn test_async_executor_stress() { dag.run(|fut| executor.spawn(fut)).await.unwrap(); - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), i as i32); } }); @@ -461,7 +461,7 @@ fn test_sync_tasks_on_async_executor() { let x = dag.add_task(task_fn(|_: ()| async { 5 })); let y = dag.add_task(task_fn(|_: ()| async { 7 })); - let sum = dag.add_task(SyncAdd).depends_on((&x, &y)); + let sum = dag.add_task(SyncAdd).depends_on((x, y)); dag.run(|fut| executor.spawn(fut)).await.unwrap(); @@ -484,7 +484,7 @@ fn test_sync_tasks_on_pollster() { let dag = DagRunner::new(); let x = dag.add_task(task_fn(|_: ()| async { 21 })); - let doubled = dag.add_task(SyncDouble).depends_on(&x); + let doubled = dag.add_task(SyncDouble).depends_on(x); dag.run(|fut| async { pollster::block_on(fut) }) .await diff --git a/tests/runtimes/smol.rs b/tests/runtimes/smol.rs index 5351266..6d6ad27 100644 --- a/tests/runtimes/smol.rs +++ b/tests/runtimes/smol.rs @@ -26,7 +26,7 @@ fn test_basic_dag_smol() { let x = dag.add_task(Value(2)); let y = dag.add_task(Value(3)); - let sum = dag.add_task(Add).depends_on((&x, &y)); + let sum = dag.add_task(Add).depends_on((x, y)); dag.run(smol::spawn).await.unwrap(); @@ -45,7 +45,7 @@ fn test_parallel_execution_smol() { dag.run(smol::spawn).await.unwrap(); - for (i, task) in tasks.iter().enumerate() { + for (i, task) in tasks.into_iter().enumerate() { assert_eq!(dag.get(task).unwrap(), i * 2); } }); @@ -58,7 +58,7 @@ fn test_complex_dependencies_smol() { let a = dag.add_task(Value(10)); let b = dag.add_task(Value(20)); - let sum = dag.add_task(Add).depends_on((&a, &b)); + let sum = dag.add_task(Add).depends_on((a, b)); let double = dag .add_task(task_fn(|x: i32| async move { x * 2 })) .depends_on(sum); diff --git a/tests/task_patterns/combined.rs b/tests/task_patterns/combined.rs index e7126f4..e670fbb 100644 --- a/tests/task_patterns/combined.rs +++ b/tests/task_patterns/combined.rs @@ -45,7 +45,7 @@ async fn test_all_three_task_patterns() { let y = dag.add_task(task_fn(|_: ()| async { 3 })); // Pattern 1: Stateless addition - let sum = dag.add_task(StatelessAdd).depends_on((&x, &y)); // 5 + 3 = 8 + let sum = dag.add_task(StatelessAdd).depends_on((x, y)); // 5 + 3 = 8 // Pattern 2: Read-only multiplication let doubled = dag.add_task(ReadOnlyMultiplier(2)).depends_on(sum); // 8 * 2 = 16 @@ -102,9 +102,9 @@ async fn test_parallel_execution() { // All three tasks should have run assert_eq!(counter.load(Ordering::SeqCst), 3); - assert_eq!(dag.get(&t1).unwrap(), 1); - assert_eq!(dag.get(&t2).unwrap(), 2); - assert_eq!(dag.get(&t3).unwrap(), 3); + assert_eq!(dag.get(t1).unwrap(), 1); + assert_eq!(dag.get(t2).unwrap(), 2); + assert_eq!(dag.get(t3).unwrap(), 3); } #[tokio::test] @@ -115,7 +115,7 @@ async fn test_task_fn_with_captured_state() { let base = dag.add_task(task_fn(|_: ()| async { 5 })); let scaled = dag .add_task(task_fn(move |x: i32| async move { x * multiplier })) - .depends_on(&base); + .depends_on(base); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/tests/task_patterns/readonly.rs b/tests/task_patterns/readonly.rs index f2407b1..0764c3f 100644 --- a/tests/task_patterns/readonly.rs +++ b/tests/task_patterns/readonly.rs @@ -55,7 +55,7 @@ async fn test_readonly_state_with_input() { let dag = DagRunner::new(); let input = dag.add_task(task_fn(|_: ()| async { 5 })); - let result = dag.add_task(ReadOnlyMultiplier(7)).depends_on(&input); + let result = dag.add_task(ReadOnlyMultiplier(7)).depends_on(input); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -76,13 +76,13 @@ async fn test_readonly_state_multiple_uses() { offset: 5, }; - let result1 = dag.add_task(config).depends_on(&input1); + let result1 = dag.add_task(config).depends_on(input1); // Note: Can't reuse config because it was moved, so create another let config2 = ReadOnlyConfig { multiplier: 3, offset: 5, }; - let result2 = dag.add_task(config2).depends_on(&input2); + let result2 = dag.add_task(config2).depends_on(input2); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/tests/task_patterns/stateless.rs b/tests/task_patterns/stateless.rs index 9b7fc84..912f087 100644 --- a/tests/task_patterns/stateless.rs +++ b/tests/task_patterns/stateless.rs @@ -84,7 +84,7 @@ async fn test_stateless_basic() { let x = dag.add_task(task_fn(|_: ()| async { 10 })); let y = dag.add_task(task_fn(|_: ()| async { 20 })); - let sum = dag.add_task(StatelessAdd).depends_on((&x, &y)); + let sum = dag.add_task(StatelessAdd).depends_on((x, y)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -98,7 +98,7 @@ async fn test_stateless_single_input() { let dag = DagRunner::new(); let input = dag.add_task(task_fn(|_: ()| async { 21 })); - let doubled = dag.add_task(StatelessDouble).depends_on(&input); + let doubled = dag.add_task(StatelessDouble).depends_on(input); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -128,9 +128,7 @@ async fn test_stateless_multiple_inputs() { let text = dag.add_task(task_fn(|_: ()| async { "test".to_string() })); let flag = dag.add_task(task_fn(|_: ()| async { true })); - let result = dag - .add_task(StatelessFormat) - .depends_on((&num, &text, &flag)); + let result = dag.add_task(StatelessFormat).depends_on((num, text, flag)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -166,7 +164,7 @@ async fn test_stateless_mixed_with_stateful() { let y = dag.add_task(task_fn(|_: ()| async { 3 })); // Stateless multiplication - let product = dag.add_task(StatelessMultiply).depends_on((&x, &y)); + let product = dag.add_task(StatelessMultiply).depends_on((x, y)); // Stateful counter let counted = dag.add_task(Counter::new(10)).depends_on(product); @@ -185,7 +183,7 @@ async fn test_stateless_chain() { let dag = DagRunner::new(); let start = dag.add_task(task_fn(|_: ()| async { 0 })); - let step1 = dag.add_task(StatelessInc).depends_on(&start); + let step1 = dag.add_task(StatelessInc).depends_on(start); let step2 = dag.add_task(StatelessInc).depends_on(step1); let step3 = dag.add_task(StatelessInc).depends_on(step2); @@ -206,7 +204,7 @@ async fn test_stateless_parallel() { let tasks: Vec<_> = (1..=5) .map(|i| { let source = dag.add_task(task_fn(move |_: ()| async move { i })); - dag.add_task(StatelessSquare).depends_on(&source) + dag.add_task(StatelessSquare).depends_on(source) }) .collect(); @@ -229,7 +227,7 @@ async fn test_stateless_with_string_types() { let hello = dag.add_task(task_fn(|_: ()| async { "Hello, ".to_string() })); let world = dag.add_task(task_fn(|_: ()| async { "World!".to_string() })); - let greeting = dag.add_task(StatelessConcat).depends_on((&hello, &world)); + let greeting = dag.add_task(StatelessConcat).depends_on((hello, world)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/tests/timing/concurrent_access.rs b/tests/timing/concurrent_access.rs index 641ea9e..bc72735 100644 --- a/tests/timing/concurrent_access.rs +++ b/tests/timing/concurrent_access.rs @@ -1,7 +1,7 @@ //! Tests for concurrent access patterns and race conditions use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; @@ -19,7 +19,7 @@ async fn test_concurrent_result_retrieval() -> DagResult<()> { tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; i as usize })); - (&task).into() + task.into() }) .collect(); @@ -64,7 +64,7 @@ async fn test_simultaneous_dag_building_and_execution() -> DagResult<()> { let mut tasks: Vec> = Vec::new(); for i in 5..50 { let task = dag_build.add_task(task_fn(move |_: ()| async move { i })); - tasks.push((&task).into()); + tasks.push(task.into()); tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; } building.store(true, Ordering::SeqCst); @@ -81,7 +81,7 @@ async fn test_simultaneous_dag_building_and_execution() -> DagResult<()> { let additional_tasks = build_handle.await.unwrap(); // Initial tasks should have results - for (i, task) in initial.iter().enumerate() { + for (i, task) in initial.into_iter().enumerate() { assert_eq!(dag.get(task)?, i); } @@ -107,16 +107,18 @@ async fn test_concurrent_dependency_resolution() -> DagResult<()> { let resolution_counter = Arc::new(AtomicUsize::new(0)); // Create a source task - let source = dag.add_task(task_fn({ - let counter = resolution_counter.clone(); - move |_: ()| { - let counter = counter.clone(); - async move { - counter.fetch_add(1, Ordering::SeqCst); - 42 + let source: TaskHandle<_> = dag + .add_task(task_fn({ + let counter = resolution_counter.clone(); + move |_: ()| { + let counter = counter.clone(); + async move { + counter.fetch_add(1, Ordering::SeqCst); + 42 + } } - } - })); + })) + .into(); // Create many tasks depending on the same source let dependents: Vec<_> = (0..100) @@ -129,7 +131,7 @@ async fn test_concurrent_dependency_resolution() -> DagResult<()> { val + i } })) - .depends_on(&source) + .depends_on(source) }) .collect(); @@ -166,6 +168,7 @@ async fn test_read_write_race_patterns() -> DagResult<()> { i } })) + .into() }) .collect(); @@ -284,7 +287,7 @@ async fn test_multiple_dag_runners_interaction() -> DagResult<()> { // Collect results let mut results = Vec::new(); for task in tasks { - results.push(dag.get(&task)?); + results.push(dag.get(task)?); } Ok::<_, dagx::DagError>(results) diff --git a/tests/timing/interleaving.rs b/tests/timing/interleaving.rs index 4cf8d50..867c204 100644 --- a/tests/timing/interleaving.rs +++ b/tests/timing/interleaving.rs @@ -1,7 +1,7 @@ //! Tests for forced execution interleaving patterns use crate::common::task_fn; -use dagx::{DagResult, DagRunner}; +use dagx::{DagResult, DagRunner, TaskHandle}; use futures::FutureExt; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -65,7 +65,7 @@ async fn test_forced_interleaving_with_barriers() -> DagResult<()> { .add_task(task_fn( |(a, b, c): (i32, i32, i32)| async move { a + b + c }, )) - .depends_on((&t1, &t2, &t3)); + .depends_on((t1, t2, t3)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; @@ -110,7 +110,7 @@ async fn test_alternating_execution_pattern() -> DagResult<()> { } } })); - let mut chain_a: dagx::TaskHandle = (&first_a).into(); + let mut chain_a: dagx::TaskHandle = first_a.into(); let first_b = dag.add_task(task_fn({ let turn = turn.clone(); @@ -128,7 +128,7 @@ async fn test_alternating_execution_pattern() -> DagResult<()> { } } })); - let mut chain_b: dagx::TaskHandle = (&first_b).into(); + let mut chain_b: dagx::TaskHandle = first_b.into(); for i in 1..5 { let turn_clone = turn.clone(); @@ -197,6 +197,7 @@ async fn test_layered_interleaving() -> DagResult<()> { i as i32 } })) + .into() }) .collect(); @@ -250,19 +251,21 @@ async fn test_cross_branch_synchronization() -> DagResult<()> { let events = Arc::new(parking_lot::Mutex::new(Vec::new())); // Branch A - let a1 = dag.add_task(task_fn({ - let sync = sync_point.clone(); - let events = events.clone(); - move |_: ()| { - let sync = sync.clone(); + let a1: TaskHandle<_> = dag + .add_task(task_fn({ + let sync = sync_point.clone(); let events = events.clone(); - async move { - events.lock().push("A1"); - sync.fetch_add(1, Ordering::SeqCst); - 1 + move |_: ()| { + let sync = sync.clone(); + let events = events.clone(); + async move { + events.lock().push("A1"); + sync.fetch_add(1, Ordering::SeqCst); + 1 + } } - } - })); + })) + .into(); let a2 = dag .add_task(task_fn({ @@ -282,7 +285,7 @@ async fn test_cross_branch_synchronization() -> DagResult<()> { } } })) - .depends_on(&a1); + .depends_on(a1); // Branch B let b1 = dag.add_task(task_fn({ @@ -320,7 +323,7 @@ async fn test_cross_branch_synchronization() -> DagResult<()> { } } })) - .depends_on(&b1); + .depends_on(b1); // Merge let merge = dag diff --git a/tests/tracing/with_tracing.rs b/tests/tracing/with_tracing.rs index f6d9d9c..1ef3d88 100644 --- a/tests/tracing/with_tracing.rs +++ b/tests/tracing/with_tracing.rs @@ -43,7 +43,7 @@ async fn test_tracing_with_subscriber() { let a = dag.add_task(Value(2)); let b = dag.add_task(Value(3)); - let sum = dag.add_task(Add).depends_on((&a, &b)); + let sum = dag.add_task(Add).depends_on((a, b)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -63,7 +63,7 @@ async fn test_tracing_with_complex_dag() { let dag = DagRunner::new(); // Create a diamond pattern - let source = dag.add_task(Value(10)); + let source = dag.add_task(Value(10)).into(); let left = dag.add_task(Add).depends_on((&source, &source)); let right = dag.add_task(Multiply).depends_on((&source, &source)); let sink = dag.add_task(Add).depends_on((&left, &right)); @@ -90,7 +90,7 @@ async fn test_tracing_inline_execution() { let dag = DagRunner::new(); // Create a linear chain (should trigger inline execution) - let a = dag.add_task(Value(1)); + let a = dag.add_task(Value(1)).into(); let b = dag.add_task(Add).depends_on((&a, &a)); let c = dag.add_task(Multiply).depends_on((&b, &b)); @@ -118,12 +118,12 @@ async fn test_tracing_multiple_layers() { // Layer 0 let v1 = dag.add_task(Value(1)); - let v2 = dag.add_task(Value(2)); + let v2 = dag.add_task(Value(2)).into(); let v3 = dag.add_task(Value(3)); // Layer 1 - let sum12 = dag.add_task(Add).depends_on((&v1, &v2)); - let mul23 = dag.add_task(Multiply).depends_on((&v2, &v3)); + let sum12 = dag.add_task(Add).depends_on((v1, &v2)); + let mul23 = dag.add_task(Multiply).depends_on((&v2, v3)); // Layer 2 let final_sum = dag.add_task(Add).depends_on((&sum12, &mul23)); diff --git a/tests/tracing/without_tracing.rs b/tests/tracing/without_tracing.rs index 79f31b9..cf05260 100644 --- a/tests/tracing/without_tracing.rs +++ b/tests/tracing/without_tracing.rs @@ -27,7 +27,7 @@ async fn test_basic_dag_without_tracing() { let a = dag.add_task(Value(2)); let b = dag.add_task(Value(3)); - let sum = dag.add_task(Add).depends_on((&a, &b)); + let sum = dag.add_task(Add).depends_on((a, b)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -46,8 +46,8 @@ async fn test_complex_dag_without_tracing() { let v3 = dag.add_task(Value(3)); let v4 = dag.add_task(Value(4)); - let sum12 = dag.add_task(Add).depends_on((&v1, &v2)); - let sum34 = dag.add_task(Add).depends_on((&v3, &v4)); + let sum12 = dag.add_task(Add).depends_on((v1, v2)); + let sum34 = dag.add_task(Add).depends_on((v3, v4)); let final_sum = dag.add_task(Add).depends_on((&sum12, &sum34)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) diff --git a/tests/type_safety/complex.rs b/tests/type_safety/complex.rs index 19bf16b..f4c166c 100644 --- a/tests/type_safety/complex.rs +++ b/tests/type_safety/complex.rs @@ -27,7 +27,7 @@ async fn test_complex_type_safety() { .unwrap(); // Correct type works - let custom = dag.get(&custom_task).unwrap(); + let custom = dag.get(custom_task).unwrap(); assert_eq!(custom.value, 42); // Type safety is enforced at compile time - we cannot get with wrong types @@ -51,8 +51,8 @@ async fn test_generic_type_safety() { .unwrap(); // Correct types work - assert_eq!(dag.get(&vec_i32).unwrap(), vec![1, 2, 3]); - assert!(dag.get(&vec_string).is_ok()); + assert_eq!(dag.get(vec_i32).unwrap(), vec![1, 2, 3]); + assert!(dag.get(vec_string).is_ok()); } #[tokio::test] @@ -71,8 +71,8 @@ async fn test_option_result_type_safety() { .unwrap(); // Correct wrapped types work - assert_eq!(dag.get(&opt_task).unwrap(), Some(42)); - assert!(dag.get(&result_task).is_ok()); + assert_eq!(dag.get(opt_task).unwrap(), Some(42)); + assert!(dag.get(result_task).is_ok()); } #[tokio::test] @@ -94,7 +94,7 @@ async fn test_zero_sized_type_safety() { .unwrap(); // Correct ZSTs work - assert!(dag.get(&zst1_task).is_ok()); + assert!(dag.get(zst1_task).is_ok()); } #[tokio::test] @@ -115,13 +115,13 @@ async fn test_type_safety_with_many_types() { .unwrap(); // Each type works correctly - assert_eq!(dag.get(&i32_task).unwrap(), 42i32); - assert_eq!(dag.get(&i64_task).unwrap(), 42i64); - assert_eq!(dag.get(&u32_task).unwrap(), 42u32); - assert_eq!(dag.get(&f32_task).unwrap(), 42.0f32); - assert_eq!(dag.get(&f64_task).unwrap(), 42.0f64); - assert_eq!(dag.get(&string_task).unwrap(), "42".to_string()); - assert!(dag.get(&bool_task).unwrap()); + assert_eq!(dag.get(i32_task).unwrap(), 42i32); + assert_eq!(dag.get(i64_task).unwrap(), 42i64); + assert_eq!(dag.get(u32_task).unwrap(), 42u32); + assert_eq!(dag.get(f32_task).unwrap(), 42.0f32); + assert_eq!(dag.get(f64_task).unwrap(), 42.0f64); + assert_eq!(dag.get(string_task).unwrap(), "42".to_string()); + assert!(dag.get(bool_task).unwrap()); } #[tokio::test] @@ -134,7 +134,7 @@ async fn test_type_safety_single_dependency() { // This compiles because types match (i32 -> i32) let transform = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&source); + .depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -156,7 +156,7 @@ async fn test_type_safety_tuple_dependencies() { .add_task(task_fn(|(x, s, b): (i32, String, bool)| async move { format!("{}: {} ({})", s, x, b) })) - .depends_on((&a, &b, &c)); + .depends_on((a, b, c)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -177,9 +177,9 @@ async fn test_type_safety_different_output_types() { .await .unwrap(); - assert_eq!(dag.get(&int_source).unwrap(), 42); - assert_eq!(dag.get(&str_source).unwrap(), "test"); - assert_eq!(dag.get(&vec_source).unwrap(), vec![1, 2, 3]); + assert_eq!(dag.get(int_source).unwrap(), 42); + assert_eq!(dag.get(str_source).unwrap(), "test"); + assert_eq!(dag.get(vec_source).unwrap(), vec![1, 2, 3]); } #[tokio::test] @@ -226,7 +226,7 @@ async fn test_type_safety_with_generics() { .add_task(task_fn( |opt: Option| async move { opt.map(|x| x * 2) }, )) - .depends_on(&source); + .depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -240,7 +240,7 @@ async fn test_type_safety_with_generics() { .add_task(task_fn( |opt: Option| async move { opt.map(|x| x * 2) }, )) - .depends_on(&source2); + .depends_on(source2); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await @@ -262,7 +262,7 @@ async fn test_large_tuple_input() { .add_task(task_fn( |(a, b, c, d, e): (i32, i32, i32, i32, i32)| async move { a + b + c + d + e }, )) - .depends_on((&a, &b, &c, &d, &e)); + .depends_on((a, b, c, d, e)); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await diff --git a/tests/type_safety/handles.rs b/tests/type_safety/handles.rs index 9372107..052167e 100644 --- a/tests/type_safety/handles.rs +++ b/tests/type_safety/handles.rs @@ -21,7 +21,7 @@ async fn test_get_with_wrong_type_returns_none() { .unwrap(); // Verify correct type works - assert_eq!(dag.get(&int_task), Ok(42i32)); + assert_eq!(dag.get(int_task), Ok(42i32)); // The type safety is enforced at compile time // We cannot create fake handles with wrong types without accessing private fields @@ -42,8 +42,8 @@ async fn test_handle_preserves_type() { .unwrap(); // Get with correct types - assert_eq!(dag.get(&string_task).unwrap(), "hello".to_string()); - assert_eq!(dag.get(&int_task).unwrap(), 42); + assert_eq!(dag.get(string_task).unwrap(), "hello".to_string()); + assert_eq!(dag.get(int_task).unwrap(), 42); // Type safety is enforced at compile time - we cannot create wrong-typed handles } @@ -53,15 +53,15 @@ async fn test_type_safety_handle_reuse() { // Verify that handles maintain type safety across reuse let dag = DagRunner::new(); - let source = dag.add_task(task_fn(|_: ()| async { 100i32 })); + let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 100i32 })).into(); // Use the same source handle multiple times let double = dag .add_task(task_fn(|x: i32| async move { x * 2 })) - .depends_on(&source); + .depends_on(source); let triple = dag .add_task(task_fn(|x: i32| async move { x * 3 })) - .depends_on(&source); + .depends_on(source); dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .await