Merge pull request #8 from TechnoPorg/push-ptxmpolotoqo

Depend directly futures-util instead of futures
This commit is contained in:
TechnoPorg authored and GitHub committed 2026-02-11 22:50:16 +01:00
commit 7999996bca
79 files changed
+447 -380

No files matched your search

Generated
+1 -1
View File
@@ -442,8 +442,8 @@ dependencies = [
"criterion", "criterion",
"dagrs", "dagrs",
"dagx-macros", "dagx-macros",
"futures",
"futures-executor", "futures-executor",
"futures-util",
"parking_lot", "parking_lot",
"pollster", "pollster",
"smol", "smol",
+1 -1
View File
@@ -28,7 +28,7 @@ unexpected_cfgs = { level = "warn", check-cfg = [
] } ] }
[dependencies] [dependencies]
futures = { version = "0.3", default-features = false, features = ["std"] } futures-util = { version = "0.3", default-features = false, features = ["std"] }
parking_lot = "0.12" parking_lot = "0.12"
dagx-macros = { version = "0.3.1", path = "./dagx-macros" } dagx-macros = { version = "0.3.1", path = "./dagx-macros" }
tracing = { version = "0.1", optional = true } tracing = { version = "0.1", optional = true }
+3 -3
View File
@@ -38,7 +38,7 @@ See [how it works](docs/CYCLE_PREVENTION.md).
```rust ```rust
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?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
``` ```
That's it. No trait boilerplate, no manual channels, no node IDs. That's it. No trait boilerplate, no manual channels, no node IDs.
@@ -91,7 +91,7 @@ async fn main() {
let sum = dag.add_task(Add).depends_on((x, &y)); let sum = dag.add_task(Add).depends_on((x, &y));
// Execute with true parallelism // Execute with true parallelism
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
// Retrieve results // Retrieve results
assert_eq!(dag.get(sum).unwrap(), 5); assert_eq!(dag.get(sum).unwrap(), 5);
@@ -223,7 +223,7 @@ dagx works with any async runtime. Provide a spawner function to `run()`:
```rust ```rust
// With Tokio // With Tokio
// The join handle result can be unwrapped because dagx catches panics internally // The join handle result can be unwrapped because dagx catches panics internally
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
// With async-std // With async-std
dag.run(|fut| async_std::task::spawn(fut)).await.unwrap(); dag.run(|fut| async_std::task::spawn(fut)).await.unwrap();
+4 -4
View File
@@ -2,7 +2,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::{task_fn, DagRunner}; use dagx::{task_fn, DagRunner};
use futures::FutureExt;
pub fn bench_dag_execution(c: &mut Criterion) { pub fn bench_dag_execution(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -14,7 +14,7 @@ pub fn bench_dag_execution(c: &mut Criterion) {
for i in 0..10 { for i in 0..10 {
dag.add_task(task_fn::<(), _, _>(move |_: ()| i)); dag.add_task(task_fn::<(), _, _>(move |_: ()| i));
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
@@ -28,7 +28,7 @@ pub fn bench_dag_execution(c: &mut Criterion) {
for i in 0..100 { for i in 0..100 {
dag.add_task(task_fn::<(), _, _>(move |_: ()| i)); dag.add_task(task_fn::<(), _, _>(move |_: ()| i));
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
@@ -108,7 +108,7 @@ pub fn bench_dag_execution(c: &mut Criterion) {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(t18); .depends_on(t18);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -2,7 +2,7 @@
use criterion::{BenchmarkId, Criterion}; use criterion::{BenchmarkId, Criterion};
use dagx::{task_fn, DagRunner}; use dagx::{task_fn, DagRunner};
use futures::FutureExt;
pub fn bench_dag_scaling(c: &mut Criterion) { pub fn bench_dag_scaling(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -19,7 +19,7 @@ pub fn bench_dag_scaling(c: &mut Criterion) {
for i in 0..size { for i in 0..size {
dag.add_task(task_fn::<(), _, _>(move |_: ()| i)); dag.add_task(task_fn::<(), _, _>(move |_: ()| i));
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -4,7 +4,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::TaskHandle; use dagx::TaskHandle;
use futures::FutureExt;
pub fn bench_deep_chain(c: &mut Criterion) { pub fn bench_deep_chain(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -29,7 +29,7 @@ pub fn bench_deep_chain(c: &mut Criterion) {
.depends_on(prev); .depends_on(prev);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
dag.get(prev).unwrap() dag.get(prev).unwrap()
+2 -2
View File
@@ -4,7 +4,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::TaskHandle; use dagx::TaskHandle;
use futures::FutureExt;
pub fn bench_diamond_pattern(c: &mut Criterion) { pub fn bench_diamond_pattern(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -29,7 +29,7 @@ pub fn bench_diamond_pattern(c: &mut Criterion) {
.add_task(task_fn::<(i32, i32), _, _>(|(x, y): (&i32, &i32)| x + y)) .add_task(task_fn::<(i32, i32), _, _>(|(x, y): (&i32, &i32)| x + y))
.depends_on((&b, &c)); .depends_on((&b, &c));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
dag.get(d).unwrap() dag.get(d).unwrap()
+2 -2
View File
@@ -3,7 +3,7 @@
//! Extract → Transform → Validate → Load pattern //! Extract → Transform → Validate → Load pattern
use criterion::Criterion; use criterion::Criterion;
use futures::FutureExt;
pub fn bench_etl_pipeline(c: &mut Criterion) { pub fn bench_etl_pipeline(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -70,7 +70,7 @@ pub fn bench_etl_pipeline(c: &mut Criterion) {
})) }))
.depends_on(validate); .depends_on(validate);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
dag.get(load).unwrap() dag.get(load).unwrap()
+2 -2
View File
@@ -3,7 +3,7 @@
//! 10,000 independent tasks to test scaling //! 10,000 independent tasks to test scaling
use criterion::Criterion; use criterion::Criterion;
use futures::FutureExt;
pub fn bench_large_scale(c: &mut Criterion) { pub fn bench_large_scale(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -22,7 +22,7 @@ pub fn bench_large_scale(c: &mut Criterion) {
dag.add_task(task_fn::<(), _, _>(move |_: ()| i * 2)); dag.add_task(task_fn::<(), _, _>(move |_: ()| i * 2));
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -3,7 +3,7 @@
//! Simple chain of tasks: A → B → C → D → E //! Simple chain of tasks: A → B → C → D → E
use criterion::Criterion; use criterion::Criterion;
use futures::FutureExt;
pub fn bench_linear_pipeline(c: &mut Criterion) { pub fn bench_linear_pipeline(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -31,7 +31,7 @@ pub fn bench_linear_pipeline(c: &mut Criterion) {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 3)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x * 3))
.depends_on(d); .depends_on(d);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
dag.get(e).unwrap() dag.get(e).unwrap()
+2 -2
View File
@@ -4,7 +4,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::TaskHandle; use dagx::TaskHandle;
use futures::FutureExt;
pub fn bench_wide_fanout(c: &mut Criterion) { pub fn bench_wide_fanout(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -25,7 +25,7 @@ pub fn bench_wide_fanout(c: &mut Criterion) {
.depends_on(source); .depends_on(source);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+3 -3
View File
@@ -2,7 +2,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::{task_fn, DagRunner}; use dagx::{task_fn, DagRunner};
use futures::FutureExt;
pub fn bench_10k_breakdown(c: &mut Criterion) { pub fn bench_10k_breakdown(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -27,7 +27,7 @@ pub fn bench_10k_breakdown(c: &mut Criterion) {
for i in 0..10_000 { for i in 0..10_000 {
dag.add_task(task_fn::<(), _, _>(move |_: ()| i)); dag.add_task(task_fn::<(), _, _>(move |_: ()| i));
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
@@ -44,7 +44,7 @@ pub fn bench_10k_breakdown(c: &mut Criterion) {
b.iter(|| { b.iter(|| {
rt.block_on(async { rt.block_on(async {
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -2,7 +2,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::{task_fn, DagRunner, TaskHandle}; use dagx::{task_fn, DagRunner, TaskHandle};
use futures::FutureExt;
pub fn bench_diamond(c: &mut Criterion) { pub fn bench_diamond(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -27,7 +27,7 @@ pub fn bench_diamond(c: &mut Criterion) {
.depends_on((&left, &right)); .depends_on((&left, &right));
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+4 -4
View File
@@ -2,7 +2,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::{task_fn, DagRunner, TaskHandle}; use dagx::{task_fn, DagRunner, TaskHandle};
use futures::FutureExt;
pub fn bench_fanout(c: &mut Criterion) { pub fn bench_fanout(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -19,7 +19,7 @@ pub fn bench_fanout(c: &mut Criterion) {
.depends_on(source); .depends_on(source);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
@@ -46,7 +46,7 @@ pub fn bench_fanout(c: &mut Criterion) {
.depends_on(source); .depends_on(source);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
@@ -72,7 +72,7 @@ pub fn bench_fanout(c: &mut Criterion) {
.depends_on(source); .depends_on(source);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -2,7 +2,7 @@
use criterion::{BenchmarkId, Criterion}; use criterion::{BenchmarkId, Criterion};
use dagx::{task_fn, DagRunner, TaskHandle}; use dagx::{task_fn, DagRunner, TaskHandle};
use futures::FutureExt;
use std::collections::HashMap; use std::collections::HashMap;
use std::hint::black_box; use std::hint::black_box;
@@ -56,7 +56,7 @@ pub fn bench_config_broadcast(c: &mut Criterion) {
.depends_on(config); .depends_on(config);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -2,7 +2,7 @@
use criterion::{BenchmarkId, Criterion}; use criterion::{BenchmarkId, Criterion};
use dagx::{task_fn, DagRunner, TaskHandle}; use dagx::{task_fn, DagRunner, TaskHandle};
use futures::FutureExt;
pub fn bench_etl_pipeline(c: &mut Criterion) { pub fn bench_etl_pipeline(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -93,7 +93,7 @@ pub fn bench_etl_pipeline(c: &mut Criterion) {
)) ))
.depends_on((&validate, &scores, &names)); .depends_on((&validate, &scores, &names));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -2,7 +2,7 @@
use criterion::{BenchmarkId, Criterion}; use criterion::{BenchmarkId, Criterion};
use dagx::{task_fn, DagRunner, TaskHandle}; use dagx::{task_fn, DagRunner, TaskHandle};
use futures::FutureExt;
use std::hint::black_box; use std::hint::black_box;
pub fn bench_memory_efficiency(c: &mut Criterion) { pub fn bench_memory_efficiency(c: &mut Criterion) {
@@ -41,7 +41,7 @@ pub fn bench_memory_efficiency(c: &mut Criterion) {
.depends_on(source); .depends_on(source);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+2 -2
View File
@@ -2,7 +2,7 @@
use criterion::Criterion; use criterion::Criterion;
use dagx::{task_fn, DagRunner, TaskHandle}; use dagx::{task_fn, DagRunner, TaskHandle};
use futures::FutureExt;
pub fn bench_mixed_patterns(c: &mut Criterion) { pub fn bench_mixed_patterns(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
@@ -55,7 +55,7 @@ pub fn bench_mixed_patterns(c: &mut Criterion) {
.depends_on(summary); .depends_on(summary);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
}) })
+1 -1
View File
@@ -19,7 +19,7 @@ let dag = DagRunner::new();
let x = dag.add_task(Value(2)); let x = dag.add_task(Value(2));
let y = dag.add_task(Value(3)); 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?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
``` ```
**dagrs** (Complex: traits + channels + IDs + manual wiring): **dagrs** (Complex: traits + channels + IDs + manual wiring):
+1 -1
View File
@@ -13,7 +13,7 @@ let a = dag.add_task(TaskA);
let b = dag.add_task(TaskB); let b = dag.add_task(TaskB);
a.depends_on(b); a.depends_on(b);
b.depends_on(a); // Compiles fine... b.depends_on(a); // Compiles fine...
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
``` ```
**dagx prevents this at compile time:** **dagx prevents this at compile time:**
+2 -2
View File
@@ -31,7 +31,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
// Step 1: Define a source task (no dependencies) // Step 1: Define a source task (no dependencies)
// //
@@ -106,7 +106,7 @@ async fn main() {
// 1. Tasks with no dependencies run first (x and y in parallel) // 1. Tasks with no dependencies run first (x and y in parallel)
// 2. Once x and y complete, sum runs (it depends on both) // 2. Once x and y complete, sum runs (it depends on both)
println!("Running DAG...\n"); println!("Running DAG...\n");
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+2 -2
View File
@@ -56,7 +56,7 @@
//! ``` //! ```
use dagx::{task, DagRunner, TaskHandle}; use dagx::{task, DagRunner, TaskHandle};
use futures::FutureExt;
// Source task with a value field // Source task with a value field
struct Source { struct Source {
@@ -141,7 +141,7 @@ async fn main() {
// Run the DAG // Run the DAG
println!("Running fan-out DAG...\n"); println!("Running fan-out DAG...\n");
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+2 -2
View File
@@ -62,7 +62,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
struct FetchName; struct FetchName;
@@ -134,7 +134,7 @@ async fn main() {
// Run the DAG // Run the DAG
println!("Running fan-in DAG...\n"); println!("Running fan-in DAG...\n");
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+2 -2
View File
@@ -53,7 +53,7 @@
//! ``` //! ```
use dagx::{task, DagResult, DagRunner, Task, TaskInput}; use dagx::{task, DagResult, DagRunner, Task, TaskInput};
use futures::FutureExt;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::time::sleep; use tokio::time::sleep;
@@ -125,7 +125,7 @@ async fn main() -> DagResult<()> {
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?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
let result = dag.get(total)?; let result = dag.get(total)?;
let elapsed = start.elapsed(); let elapsed = start.elapsed();
+8 -8
View File
@@ -151,7 +151,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
use std::sync::Arc; use std::sync::Arc;
use std::time::Instant; use std::time::Instant;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@@ -390,7 +390,7 @@ async fn main() {
false, // success false, // success
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -404,7 +404,7 @@ async fn main() {
true, // fail true, // fail
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -418,7 +418,7 @@ async fn main() {
true, // fail true, // fail
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -432,7 +432,7 @@ async fn main() {
true, // fail true, // fail
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -450,7 +450,7 @@ async fn main() {
.add_task(FallbackService::new("ServiceCall-5")) .add_task(FallbackService::new("ServiceCall-5"))
.depends_on(call5); .depends_on(call5);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -469,7 +469,7 @@ async fn main() {
false, // success false, // success
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -483,7 +483,7 @@ async fn main() {
false, // success false, // success
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+2 -2
View File
@@ -67,7 +67,7 @@
//! ``` //! ```
use dagx::{task, DagResult, DagRunner}; use dagx::{task, DagResult, DagRunner};
use futures::FutureExt;
// Extract: Load data from different sources // Extract: Load data from different sources
struct LoadData { struct LoadData {
@@ -202,7 +202,7 @@ async fn main() -> DagResult<()> {
// Execute the entire ETL pipeline // Execute the entire ETL pipeline
println!("Executing pipeline...\n"); println!("Executing pipeline...\n");
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Display final report // Display final report
println!("\n{}", dag.get(report)?); println!("\n{}", dag.get(report)?);
+2 -2
View File
@@ -56,7 +56,7 @@
//! ``` //! ```
use dagx::{task, DagResult, DagRunner}; use dagx::{task, DagResult, DagRunner};
use futures::FutureExt;
// Task that validates and processes input // Task that validates and processes input
struct ValidateAndDouble { struct ValidateAndDouble {
@@ -138,7 +138,7 @@ async fn main() -> DagResult<()> {
.depends_on((&cat1, &cat2, &cat3)); .depends_on((&cat1, &cat2, &cat3));
// Execute // Execute
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Display results // Display results
println!("\nFinal summary: {}", dag.get(summary)?); println!("\nFinal summary: {}", dag.get(summary)?);
+2 -2
View File
@@ -35,7 +35,7 @@
//! ``` //! ```
use dagx::{task, DagRunner, TaskHandle}; use dagx::{task, DagRunner, TaskHandle};
use futures::FutureExt;
#[derive(Debug)] #[derive(Debug)]
struct User { struct User {
@@ -107,7 +107,7 @@ async fn main() {
let validation = dag.add_task(ValidateUser).depends_on(user_task); let validation = dag.add_task(ValidateUser).depends_on(user_task);
// Execute the DAG // Execute the DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+2 -2
View File
@@ -76,7 +76,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
// Data source tasks // Data source tasks
struct LoadValue1; struct LoadValue1;
@@ -221,7 +221,7 @@ async fn main() {
// Execute the pipeline // Execute the pipeline
println!("Executing pipeline...\n"); println!("Executing pipeline...\n");
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+3 -3
View File
@@ -115,7 +115,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
use std::time::Instant; use std::time::Instant;
use tokio::time::{sleep, Duration}; use tokio::time::{sleep, Duration};
@@ -401,7 +401,7 @@ async fn main() {
.depends_on((inventory, payment, shipping)); .depends_on((inventory, payment, shipping));
// Run the DAG // Run the DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -441,7 +441,7 @@ async fn main() {
true, // will fail true, // will fail
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+5 -5
View File
@@ -115,7 +115,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
// Source task that provides a string input // Source task that provides a string input
struct StringSource(&'static str); struct StringSource(&'static str);
@@ -223,7 +223,7 @@ async fn main() {
let processed = dag.add_task(ProcessData).depends_on(validated); let processed = dag.add_task(ProcessData).depends_on(validated);
let logged = dag.add_task(LogError).depends_on(processed); let logged = dag.add_task(LogError).depends_on(processed);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -249,7 +249,7 @@ async fn main() {
let processed = dag.add_task(ProcessData).depends_on(validated); let processed = dag.add_task(ProcessData).depends_on(validated);
let logged = dag.add_task(LogError).depends_on(processed); let logged = dag.add_task(LogError).depends_on(processed);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -275,7 +275,7 @@ async fn main() {
let processed = dag.add_task(ProcessData).depends_on(validated); let processed = dag.add_task(ProcessData).depends_on(validated);
let logged = dag.add_task(LogError).depends_on(processed); let logged = dag.add_task(LogError).depends_on(processed);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -298,7 +298,7 @@ async fn main() {
.add_task(WithFallback { fallback: 0 }) .add_task(WithFallback { fallback: 0 })
.depends_on(parsed); .depends_on(parsed);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+6 -6
View File
@@ -110,7 +110,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
use std::time::Instant; use std::time::Instant;
// Simple computation task // Simple computation task
@@ -182,7 +182,7 @@ async fn main() {
println!(" Build time: {:?}", build_time); println!(" Build time: {:?}", build_time);
let exec_start = Instant::now(); let exec_start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let exec_time = exec_start.elapsed(); let exec_time = exec_start.elapsed();
@@ -222,7 +222,7 @@ async fn main() {
println!(" Build time: {:?}", build_time); println!(" Build time: {:?}", build_time);
let exec_start = Instant::now(); let exec_start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let exec_time = exec_start.elapsed(); let exec_time = exec_start.elapsed();
@@ -273,7 +273,7 @@ async fn main() {
println!(" Tree depth: {}", level); println!(" Tree depth: {}", level);
let exec_start = Instant::now(); let exec_start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let exec_time = exec_start.elapsed(); let exec_time = exec_start.elapsed();
@@ -331,7 +331,7 @@ async fn main() {
println!(" Build time: {:?}", build_time); println!(" Build time: {:?}", build_time);
let exec_start = Instant::now(); let exec_start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let exec_time = exec_start.elapsed(); let exec_time = exec_start.elapsed();
@@ -355,7 +355,7 @@ async fn main() {
.map(|i| dag.add_task(FormatNumber { id: i })) .map(|i| dag.add_task(FormatNumber { id: i }))
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+6 -6
View File
@@ -153,7 +153,7 @@
//! ``` //! ```
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
use tokio::time::{sleep, Duration}; use tokio::time::{sleep, Duration};
// Retry strategy configuration // Retry strategy configuration
@@ -356,7 +356,7 @@ async fn main() {
], ],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -378,7 +378,7 @@ async fn main() {
], ],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -404,7 +404,7 @@ async fn main() {
], ],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -423,7 +423,7 @@ async fn main() {
vec![ApiError::AuthenticationFailed], vec![ApiError::AuthenticationFailed],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -450,7 +450,7 @@ async fn main() {
], ],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+7 -7
View File
@@ -24,7 +24,7 @@
//! //!
//! **2. DAG-Level Timeout** - Entire workflow with timeout //! **2. DAG-Level Timeout** - Entire workflow with timeout
//! ```rust //! ```rust
//! match timeout(dag_timeout, dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await { //! match timeout(dag_timeout, dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await {
//! Ok(result) => { /* DAG completed */ }, //! Ok(result) => { /* DAG completed */ },
//! Err(_) => { /* DAG timed out */ }, //! Err(_) => { /* DAG timed out */ },
//! } //! }
@@ -99,7 +99,7 @@
//! ``` //! ```
use dagx::{task, DagRunner, TaskHandle}; use dagx::{task, DagRunner, TaskHandle};
use futures::FutureExt;
use tokio::time::{sleep, timeout, Duration}; use tokio::time::{sleep, timeout, Duration};
// Fast task that completes quickly // Fast task that completes quickly
@@ -178,7 +178,7 @@ async fn main() {
timeout_ms: 500, timeout_ms: 500,
}); });
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -198,7 +198,7 @@ async fn main() {
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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -225,7 +225,7 @@ async fn main() {
timeout_ms: 200, timeout_ms: 200,
}); });
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -251,7 +251,7 @@ async fn main() {
let processed1 = 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); let processed2 = dag.add_task(ProcessResult).depends_on(source);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -272,7 +272,7 @@ async fn main() {
let dag_timeout = Duration::from_millis(500); let dag_timeout = Duration::from_millis(500);
match timeout( match timeout(
dag_timeout, dag_timeout,
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)), dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }),
) )
.await .await
{ {
+4 -4
View File
@@ -34,7 +34,7 @@
//! //!
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
use tracing_subscriber::{fmt, EnvFilter}; use tracing_subscriber::{fmt, EnvFilter};
// Simple source task // Simple source task
@@ -96,7 +96,7 @@ async fn main() {
// Layer 2: Combine results // Layer 2: Combine results
let result = dag.add_task(Add).depends_on((&left, &right)); let result = dag.add_task(Add).depends_on((&left, &right));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -117,7 +117,7 @@ async fn main() {
let c = dag.add_task(Multiply).depends_on((&b, &b)); let c = dag.add_task(Multiply).depends_on((&b, &b));
let d = dag.add_task(Add).depends_on((&c, &c)); let d = dag.add_task(Add).depends_on((&c, &c));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -146,7 +146,7 @@ async fn main() {
let sum_all = dag.add_task(Add).depends_on((&sum12, &sum23)); let sum_all = dag.add_task(Add).depends_on((&sum12, &sum23));
let final_result = dag.add_task(Add).depends_on((&sum_all, &sum34)); let final_result = dag.add_task(Add).depends_on((&sum_all, &sum34));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+4 -4
View File
@@ -22,7 +22,7 @@ use tracing::debug;
/// ///
/// ```no_run /// ```no_run
/// # use dagx::{task, DagRunner, Task}; /// # use dagx::{task, DagRunner, Task};
/// # use futures::FutureExt; /// #
/// // Using tuple struct for simple constants /// // Using tuple struct for simple constants
/// struct Constant(i32); /// struct Constant(i32);
/// ///
@@ -57,7 +57,7 @@ use tracing::debug;
/// let b = b.depends_on(a); /// let b = b.depends_on(a);
/// // Now b is a TaskHandle<i32> /// // Now b is a TaskHandle<i32>
/// ///
/// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); /// dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
/// assert_eq!(dag.get(b).unwrap(), 20); /// assert_eq!(dag.get(b).unwrap(), 20);
/// # }; /// # };
/// ``` /// ```
@@ -81,7 +81,7 @@ impl<'a, Tk: Task, Deps> TaskBuilder<'a, Tk, Deps> {
/// ///
/// ```no_run /// ```no_run
/// # use dagx::{task, DagRunner, Task}; /// # use dagx::{task, DagRunner, Task};
/// # use futures::FutureExt; /// #
/// // Tuple struct /// // Tuple struct
/// struct Value(i32); /// struct Value(i32);
/// ///
@@ -118,7 +118,7 @@ impl<'a, Tk: Task, Deps> TaskBuilder<'a, Tk, Deps> {
/// // Multiple dependencies: tuple form /// // 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(); /// dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
/// # }; /// # };
/// ``` /// ```
pub fn depends_on<D>(self, deps: D) -> TaskHandle<Tk::Output> pub fn depends_on<D>(self, deps: D) -> TaskHandle<Tk::Output>
+1 -1
View File
@@ -63,7 +63,7 @@ impl std::fmt::Display for DagError {
f, f,
"Result not found for task #{}.\n\ "Result not found for task #{}.\n\
\n\ \n\
Call dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).", Call dag.run(|fut| async move {{ tokio::spawn(fut).await.unwrap() }}).",
task_id task_id
) )
} }
+1 -1
View File
@@ -51,7 +51,7 @@ fn test_dag_error_display_result_not_found() {
assert!(display.contains("Result not found")); assert!(display.contains("Result not found"));
assert!(display.contains("task #7")); assert!(display.contains("task #7"));
assert!(display.contains("Call dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))")); assert!(display.contains("Call dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })"));
} }
#[test] #[test]
+14 -15
View File
@@ -24,7 +24,6 @@
//! //!
//! ```no_run //! ```no_run
//! use dagx::{task, DagRunner, Task, TaskHandle}; //! use dagx::{task, DagRunner, Task, TaskHandle};
//! use futures::FutureExt; // for FutureExt::map
//! //!
//! // Source task with read-only state (tuple struct) //! // Source task with read-only state (tuple struct)
//! struct Value(i32); //! struct Value(i32);
@@ -53,7 +52,7 @@
//! let sum = dag.add_task(Add).depends_on((x, &y)); //! let sum = dag.add_task(Add).depends_on((x, &y));
//! //!
//! // Execute and retrieve results //! // Execute and retrieve results
//! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); //! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
//! assert_eq!(dag.get(sum).unwrap(), 5); //! assert_eq!(dag.get(sum).unwrap(), 5);
//! # }; //! # };
//! ``` //! ```
@@ -291,7 +290,7 @@
//! //!
//! ```no_run //! ```no_run
//! use dagx::{task, DagRunner, Task}; //! use dagx::{task, DagRunner, Task};
//! use futures::FutureExt; //!
//! //!
//! // Source task (tuple struct) //! // Source task (tuple struct)
//! struct Value(i32); //! struct Value(i32);
@@ -324,7 +323,7 @@
//! let plus1 = dag.add_task(Add(1)).depends_on(&base); //! let plus1 = dag.add_task(Add(1)).depends_on(&base);
//! let times2 = dag.add_task(Scale(2)).depends_on(&base); //! let times2 = dag.add_task(Scale(2)).depends_on(&base);
//! //!
//! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); //! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
//! //!
//! assert_eq!(dag.get(plus1).unwrap(), 11); //! assert_eq!(dag.get(plus1).unwrap(), 11);
//! assert_eq!(dag.get(times2).unwrap(), 20); //! assert_eq!(dag.get(times2).unwrap(), 20);
@@ -337,7 +336,7 @@
//! //!
//! ```no_run //! ```no_run
//! use dagx::{task, DagRunner, Task}; //! use dagx::{task, DagRunner, Task};
//! use futures::FutureExt; //!
//! //!
//! // Source task for String (tuple struct) //! // Source task for String (tuple struct)
//! struct Name(String); //! struct Name(String);
@@ -381,7 +380,7 @@
//! let active = dag.add_task(Active(true)); //! 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(); //! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
//! //!
//! assert_eq!(dag.get(result).unwrap(), "User: Alice, Age: 30, Active: true"); //! assert_eq!(dag.get(result).unwrap(), "User: Alice, Age: 30, Active: true");
//! # }; //! # };
@@ -393,7 +392,7 @@
//! //!
//! ```no_run //! ```no_run
//! use dagx::{task, DagRunner, Task}; //! use dagx::{task, DagRunner, Task};
//! use futures::FutureExt; //!
//! //!
//! // Source task (tuple struct) //! // Source task (tuple struct)
//! struct Value(i32); //! struct Value(i32);
@@ -434,7 +433,7 @@
//! // Layer 3: Final result //! // Layer 3: Final result
//! let total = dag.add_task(Add).depends_on((&sum_xy, &prod_yz)); // 5 + 15 = 20 //! let total = dag.add_task(Add).depends_on((&sum_xy, &prod_yz)); // 5 + 15 = 20
//! //!
//! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); //! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
//! //!
//! assert_eq!(dag.get(total).unwrap(), 20); //! assert_eq!(dag.get(total).unwrap(), 20);
//! # }; //! # };
@@ -447,7 +446,7 @@
//! //!
//! ```no_run //! ```no_run
//! # use dagx::{task, DagRunner, Task}; //! # use dagx::{task, DagRunner, Task};
//! # use futures::FutureExt; //! #
//! //!
//! struct User { //! struct User {
//! name: String, //! name: String,
@@ -476,7 +475,7 @@
//! let user = dag.add_task(CreateUser); //! 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(); //! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
//! //!
//! assert_eq!(dag.get(formatted).unwrap(), "Alice is 30 years old"); //! assert_eq!(dag.get(formatted).unwrap(), "Alice is 30 years old");
//! # }; //! # };
@@ -533,7 +532,7 @@
//! //!
//! ```no_run //! ```no_run
//! # use dagx::{task, DagRunner, Task}; //! # use dagx::{task, DagRunner, Task};
//! # use futures::FutureExt; //! #
//! # struct Value(i32); //! # struct Value(i32);
//! # #[task] //! # #[task]
//! # impl Value { //! # impl Value {
@@ -543,11 +542,11 @@
//! # let dag = DagRunner::new(); //! # let dag = DagRunner::new();
//! # let node = dag.add_task(Value(42)); //! # let node = dag.add_task(Value(42));
//! // Simple approach with .unwrap() //! // Simple approach with .unwrap()
//! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); //! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
//! let result = dag.get(node).unwrap(); //! let result = dag.get(node).unwrap();
//! //!
//! // Or handle errors explicitly //! // Or handle errors explicitly
//! match dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await { //! match dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await {
//! Ok(_) => println!("DAG executed successfully"), //! Ok(_) => println!("DAG executed successfully"),
//! Err(e) => eprintln!("DAG execution failed: {}", e), //! Err(e) => eprintln!("DAG execution failed: {}", e),
//! } //! }
@@ -631,7 +630,7 @@
//! //!
//! ``` //! ```
//! # use dagx::{task, DagRunner, Task}; //! # use dagx::{task, DagRunner, Task};
//! # use futures::FutureExt; //! #
//! //!
//! // ✅ CORRECT: Just output Vec<String>, framework wraps in Arc internally //! // ✅ CORRECT: Just output Vec<String>, framework wraps in Arc internally
//! struct FetchData; //! struct FetchData;
@@ -661,7 +660,7 @@
//! let task2 = dag.add_task(ProcessData).depends_on(&data); //! let task2 = dag.add_task(ProcessData).depends_on(&data);
//! let task3 = dag.add_task(ProcessData).depends_on(&data); //! let task3 = dag.add_task(ProcessData).depends_on(&data);
//! //!
//! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); //! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
//! # }; //! # };
//! ``` //! ```
//! //!
+13 -12
View File
@@ -9,14 +9,13 @@ use std::any::Any;
use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::{HashMap, HashSet, VecDeque};
use std::future::Future; use std::future::Future;
use std::panic::AssertUnwindSafe; use std::panic::AssertUnwindSafe;
use std::pin::Pin;
use std::sync::{ use std::sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Arc,
}; };
use futures::future::BoxFuture; use futures_util::{stream::FuturesUnordered, FutureExt, StreamExt, TryFutureExt};
use futures::stream::FuturesUnordered;
use futures::{FutureExt, StreamExt, TryFutureExt};
use parking_lot::Mutex; use parking_lot::Mutex;
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
@@ -28,6 +27,8 @@ use crate::node::{ExecutableNode, TypedNode};
use crate::task::Task; use crate::task::Task;
use crate::types::{NodeId, Pending, TaskHandle}; use crate::types::{NodeId, Pending, TaskHandle};
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
// Guard to ensure run_lock is released even on early return or panic // Guard to ensure run_lock is released even on early return or panic
struct RunGuard<'a> { struct RunGuard<'a> {
lock: &'a AtomicBool, lock: &'a AtomicBool,
@@ -56,7 +57,7 @@ impl<'a> Drop for RunGuard<'a> {
/// ///
/// ```no_run /// ```no_run
/// # use dagx::{task, DagRunner, Task}; /// # use dagx::{task, DagRunner, Task};
/// # use futures::FutureExt; /// #
/// // Task with state constructed via ::new() /// // Task with state constructed via ::new()
/// struct LoadValue { value: i32 } /// struct LoadValue { value: i32 }
/// ///
@@ -85,7 +86,7 @@ impl<'a> Drop for RunGuard<'a> {
/// let y = dag.add_task(LoadValue::new(3)); /// 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(); /// dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
/// ///
/// assert_eq!(dag.get(sum).unwrap(), 5); /// assert_eq!(dag.get(sum).unwrap(), 5);
/// # }; /// # };
@@ -150,7 +151,7 @@ impl DagRunner {
/// ///
/// ```no_run /// ```no_run
/// # use dagx::{task, DagRunner, Task}; /// # use dagx::{task, DagRunner, Task};
/// # use futures::FutureExt; /// #
/// // Task with state - shows you construct with specific value /// // Task with state - shows you construct with specific value
/// struct LoadValue { /// struct LoadValue {
/// initial: i32, /// initial: i32,
@@ -192,7 +193,7 @@ impl DagRunner {
/// // Construct task with offset of 1 /// // 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(); /// dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
/// assert_eq!(dag.get(inc).unwrap(), 11); /// assert_eq!(dag.get(inc).unwrap(), 11);
/// # }; /// # };
/// ``` /// ```
@@ -236,7 +237,7 @@ impl DagRunner {
/// ///
/// - `spawner`: A function that spawns futures on the async runtime /// - `spawner`: A function that spawns futures on the async runtime
/// and returns a handle to the task. This is the only way to run tasks on separate threads. Examples: /// and returns a handle to the task. This is the only way to run tasks on separate threads. Examples:
/// - Tokio: `|fut| { tokio::spawn(fut).map(Result::unwrap) }` /// - Tokio: `|fut| { tokio::spawn(fut).await.unwrap() }`
/// - Smol: `|fut| { smol::spawn(fut) }` /// - Smol: `|fut| { smol::spawn(fut) }`
/// - Async-std: `|fut| { async_std::task::spawn(fut) }` /// - Async-std: `|fut| { async_std::task::spawn(fut) }`
/// - Single-threaded: `|fut| fut` /// - Single-threaded: `|fut| fut`
@@ -256,7 +257,7 @@ impl DagRunner {
/// ///
/// ``` /// ```
/// # use dagx::{task, DagRunner, Task}; /// # use dagx::{task, DagRunner, Task};
/// # use futures::FutureExt; /// #
/// // Tuple struct /// // Tuple struct
/// struct Value(i32); /// struct Value(i32);
/// ///
@@ -280,7 +281,7 @@ impl DagRunner {
/// let b = dag.add_task(Value(2)); /// 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 /// dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap(); // Executes all tasks
/// # }; /// # };
/// ``` /// ```
#[inline] #[inline]
@@ -531,7 +532,7 @@ impl DagRunner {
/// ///
/// ```no_run /// ```no_run
/// # use dagx::{task, DagRunner, Task}; /// # use dagx::{task, DagRunner, Task};
/// # use futures::FutureExt; /// #
/// struct Configuration { /// struct Configuration {
/// setting: i32, /// setting: i32,
/// } /// }
@@ -553,7 +554,7 @@ impl DagRunner {
/// // Construct task with specific setting value /// // Construct task with specific setting value
/// let task = dag.add_task(Configuration::new(42)); /// let task = dag.add_task(Configuration::new(42));
/// ///
/// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); /// dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
/// ///
/// assert_eq!(dag.get(task).unwrap(), 42); /// assert_eq!(dag.get(task).unwrap(), 42);
/// # }; /// # };
+9 -7
View File
@@ -4,8 +4,6 @@ use crate::error::DagError;
use crate::runner::DagRunner; use crate::runner::DagRunner;
use crate::types::TaskHandle; use crate::types::TaskHandle;
use futures::FutureExt;
// Initialize tracing subscriber for tests (idempotent) // Initialize tracing subscriber for tests (idempotent)
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
fn init_tracing() { fn init_tracing() {
@@ -69,7 +67,7 @@ async fn test_get_wrong_type() {
let dag = DagRunner::new(); let dag = DagRunner::new();
let handle = dag.add_task(TestTask { value: 42 }); let handle = dag.add_task(TestTask { value: 42 });
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -144,12 +142,14 @@ async fn test_concurrent_run_protection() {
// Start two runs concurrently // Start two runs concurrently
let handle1 = tokio::spawn(async move { let handle1 = tokio::spawn(async move {
barrier1.wait().await; barrier1.wait().await;
dag1.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await dag1.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await
}); });
let handle2 = tokio::spawn(async move { let handle2 = tokio::spawn(async move {
barrier2.wait().await; barrier2.wait().await;
dag2.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await dag2.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await
}); });
// One should succeed, one should fail (concurrent execution not supported) // One should succeed, one should fail (concurrent execution not supported)
@@ -197,7 +197,7 @@ async fn test_invalid_node_id_in_get() {
_phantom: std::marker::PhantomData, _phantom: std::marker::PhantomData,
}; };
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -250,7 +250,9 @@ async fn test_task_panic_in_multi_task_layer() {
let _good_task = dag.add_task(GoodTask).depends_on(source); let _good_task = dag.add_task(GoodTask).depends_on(source);
// Run the DAG - the panic should be caught // Run the DAG - the panic should be caught
let result = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let result = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// The run should fail due to the panic // The run should fail due to the panic
// Note: Tokio catches panics in spawned tasks, so the behavior depends on the runtime // Note: Tokio catches panics in spawned tasks, so the behavior depends on the runtime
+2 -2
View File
@@ -23,7 +23,7 @@ pub struct NodeId(pub usize);
/// ///
/// ```no_run /// ```no_run
/// # use dagx::{task, DagRunner, Task}; /// # use dagx::{task, DagRunner, Task};
/// # use futures::FutureExt; /// #
/// # struct LoadValue { value: i32 } /// # struct LoadValue { value: i32 }
/// # impl LoadValue { pub fn new(v: i32) -> Self { Self { value: v } } } /// # impl LoadValue { pub fn new(v: i32) -> Self { Self { value: v } } }
/// # #[task] /// # #[task]
@@ -34,7 +34,7 @@ pub struct NodeId(pub usize);
/// let dag = DagRunner::new(); /// let dag = DagRunner::new();
/// let node = dag.add_task(LoadValue::new(42)); /// let node = dag.add_task(LoadValue::new(42));
/// ///
/// dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap(); /// dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
/// ///
/// assert_eq!(dag.get(node).unwrap(), 42); /// assert_eq!(dag.get(node).unwrap(), 42);
/// # }; /// # };
+5 -6
View File
@@ -3,7 +3,6 @@
//! These tests ensure we hit line 71 in the From<TaskBuilder> implementation //! These tests ensure we hit line 71 in the From<TaskBuilder> implementation
use crate::{task, DagRunner, TaskHandle}; use crate::{task, DagRunner, TaskHandle};
use futures::FutureExt;
#[tokio::test] #[tokio::test]
async fn test_unit_type_taskbuilder_to_handle_conversion() { async fn test_unit_type_taskbuilder_to_handle_conversion() {
@@ -31,7 +30,7 @@ async fn test_unit_type_taskbuilder_to_handle_conversion() {
// specifically covering line 71 // specifically covering line 71
let handle: TaskHandle<_> = builder.into(); let handle: TaskHandle<_> = builder.into();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -79,7 +78,7 @@ async fn test_unit_type_conversion_with_multiple_tasks() {
let second_handle: TaskHandle<_> = second_builder.into(); let second_handle: TaskHandle<_> = second_builder.into();
let third_handle: TaskHandle<bool> = third_builder.into(); let third_handle: TaskHandle<bool> = third_builder.into();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -118,7 +117,7 @@ async fn test_unit_struct_with_state() {
// Explicit conversion - triggers line 71 // Explicit conversion - triggers line 71
let handle: TaskHandle<_> = builder.into(); let handle: TaskHandle<_> = builder.into();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -144,7 +143,7 @@ async fn test_taskbuilder_conversion_assignment() {
// This also uses From<TaskBuilder> implementation // This also uses From<TaskBuilder> implementation
let handle: TaskHandle<Vec<i32>> = builder.into(); let handle: TaskHandle<Vec<i32>> = builder.into();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -181,7 +180,7 @@ async fn test_mixed_unit_and_dependent_tasks() {
// Doubler needs dependencies, so we use it differently // Doubler needs dependencies, so we use it differently
let doubler = dag.add_task(Doubler).depends_on(source_handle); let doubler = dag.add_task(Doubler).depends_on(source_handle);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+20 -20
View File
@@ -10,7 +10,7 @@
//! These tests serve as both validation and documentation for proper Arc usage. //! These tests serve as both validation and documentation for proper Arc usage.
use dagx::{task, DagRunner, TaskHandle}; use dagx::{task, DagRunner, TaskHandle};
use futures::FutureExt;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -44,7 +44,7 @@ async fn test_arc_basic_pipeline() {
let producer = dag.add_task(Producer); 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -100,7 +100,7 @@ async fn test_arc_with_primitives() {
.add_task(AllConsumer) .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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -174,7 +174,7 @@ async fn test_arc_with_collections() {
.add_task(CollectionConsumer) .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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -245,7 +245,7 @@ async fn test_arc_with_custom_structs() {
let age_ext = dag.add_task(AgeExtractor).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 email_ext = dag.add_task(EmailCountExtractor).depends_on(person_prod);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -311,7 +311,7 @@ async fn test_arc_fan_out_three_consumers() {
let c2 = dag.add_task(FirstConsumer).depends_on(producer); let c2 = dag.add_task(FirstConsumer).depends_on(producer);
let c3 = dag.add_task(JoinConsumer).depends_on(producer); let c3 = dag.add_task(JoinConsumer).depends_on(producer);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -385,7 +385,7 @@ async fn test_arc_fan_out_five_consumers_large_data() {
let c4 = dag.add_task(PatternCounter).depends_on(producer); let c4 = dag.add_task(PatternCounter).depends_on(producer);
let c5 = dag.add_task(TotalBytesComputer).depends_on(producer); let c5 = dag.add_task(TotalBytesComputer).depends_on(producer);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -475,7 +475,7 @@ async fn test_arc_nested_fan_out_tree() {
let l2_negate = dag.add_task(Level2Negate).depends_on(l1_prod); let l2_negate = dag.add_task(Level2Negate).depends_on(l1_prod);
let l2_mod = dag.add_task(Level2Mod10).depends_on(l1_prod); let l2_mod = dag.add_task(Level2Mod10).depends_on(l1_prod);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -543,7 +543,7 @@ async fn test_arc_performance_vs_clone() {
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -643,7 +643,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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -750,7 +750,7 @@ async fn test_arc_with_option() {
let c3 = dag.add_task(OptionArcConsumer1).depends_on(opt_arc_some); let c3 = dag.add_task(OptionArcConsumer1).depends_on(opt_arc_some);
let c4 = dag.add_task(OptionArcConsumer2).depends_on(opt_arc_none); let c4 = dag.add_task(OptionArcConsumer2).depends_on(opt_arc_none);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -805,7 +805,7 @@ async fn test_arc_diamond_dependency() {
let right = dag.add_task(RightBranch).depends_on(top); let right = dag.add_task(RightBranch).depends_on(top);
let bottom = dag.add_task(Bottom).depends_on((&left, &right)); let bottom = dag.add_task(Bottom).depends_on((&left, &right));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -873,7 +873,7 @@ async fn test_arc_empty_collections() {
.add_task(EmptyConsumer) .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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -944,7 +944,7 @@ async fn test_arc_very_large_data() {
let last = dag.add_task(LastSampler).depends_on(producer); let last = dag.add_task(LastSampler).depends_on(producer);
let middle = dag.add_task(MiddleSampler).depends_on(producer); let middle = dag.add_task(MiddleSampler).depends_on(producer);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -981,7 +981,7 @@ async fn test_arc_of_arc() {
let producer = dag.add_task(NestedProducer); 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -1045,7 +1045,7 @@ async fn test_arc_mixed_with_non_arc() {
let unwrap = dag.add_task(Unwrapper).depends_on(arc_prod); let unwrap = dag.add_task(Unwrapper).depends_on(arc_prod);
let wrap = dag.add_task(Wrapper).depends_on(non_arc_prod); let wrap = dag.add_task(Wrapper).depends_on(non_arc_prod);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -1113,7 +1113,7 @@ async fn test_arc_parallel_execution() {
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -1162,7 +1162,7 @@ async fn test_arc_reference_counting() {
let producer = dag.add_task(RefCountProducer); 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -1240,7 +1240,7 @@ async fn test_arc_massive_fanout_performance_comparison() {
let start_without_arc = Instant::now(); let start_without_arc = Instant::now();
dag_without_arc dag_without_arc
.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let duration_without_arc = start_without_arc.elapsed(); let duration_without_arc = start_without_arc.elapsed();
@@ -1294,7 +1294,7 @@ async fn test_arc_massive_fanout_performance_comparison() {
let start_with_arc = Instant::now(); let start_with_arc = Instant::now();
dag_with_arc dag_with_arc
.run(|fut| tokio::spawn(fut).map(Result::unwrap)) .run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let duration_with_arc = start_with_arc.elapsed(); let duration_with_arc = start_with_arc.elapsed();
+10 -10
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner}; use dagx::{DagResult, DagRunner};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -20,7 +20,7 @@ async fn test_1000_level_deep_chain() -> DagResult<()> {
.depends_on(current); .depends_on(current);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(current)?, 999); assert_eq!(dag.get(current)?, 999);
Ok(()) Ok(())
@@ -50,7 +50,7 @@ async fn test_deep_chain_with_branches() -> DagResult<()> {
} }
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(main_chain)?, 499); assert_eq!(dag.get(main_chain)?, 499);
@@ -108,7 +108,7 @@ async fn test_multiple_parallel_deep_chains() -> DagResult<()> {
&chain_ends[7], &chain_ends[7],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Each chain: start + 500 // Each chain: start + 500
// Chain 0: 0 + 500 = 500 // Chain 0: 0 + 500 = 500
@@ -149,7 +149,7 @@ async fn test_deep_chain_execution_order() -> DagResult<()> {
.depends_on(current); .depends_on(current);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(order.load(Ordering::SeqCst), 100); assert_eq!(order.load(Ordering::SeqCst), 100);
assert_eq!(dag.get(current)?, 99); assert_eq!(dag.get(current)?, 99);
@@ -179,7 +179,7 @@ async fn test_deep_binary_tree() -> DagResult<()> {
let root = build_tree(&dag, 10, 1); let root = build_tree(&dag, 10, 1);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Sum of all values in a complete binary tree with values 1024..2047 // Sum of all values in a complete binary tree with values 1024..2047
// This is sum from 2^10 to 2^11-1 = 1024 * 1023 / 2 + 1024 * 512 = 1047552 // This is sum from 2^10 to 2^11-1 = 1024 * 1023 / 2 + 1024 * 512 = 1047552
@@ -209,7 +209,7 @@ async fn test_fibonacci_chain() -> DagResult<()> {
prev1 = next; prev1 = next;
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// 50th Fibonacci number (0-indexed) = 7778742049 // 50th Fibonacci number (0-indexed) = 7778742049
assert_eq!(dag.get(prev1)?, 7778742049); assert_eq!(dag.get(prev1)?, 7778742049);
@@ -232,7 +232,7 @@ async fn test_deep_chain_with_accumulator() -> DagResult<()> {
.depends_on(current); .depends_on(current);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
let result = dag.get(current)?; let result = dag.get(current)?;
assert_eq!(result, 20100); // sum of 1..=200 assert_eq!(result, 20100); // sum of 1..=200
@@ -270,7 +270,7 @@ async fn test_zigzag_dependencies() -> DagResult<()> {
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b)) .add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
.depends_on((&chain_a, &chain_b)); .depends_on((&chain_a, &chain_b));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
let result = dag.get(final_task)?; let result = dag.get(final_task)?;
assert!(result > 100); assert!(result > 100);
@@ -293,7 +293,7 @@ async fn test_10000_level_chain_stress() -> DagResult<()> {
.depends_on(current); .depends_on(current);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(current)?, 9_999); assert_eq!(dag.get(current)?, 9_999);
Ok(()) Ok(())
+6 -6
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner}; use dagx::{DagResult, DagRunner};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -23,7 +23,7 @@ async fn test_10000_independent_tasks() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Verify all tasks completed // Verify all tasks completed
assert_eq!(counter.load(Ordering::Relaxed), 10_000); assert_eq!(counter.load(Ordering::Relaxed), 10_000);
@@ -100,7 +100,7 @@ async fn test_5000_node_pyramid() -> DagResult<()> {
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b)) .add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
.depends_on((&current_layer[0], &current_layer[1])); .depends_on((&current_layer[0], &current_layer[1]));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// We created 1024 ones and 1024 zeros at the bottom // We created 1024 ones and 1024 zeros at the bottom
// The sum should propagate up to 1024 // The sum should propagate up to 1024
@@ -209,7 +209,7 @@ async fn test_wide_dag_1000_sources_1000_sinks() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Verify some sinks completed correctly // Verify some sinks completed correctly
let result0 = dag.get(sinks[0])?; let result0 = dag.get(sinks[0])?;
@@ -258,7 +258,7 @@ async fn test_10000_node_linear_chain_segments() -> DagResult<()> {
chain_ends.push(current); chain_ends.push(current);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// All 10,000 tasks should have executed // All 10,000 tasks should have executed
assert_eq!(counter.load(Ordering::Relaxed), 10_000); assert_eq!(counter.load(Ordering::Relaxed), 10_000);
@@ -297,7 +297,7 @@ async fn test_100000_nodes_stress() -> DagResult<()> {
.collect(); .collect();
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(completed.load(Ordering::Relaxed), 100_000); assert_eq!(completed.load(Ordering::Relaxed), 100_000);
Ok(()) Ok(())
+9 -9
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner, TaskHandle}; use dagx::{DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::marker::PhantomData; use std::marker::PhantomData;
#[tokio::test] #[tokio::test]
@@ -37,7 +37,7 @@ async fn test_zero_sized_types_throughout() -> DagResult<()> {
})) }))
.depends_on(t2); .depends_on(t2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(t1)?, Empty); assert_eq!(dag.get(t1)?, Empty);
assert_eq!(dag.get(t2)?, 42); assert_eq!(dag.get(t2)?, 42);
@@ -72,7 +72,7 @@ async fn test_large_value_types() -> DagResult<()> {
})) }))
.depends_on(t1); .depends_on(t1);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(t2)?, 1042); assert_eq!(dag.get(t2)?, 1042);
@@ -95,7 +95,7 @@ async fn test_unit_type_chains() -> DagResult<()> {
.add_task(task_fn::<(), _, _>(|_: ()| "done")) .add_task(task_fn::<(), _, _>(|_: ()| "done"))
.depends_on((t3,)); .depends_on((t3,));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
dag.get(t1)?; // Verify no error dag.get(t1)?; // Verify no error
dag.get(t2)?; dag.get(t2)?;
@@ -145,7 +145,7 @@ async fn test_string_types_variety() -> DagResult<()> {
)) ))
.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?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
let result = dag.get(combined)?; let result = dag.get(combined)?;
assert!(result.contains("static str")); assert!(result.contains("static str"));
@@ -178,7 +178,7 @@ async fn test_generic_type_constraints() -> DagResult<()> {
)) ))
.depends_on((t1, t2, t3)); .depends_on((t1, t2, t3));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
let result = dag.get(combined)?; let result = dag.get(combined)?;
assert!(result.contains("Wrapper(42)")); assert!(result.contains("Wrapper(42)"));
@@ -204,7 +204,7 @@ async fn test_reference_wrapper_types() -> DagResult<()> {
.add_task(task_fn::<i32, _, _>(|&val: &i32| val * 2)) .add_task(task_fn::<i32, _, _>(|&val: &i32| val * 2))
.depends_on(t1); .depends_on(t1);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(t2)?, 200); assert_eq!(dag.get(t2)?, 200);
@@ -231,7 +231,7 @@ async fn test_array_types() -> DagResult<()> {
)) ))
.depends_on((t1, t2)); .depends_on((t1, t2));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(t3)?, 55); assert_eq!(dag.get(t3)?, 55);
@@ -270,7 +270,7 @@ async fn test_enum_variants() -> DagResult<()> {
)) ))
.depends_on((t1, t2, t3, t4)); .depends_on((t1, t2, t3, t4));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert!(dag.get(combined)?); assert!(dag.get(combined)?);
+12 -12
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagResult, DagRunner}; use dagx::{task, DagResult, DagRunner};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use tokio::task::yield_now; use tokio::task::yield_now;
@@ -12,7 +12,7 @@ async fn test_empty_dag_execution() -> DagResult<()> {
// Test that an empty DAG can be created and run without issues // Test that an empty DAG can be created and run without issues
let dag = DagRunner::new(); let dag = DagRunner::new();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Should complete successfully with no tasks // Should complete successfully with no tasks
Ok(()) Ok(())
@@ -25,7 +25,7 @@ async fn test_single_task_no_deps() -> DagResult<()> {
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42)); let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(task)?, 42); assert_eq!(dag.get(task)?, 42);
Ok(()) Ok(())
@@ -44,7 +44,7 @@ async fn test_single_task_unit_input_output() -> DagResult<()> {
exec.fetch_add(1, Ordering::SeqCst); exec.fetch_add(1, Ordering::SeqCst);
})); }));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
dag.get(task)?; // Just verify it doesn't error dag.get(task)?; // Just verify it doesn't error
assert_eq!(executed.load(Ordering::SeqCst), 1); assert_eq!(executed.load(Ordering::SeqCst), 1);
@@ -61,7 +61,7 @@ async fn test_zero_sized_type_task() -> DagResult<()> {
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| ZeroSized)); let task = dag.add_task(task_fn::<(), _, _>(|_: ()| ZeroSized));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(task)?, ZeroSized); assert_eq!(dag.get(task)?, ZeroSized);
Ok(()) Ok(())
@@ -73,7 +73,7 @@ async fn test_empty_dag_multiple_runs() -> DagResult<()> {
let dag = DagRunner::new(); let dag = DagRunner::new();
for _ in 0..10 { for _ in 0..10 {
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
} }
Ok(()) Ok(())
@@ -88,7 +88,7 @@ async fn test_dag_with_only_source_tasks() -> DagResult<()> {
.map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i))) .map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i)))
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
for (i, task) in tasks.into_iter().enumerate() { for (i, task) in tasks.into_iter().enumerate() {
assert_eq!(dag.get(task)?, i); assert_eq!(dag.get(task)?, i);
@@ -114,7 +114,7 @@ async fn test_single_self_contained_stateful_task() -> DagResult<()> {
let dag = DagRunner::new(); let dag = DagRunner::new();
let task = dag.add_task(Counter { value: 21 }); let task = dag.add_task(Counter { value: 21 });
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(task)?, 42); assert_eq!(dag.get(task)?, 42);
Ok(()) Ok(())
@@ -128,11 +128,11 @@ async fn test_alternating_empty_and_filled_dag_runs() -> DagResult<()> {
if i % 2 == 0 { if i % 2 == 0 {
// Empty DAG // Empty DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
} else { } else {
// DAG with a task // DAG with a task
let task = dag.add_task(task_fn::<(), _, _>(move |_: ()| i)); let task = dag.add_task(task_fn::<(), _, _>(move |_: ()| i));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(task)?, i); assert_eq!(dag.get(task)?, i);
} }
} }
@@ -152,7 +152,7 @@ async fn test_dag_with_never_type_simulation() -> DagResult<()> {
// This task completes immediately but returns a Result containing "never" type // This task completes immediately but returns a Result containing "never" type
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| Result::<i32, Never>::Ok(42))); let task = dag.add_task(task_fn::<(), _, _>(|_: ()| Result::<i32, Never>::Ok(42)));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(task)?, Ok(42)); assert_eq!(dag.get(task)?, Ok(42));
Ok(()) Ok(())
@@ -175,7 +175,7 @@ async fn test_minimal_task_with_minimal_async_work() -> DagResult<()> {
let task = dag.add_task(YieldTask); let task = dag.add_task(YieldTask);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(task)?, 1337); assert_eq!(dag.get(task)?, 1337);
Ok(()) Ok(())
+4 -5
View File
@@ -1,6 +1,5 @@
// Test that custom types work without any trait implementations // Test that custom types work without any trait implementations
use dagx::{task, DagRunner, TaskHandle}; use dagx::{task, DagRunner, TaskHandle};
use futures::FutureExt;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Person { struct Person {
@@ -57,7 +56,7 @@ async fn test_custom_type_single_dependency() {
let fetch = dag.add_task(FetchPerson); 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -73,7 +72,7 @@ async fn test_custom_type_passthrough() {
let transform = dag.add_task(PersonToCompany).depends_on(fetch); let transform = dag.add_task(PersonToCompany).depends_on(fetch);
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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -96,7 +95,7 @@ async fn test_custom_type_diamond_pattern() {
let path_a = dag.add_task(ProcessPerson).depends_on(fetch); let path_a = dag.add_task(ProcessPerson).depends_on(fetch);
let path_b = dag.add_task(PersonToCompany).depends_on(fetch); let path_b = dag.add_task(PersonToCompany).depends_on(fetch);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -116,7 +115,7 @@ async fn test_custom_type_fan_out() {
let process2 = 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 process3 = dag.add_task(ProcessPerson).depends_on(fetch);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+1 -2
View File
@@ -4,7 +4,6 @@
//! prevents it through the type-state pattern. //! prevents it through the type-state pattern.
use dagx::{task, DagRunner, TaskHandle}; use dagx::{task, DagRunner, TaskHandle};
use futures::FutureExt;
/// Demonstrates that TaskBuilder is consumed by depends_on, /// Demonstrates that TaskBuilder is consumed by depends_on,
/// preventing you from wiring the same task multiple times /// preventing you from wiring the same task multiple times
@@ -271,7 +270,7 @@ async fn test_type_safety_prevents_invalid_graphs() {
let result = dag.add_task(Aggregate).depends_on((&t1, &t2)); let result = dag.add_task(Aggregate).depends_on((&t1, &t2));
// Execute and verify // Execute and verify
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+5 -5
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagResult, DagRunner, TaskHandle}; use dagx::{task, DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
#[tokio::test] #[tokio::test]
@@ -79,7 +79,7 @@ async fn test_dependency_resolution_order() -> DagResult<()> {
.depends_on(d) .depends_on(d)
}; };
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(e)?, 5); assert_eq!(dag.get(e)?, 5);
@@ -113,7 +113,7 @@ async fn test_transitive_dependencies() -> DagResult<()> {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5))
.depends_on(b); .depends_on(b);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(a)?, 10); assert_eq!(dag.get(a)?, 10);
assert_eq!(dag.get(b)?, 20); assert_eq!(dag.get(b)?, 20);
@@ -136,7 +136,7 @@ async fn test_deep_chain_50_levels() -> DagResult<()> {
handles.push(next); handles.push(next);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(handles.last().unwrap())?, 50); assert_eq!(dag.get(handles.last().unwrap())?, 50);
Ok(()) Ok(())
@@ -155,7 +155,7 @@ async fn test_deep_chain_200_levels() -> DagResult<()> {
.depends_on(current); .depends_on(current);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(current)?, 201); assert_eq!(dag.get(current)?, 201);
Ok(()) Ok(())
+6 -6
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner, TaskHandle}; use dagx::{DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
#[tokio::test] #[tokio::test]
async fn test_single_dependency() -> DagResult<()> { async fn test_single_dependency() -> DagResult<()> {
@@ -13,7 +13,7 @@ async fn test_single_dependency() -> DagResult<()> {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(source); .depends_on(source);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(dependent)?, 43); assert_eq!(dag.get(dependent)?, 43);
Ok(()) Ok(())
@@ -44,7 +44,7 @@ async fn test_dependency_data_flow() -> DagResult<()> {
.add_task(task_fn::<(i32, i32), _, _>(|(s, p): (&i32, &i32)| s + p)) .add_task(task_fn::<(i32, i32), _, _>(|(s, p): (&i32, &i32)| s + p))
.depends_on((&sum, &product)); .depends_on((&sum, &product));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Note: sum and product are not sinks (final_result depends on them) // Note: sum and product are not sinks (final_result depends on them)
// Only final_result is a sink and can be retrieved // Only final_result is a sink and can be retrieved
@@ -68,7 +68,7 @@ async fn test_dependencies_with_different_types() -> DagResult<()> {
)) ))
.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?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(combined)?, "hello: 42 (true)"); assert_eq!(dag.get(combined)?, "hello: 42 (true)");
Ok(()) Ok(())
@@ -89,7 +89,7 @@ async fn test_shared_dependencies() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Verify all dependents got the correct value from shared // Verify all dependents got the correct value from shared
for (i, handle) in dependents.iter().enumerate() { for (i, handle) in dependents.iter().enumerate() {
@@ -108,7 +108,7 @@ async fn test_multiple_source_nodes() -> DagResult<()> {
.map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i * 10))) .map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i * 10)))
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
for (i, source) in sources.into_iter().enumerate() { for (i, source) in sources.into_iter().enumerate() {
assert_eq!(dag.get(source)?, i as i32 * 10); assert_eq!(dag.get(source)?, i as i32 * 10);
+8 -8
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner}; use dagx::{DagResult, DagRunner};
use futures::FutureExt;
#[tokio::test] #[tokio::test]
async fn test_two_dependencies() -> DagResult<()> { async fn test_two_dependencies() -> DagResult<()> {
@@ -14,7 +14,7 @@ async fn test_two_dependencies() -> DagResult<()> {
.add_task(task_fn::<(i32, i32), _, _>(|(x, y): (&i32, &i32)| x + y)) .add_task(task_fn::<(i32, i32), _, _>(|(x, y): (&i32, &i32)| x + y))
.depends_on((a, b)); .depends_on((a, b));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 30); assert_eq!(dag.get(sum)?, 30);
Ok(()) Ok(())
@@ -33,7 +33,7 @@ async fn test_three_dependencies() -> DagResult<()> {
)) ))
.depends_on((a, b, c)); .depends_on((a, b, c));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 6); assert_eq!(dag.get(sum)?, 6);
Ok(()) Ok(())
@@ -53,7 +53,7 @@ async fn test_four_dependencies() -> DagResult<()> {
)) ))
.depends_on((&deps[0], &deps[1], &deps[2], &deps[3])); .depends_on((&deps[0], &deps[1], &deps[2], &deps[3]));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 10); // 1+2+3+4 assert_eq!(dag.get(sum)?, 10); // 1+2+3+4
Ok(()) Ok(())
@@ -73,7 +73,7 @@ async fn test_five_dependencies() -> DagResult<()> {
)) ))
.depends_on((&deps[0], &deps[1], &deps[2], &deps[3], &deps[4])); .depends_on((&deps[0], &deps[1], &deps[2], &deps[3], &deps[4]));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 15); // 1+2+3+4+5 assert_eq!(dag.get(sum)?, 15); // 1+2+3+4+5
Ok(()) Ok(())
@@ -93,7 +93,7 @@ async fn test_six_dependencies() -> DagResult<()> {
)) ))
.depends_on((&deps[0], &deps[1], &deps[2], &deps[3], &deps[4], &deps[5])); .depends_on((&deps[0], &deps[1], &deps[2], &deps[3], &deps[4], &deps[5]));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 21); // 1+2+3+4+5+6 assert_eq!(dag.get(sum)?, 21); // 1+2+3+4+5+6
Ok(()) Ok(())
@@ -117,7 +117,7 @@ async fn test_seven_dependencies() -> DagResult<()> {
&deps[0], &deps[1], &deps[2], &deps[3], &deps[4], &deps[5], &deps[6], &deps[0], &deps[1], &deps[2], &deps[3], &deps[4], &deps[5], &deps[6],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 28); // 1+2+3+4+5+6+7 assert_eq!(dag.get(sum)?, 28); // 1+2+3+4+5+6+7
Ok(()) Ok(())
@@ -141,7 +141,7 @@ async fn test_eight_dependencies() -> DagResult<()> {
&deps[0], &deps[1], &deps[2], &deps[3], &deps[4], &deps[5], &deps[6], &deps[7], &deps[0], &deps[1], &deps[2], &deps[3], &deps[4], &deps[5], &deps[6], &deps[7],
)); ));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 36); // Sum of 1..=8 assert_eq!(dag.get(sum)?, 36); // Sum of 1..=8
Ok(()) Ok(())
+11 -8
View File
@@ -2,7 +2,6 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagError, DagRunner, TaskHandle}; use dagx::{DagError, DagRunner, TaskHandle};
use futures::FutureExt;
#[tokio::test] #[tokio::test]
async fn test_result_not_found_error() { async fn test_result_not_found_error() {
@@ -15,7 +14,7 @@ async fn test_result_not_found_error() {
assert!(matches!(result, Err(DagError::ResultNotFound { .. }))); assert!(matches!(result, Err(DagError::ResultNotFound { .. })));
// Run and verify it works after // Run and verify it works after
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -33,7 +32,7 @@ async fn test_nested_result_error_handling() {
let task2 = dag.add_task(task_fn::<(), _, _>(|_: ()| Result::<i32, String>::Ok(42))); let task2 = dag.add_task(task_fn::<(), _, _>(|_: ()| Result::<i32, String>::Ok(42)));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -48,7 +47,7 @@ async fn test_option_none_not_error() {
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| None::<i32>)); let task = dag.add_task(task_fn::<(), _, _>(|_: ()| None::<i32>));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -77,7 +76,7 @@ async fn test_custom_error_types() {
}) })
})); }));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -106,7 +105,9 @@ async fn test_error_in_tuple_dependency() {
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b)) .add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| 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; let result = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
assert!(result.is_err()); assert!(result.is_err());
assert!(dag.get(dependent).is_err()); assert!(dag.get(dependent).is_err());
@@ -124,7 +125,9 @@ async fn test_string_panic_vs_structured_panic() {
panic!("Formatted panic: value={}, code={}", 42, "ERROR"); panic!("Formatted panic: value={}, code={}", 42, "ERROR");
})); }));
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// Both should result in errors // Both should result in errors
assert!(dag.get(string_panic).is_err()); assert!(dag.get(string_panic).is_err());
@@ -144,7 +147,7 @@ async fn test_anyhow_like_error_chain() {
outer outer
})); }));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+21 -9
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagRunner, TaskHandle}; use dagx::{task, DagRunner, TaskHandle};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@@ -25,7 +25,9 @@ async fn test_linear_error_propagation() {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 2)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x * 2))
.depends_on(t3); .depends_on(t3);
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// t1 succeeds // t1 succeeds
assert_eq!(dag.get(t1).unwrap(), 1); assert_eq!(dag.get(t1).unwrap(), 1);
@@ -64,7 +66,9 @@ async fn test_diamond_error_propagation() {
.add_task(task_fn::<(i32, i32), _, _>(|(l, r): (&i32, &i32)| l + r)) .add_task(task_fn::<(i32, i32), _, _>(|(l, r): (&i32, &i32)| l + r))
.depends_on((&left, &right)); .depends_on((&left, &right));
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
assert_eq!(dag.get(source).unwrap(), 100); assert_eq!(dag.get(source).unwrap(), 100);
assert_eq!(dag.get(left).unwrap(), 50); assert_eq!(dag.get(left).unwrap(), 50);
@@ -110,7 +114,9 @@ async fn test_error_stops_at_boundary() {
} }
})); }));
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// Error branch: source runs but dependent doesn't // Error branch: source runs but dependent doesn't
assert!(dag.get(error_source).is_err()); assert!(dag.get(error_source).is_err());
@@ -149,7 +155,9 @@ async fn test_multiple_error_sources_convergence() {
)) ))
.depends_on((&error1, &error2, &success)); .depends_on((&error1, &error2, &success));
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// All error sources fail // All error sources fail
assert!(dag.get(error1).is_err()); assert!(dag.get(error1).is_err());
@@ -180,7 +188,9 @@ async fn test_error_in_wide_fanout() {
}) })
.collect(); .collect();
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// Source fails // Source fails
assert!(dag.get(source).is_err()); assert!(dag.get(source).is_err());
@@ -225,7 +235,7 @@ async fn test_selective_error_propagation() {
})) }))
.depends_on(handler); .depends_on(handler);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -291,7 +301,9 @@ async fn test_error_propagation_timing() {
})) }))
.depends_on(t2); .depends_on(t2);
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
let order = propagation_order.lock().clone(); let order = propagation_order.lock().clone();
@@ -364,7 +376,7 @@ async fn test_partial_branch_failure_propagation() {
)) ))
.depends_on((&a3, &b3, &c3)); .depends_on((&a3, &b3, &c3));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.ok(); .ok();
+20 -9
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner}; use dagx::{DagResult, DagRunner};
use futures::FutureExt;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -24,7 +24,9 @@ async fn test_fallback_on_error() -> DagResult<()> {
let _selector = dag.add_task(task_fn::<(), _, _>(|_: ()| {})); let _selector = dag.add_task(task_fn::<(), _, _>(|_: ()| {}));
// Run DAG // Run DAG
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// Primary should fail // Primary should fail
assert!(dag.get(primary).is_err()); assert!(dag.get(primary).is_err());
@@ -58,7 +60,8 @@ async fn test_retry_pattern_simulation() -> DagResult<()> {
} }
})); }));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Task completes with error on first "attempt" // Task completes with error on first "attempt"
assert_eq!(dag.get(task)?, Err("Simulated failure")); assert_eq!(dag.get(task)?, Err("Simulated failure"));
@@ -99,7 +102,8 @@ async fn test_circuit_breaker_pattern() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// First few tasks fail and open circuit // First few tasks fail and open circuit
for task in tasks.into_iter().take(4) { for task in tasks.into_iter().take(4) {
@@ -131,7 +135,9 @@ async fn test_partial_recovery_with_defaults() -> DagResult<()> {
vec![0, 10, 20, 0, 40, 50, 0, 70, 80, 0] // 0 for failed tasks vec![0, 10, 20, 0, 40, 50, 0, 70, 80, 0] // 0 for failed tasks
})); }));
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
let result = dag.get(aggregator)?; let result = dag.get(aggregator)?;
assert_eq!(result.len(), 10); assert_eq!(result.len(), 10);
@@ -159,7 +165,8 @@ async fn test_error_accumulation_pattern() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Check accumulated errors // Check accumulated errors
let error_list = errors.lock().clone(); let error_list = errors.lock().clone();
@@ -197,7 +204,8 @@ async fn test_graceful_degradation() -> DagResult<()> {
})) }))
.depends_on(critical); .depends_on(critical);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Critical path works // Critical path works
assert_eq!(dag.get(final_task)?, 15); assert_eq!(dag.get(final_task)?, 15);
@@ -228,7 +236,8 @@ async fn test_error_boundary_isolation() -> DagResult<()> {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5))
.depends_on(b2); .depends_on(b2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Group A fails (returns Err) // Group A fails (returns Err)
assert_eq!(dag.get(a2)?, Err("Group A error")); assert_eq!(dag.get(a2)?, Err("Group A error"));
@@ -261,7 +270,9 @@ async fn test_compensation_action() -> DagResult<()> {
} }
})); }));
let _ = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let _ = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
// Action failed // Action failed
assert!(dag.get(action).is_err()); assert!(dag.get(action).is_err());
+13 -14
View File
@@ -1,13 +1,12 @@
// Basic execution tests for DagRunner // Basic execution tests for DagRunner
use crate::common::task_fn; use crate::common::task_fn;
use futures::FutureExt;
use dagx::*; use dagx::*;
#[tokio::test] #[tokio::test]
async fn test_empty_dag() { async fn test_empty_dag() {
let dag = DagRunner::new(); let dag = DagRunner::new();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); // Should complete without error .unwrap(); // Should complete without error
} }
@@ -16,7 +15,7 @@ async fn test_empty_dag() {
async fn test_single_task() { async fn test_single_task() {
let dag = DagRunner::new(); let dag = DagRunner::new();
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42)); let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(task).unwrap(), 42); assert_eq!(dag.get(task).unwrap(), 42);
@@ -40,7 +39,7 @@ async fn test_deep_chain() {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(d); .depends_on(d);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -57,7 +56,7 @@ async fn test_wide_parallel() {
.map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i * 2))) .map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i * 2)))
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -81,7 +80,7 @@ async fn test_diamond_dependency() {
.add_task(task_fn::<(i32, i32), _, _>(|(x, y): (&i32, &i32)| x + y)) .add_task(task_fn::<(i32, i32), _, _>(|(x, y): (&i32, &i32)| x + y))
.depends_on((&b, &c)); .depends_on((&b, &c));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -107,7 +106,7 @@ async fn test_different_output_types() {
age: 30, age: 30,
})); }));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -140,7 +139,7 @@ async fn test_multiple_sinks() {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 3)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x * 3))
.depends_on(branch2); .depends_on(branch2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); // Should wait for both sinks .unwrap(); // Should wait for both sinks
@@ -162,7 +161,7 @@ async fn test_single_task_inline_path() {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5))
.depends_on(t2); .depends_on(t2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -187,7 +186,7 @@ async fn test_multi_task_spawn_path() {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 3)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x + 3))
.depends_on(source); .depends_on(source);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -213,7 +212,7 @@ async fn test_producer_consumer_channels() {
})) }))
.depends_on(producer); .depends_on(producer);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -238,7 +237,7 @@ async fn test_multi_consumer_fanout() {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x - 5)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x - 5))
.depends_on(producer); .depends_on(producer);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -266,7 +265,7 @@ async fn test_compute_layers_with_dependents_tracking() {
.add_task(task_fn::<(i32, i32), _, _>(|(l, r): (&i32, &i32)| l + r)) .add_task(task_fn::<(i32, i32), _, _>(|(l, r): (&i32, &i32)| l + r))
.depends_on((&left, &right)); .depends_on((&left, &right));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -308,7 +307,7 @@ async fn test_layer_execution_order() {
})) }))
.depends_on(t2); .depends_on(t2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+21 -11
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner, Task}; use dagx::{DagResult, DagRunner, Task};
use futures::FutureExt;
use std::time::Instant; use std::time::Instant;
use tokio::time::{sleep, Duration}; use tokio::time::{sleep, Duration};
@@ -68,7 +68,8 @@ async fn integration_test_etl_pipeline() -> DagResult<()> {
let final_result = dag.add_task(Add).depends_on((&combine12, &transform3)); let final_result = dag.add_task(Add).depends_on((&combine12, &transform3));
// Execute pipeline // Execute pipeline
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify // Verify
let result = dag.get(final_result)?; let result = dag.get(final_result)?;
@@ -98,7 +99,8 @@ async fn integration_test_multi_layer_dag() -> DagResult<()> {
// Layer 4: Final result // Layer 4: Final result
let final_result = dag.add_task(Add).depends_on((&double_ab, &double_bc)); let final_result = dag.add_task(Add).depends_on((&double_ab, &double_bc));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let result = dag.get(final_result)?; let result = dag.get(final_result)?;
// (1+2)*2 + (2+3)*2 = 6 + 10 = 16 // (1+2)*2 + (2+3)*2 = 6 + 10 = 16
@@ -119,7 +121,8 @@ async fn integration_test_multiple_sinks() -> DagResult<()> {
let branch2 = dag.add_task(Multiply::new(3)).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 branch3 = dag.add_task(Multiply::new(4)).depends_on(source);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// All branches should complete // All branches should complete
assert_eq!(dag.get(branch1)?, 20); assert_eq!(dag.get(branch1)?, 20);
@@ -145,7 +148,8 @@ async fn integration_test_diamond_cascade() -> DagResult<()> {
let right2 = dag.add_task(Multiply::new(3)).depends_on(sink1); let right2 = dag.add_task(Multiply::new(3)).depends_on(sink1);
let sink2 = dag.add_task(Add).depends_on((&left2, &right2)); let sink2 = dag.add_task(Add).depends_on((&left2, &right2));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let result = dag.get(sink2)?; let result = dag.get(sink2)?;
// Diamond 1: (10*2) + (10*3) = 50 // Diamond 1: (10*2) + (10*3) = 50
@@ -176,7 +180,8 @@ async fn integration_test_wide_and_deep() -> DagResult<()> {
final_nodes.push(step3); final_nodes.push(step3);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify each chain // Verify each chain
for (i, node) in final_nodes.iter().enumerate() { for (i, node) in final_nodes.iter().enumerate() {
@@ -195,7 +200,8 @@ async fn integration_test_error_recovery() -> DagResult<()> {
let source = dag.add_task(LoadValue::new(42)); 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?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Should be able to access results // Should be able to access results
assert_eq!(dag.get(transform)?, 84); assert_eq!(dag.get(transform)?, 84);
@@ -231,7 +237,8 @@ async fn integration_test_large_scale() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify some results // Verify some results
assert_eq!(dag.get(aggregations[0])?, 1); // First two assert_eq!(dag.get(aggregations[0])?, 1); // First two
@@ -255,7 +262,8 @@ async fn integration_test_reused_values() -> DagResult<()> {
// Combine some of the results // Combine some of the results
let combined = dag.add_task(Add).depends_on((&double, &triple)); let combined = dag.add_task(Add).depends_on((&double, &triple));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(double)?, 200); assert_eq!(dag.get(double)?, 200);
assert_eq!(dag.get(triple)?, 300); assert_eq!(dag.get(triple)?, 300);
@@ -284,7 +292,8 @@ async fn integration_test_parallel_execution_timing() -> DagResult<()> {
.collect(); .collect();
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let elapsed = start.elapsed(); let elapsed = start.elapsed();
// Verify all tasks completed // Verify all tasks completed
@@ -345,7 +354,8 @@ async fn integration_test_parallel_vs_sequential_timing() -> DagResult<()> {
.depends_on(seq2); .depends_on(seq2);
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let elapsed = start.elapsed(); let elapsed = start.elapsed();
// Verify results // Verify results
+9 -7
View File
@@ -3,7 +3,6 @@ use crate::common::task_fn;
use crate::common::tasks::Counter; use crate::common::tasks::Counter;
use dagx::*; use dagx::*;
use futures::FutureExt;
#[tokio::test] #[tokio::test]
async fn test_result_type() { async fn test_result_type() {
@@ -14,7 +13,7 @@ async fn test_result_type() {
Err::<i32, String>("error".to_string()) Err::<i32, String>("error".to_string())
})); }));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -29,7 +28,8 @@ async fn test_dag_result_type_works() {
// Test that DagResult<()> works with ? operator pattern // Test that DagResult<()> works with ? operator pattern
async fn run_dag(dag: &DagRunner) -> DagResult<()> { async fn run_dag(dag: &DagRunner) -> DagResult<()> {
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
Ok(()) Ok(())
} }
@@ -64,7 +64,7 @@ async fn test_error_messages_are_helpful() {
let err_msg = format!("{}", result.unwrap_err()); let err_msg = format!("{}", result.unwrap_err());
assert!(err_msg.contains("Result not found")); assert!(err_msg.contains("Result not found"));
assert!(err_msg.contains("task #0")); // Task ID assert!(err_msg.contains("task #0")); // Task ID
assert!(err_msg.contains("Call dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))")); assert!(err_msg.contains("Call dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })"));
} }
#[tokio::test] #[tokio::test]
@@ -73,7 +73,9 @@ async fn test_successful_execution_returns_ok() {
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42)); let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
// Should return Ok(()) // Should return Ok(())
let result = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await; let result = dag
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await;
assert!(result.is_ok()); assert!(result.is_ok());
// Should be able to get value // Should be able to get value
@@ -87,7 +89,7 @@ async fn test_stateful_tasks() {
let input = dag.add_task(task_fn::<(), _, _>(|_: ()| 5)); let input = dag.add_task(task_fn::<(), _, _>(|_: ()| 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -107,7 +109,7 @@ async fn test_task_fn_with_captured_state() {
.add_task(task_fn::<i32, _, _>(move |&x: &i32| x * multiplier)) .add_task(task_fn::<i32, _, _>(move |&x: &i32| x * multiplier))
.depends_on(base); .depends_on(base);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+10 -10
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@@ -31,7 +31,7 @@ async fn test_concurrent_run_calls() {
for _ in 0..5 { for _ in 0..5 {
let dag = Arc::clone(&dag); let dag = Arc::clone(&dag);
handles.spawn(async move { dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await }); handles.spawn(async move { dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await });
} }
// Only one run should succeed, others should fail with concurrent execution error // Only one run should succeed, others should fail with concurrent execution error
@@ -66,7 +66,7 @@ async fn test_concurrent_execution_and_building() {
.collect(); .collect();
// Execute the initial DAG // Execute the initial DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -95,7 +95,7 @@ async fn test_concurrent_execution_and_building() {
} }
// Execute again with the new tasks // Execute again with the new tasks
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
} }
@@ -139,7 +139,7 @@ async fn test_dag_builder_thread_safety() {
assert_eq!(counter.load(Ordering::SeqCst), 10); assert_eq!(counter.load(Ordering::SeqCst), 10);
// Execute the combined DAG // Execute the combined DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -161,7 +161,7 @@ async fn test_concurrent_get_operations() {
.map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i))) .map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i)))
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -213,7 +213,7 @@ async fn test_no_race_in_dependency_tracking() {
} }
// Execute // Execute
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -273,7 +273,7 @@ async fn test_high_concurrency_stress() {
assert_eq!(completed.load(Ordering::SeqCst), 1000); assert_eq!(completed.load(Ordering::SeqCst), 1000);
// The DAG should still be executable // The DAG should still be executable
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
} }
@@ -363,7 +363,7 @@ async fn test_atomic_dag_operations() {
assert_eq!(deps.len(), 50); assert_eq!(deps.len(), 50);
// Execute and verify // Execute and verify
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -416,7 +416,7 @@ async fn test_no_deadlock_on_circular_waiting() {
assert!(result.is_ok(), "Deadlock detected - operation timed out"); assert!(result.is_ok(), "Deadlock detected - operation timed out");
// Should be able to execute the DAG // Should be able to execute the DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
} }
+4 -4
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagResult, DagRunner, TaskHandle}; use dagx::{task, DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::time::sleep; use tokio::time::sleep;
@@ -87,7 +87,7 @@ async fn test_layers_execute_in_parallel() -> DagResult<()> {
.depends_on((&layer1[0], &layer1[1], &layer1[2])) .depends_on((&layer1[0], &layer1[1], &layer1[2]))
}; };
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(final_task)?, 33); // (0+1) + (10+1) + (20+1) assert_eq!(dag.get(final_task)?, 33); // (0+1) + (10+1) + (20+1)
@@ -213,7 +213,7 @@ async fn test_completion_order_matches_dependencies() -> DagResult<()> {
.depends_on(c) .depends_on(c)
}; };
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(d)?, 6); // (1 + 2) * 2 assert_eq!(dag.get(d)?, 6); // (1 + 2) * 2
@@ -313,7 +313,7 @@ async fn test_dependent_tasks_respect_ordering() -> DagResult<()> {
.depends_on(c) .depends_on(c)
}; };
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
// Verify results // Verify results
assert_eq!(dag.get(a)?, 1); assert_eq!(dag.get(a)?, 1);
+3 -2
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner}; use dagx::{DagResult, DagRunner};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -27,7 +27,8 @@ async fn test_spawner_actually_spawns_tasks() -> DagResult<()> {
.collect(); .collect();
// Custom spawner that counts invocations // Custom spawner that counts invocations
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify all tasks were spawned // Verify all tasks were spawned
for (i, task) in tasks.into_iter().enumerate() { for (i, task) in tasks.into_iter().enumerate() {
+9 -5
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagResult, DagRunner, TaskHandle}; use dagx::{task, DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@@ -52,7 +52,8 @@ async fn test_tasks_run_on_different_threads() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify all tasks completed // Verify all tasks completed
for task in tasks.into_iter() { for task in tasks.into_iter() {
@@ -129,7 +130,8 @@ async fn test_concurrent_execution_with_atomic_counter() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify all tasks completed // Verify all tasks completed
for (i, task) in tasks.into_iter().enumerate() { for (i, task) in tasks.into_iter().enumerate() {
@@ -212,7 +214,8 @@ async fn test_diamond_parallel_execution() -> DagResult<()> {
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b)) .add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
.depends_on((&parallel1, &parallel2)); .depends_on((&parallel1, &parallel2));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(sink)?, 500); // (100 * 2) + (100 * 3) assert_eq!(dag.get(sink)?, 500); // (100 * 2) + (100 * 3)
@@ -279,7 +282,8 @@ async fn test_massive_parallel_fanout() -> DagResult<()> {
.collect(); .collect();
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let elapsed = start.elapsed(); let elapsed = start.elapsed();
// All should complete // All should complete
+3 -2
View File
@@ -1,7 +1,7 @@
//! Tests for timing and speedup verification //! Tests for timing and speedup verification
use dagx::{task, DagResult, DagRunner}; use dagx::{task, DagResult, DagRunner};
use futures::FutureExt;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::time::sleep; use tokio::time::sleep;
@@ -29,7 +29,8 @@ async fn test_parallel_execution_speedup() -> DagResult<()> {
.collect(); .collect();
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let elapsed = start.elapsed(); let elapsed = start.elapsed();
// Verify all tasks completed // Verify all tasks completed
+9 -5
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner, TaskHandle}; use dagx::{DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -52,7 +52,8 @@ async fn test_butterfly_network() -> DagResult<()> {
.depends_on((&layer1[3], &layer1[7])), .depends_on((&layer1[3], &layer1[7])),
]; ];
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify some outputs exist // Verify some outputs exist
for task in &layer2 { for task in &layer2 {
@@ -107,7 +108,8 @@ async fn test_recursive_butterfly() -> DagResult<()> {
let outputs = build_butterfly(&dag, inputs); let outputs = build_butterfly(&dag, inputs);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(outputs.len(), 4); assert_eq!(outputs.len(), 4);
for output in outputs { for output in outputs {
@@ -158,7 +160,8 @@ async fn test_benes_network() -> DagResult<()> {
.depends_on((&stage1[1], &stage1[3])), .depends_on((&stage1[1], &stage1[3])),
]; ];
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
for output in outputs { for output in outputs {
let _ = dag.get(output)?; let _ = dag.get(output)?;
@@ -212,7 +215,8 @@ async fn test_shuffle_exchange_network() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(counter.load(Ordering::Relaxed), 8); assert_eq!(counter.load(Ordering::Relaxed), 8);
+11 -6
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner, TaskHandle}; use dagx::{DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -60,7 +60,8 @@ async fn test_workflow_with_conditional_paths() -> DagResult<()> {
})) }))
.depends_on(combine); .depends_on(combine);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(process)?, 84); assert_eq!(dag.get(process)?, 84);
let result = dag.get(final_result)?; let result = dag.get(final_result)?;
@@ -147,7 +148,8 @@ async fn test_map_reduce_pattern() -> DagResult<()> {
)) ))
.depends_on((&reducers[0], &reducers[1], &reducers[2], &reducers[3])); .depends_on((&reducers[0], &reducers[1], &reducers[2], &reducers[3]));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let result = dag.get(final_task)?; let result = dag.get(final_task)?;
assert!(result > 0); assert!(result > 0);
@@ -198,7 +200,8 @@ async fn test_pipeline_with_feedback() -> DagResult<()> {
})) }))
.depends_on(stage3); .depends_on(stage3);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(stage1)?, 2); assert_eq!(dag.get(stage1)?, 2);
assert_eq!(dag.get(stage3)?, 12); assert_eq!(dag.get(stage3)?, 12);
@@ -244,7 +247,8 @@ async fn test_scatter_gather_pattern() -> DagResult<()> {
)) ))
.depends_on((&workers[0], &workers[1], &workers[2], &workers[3])); .depends_on((&workers[0], &workers[1], &workers[2], &workers[3]));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Sum of 10+20+30+40+50+60+70+80 = 360 // Sum of 10+20+30+40+50+60+70+80 = 360
assert_eq!(dag.get(gather)?, 360); assert_eq!(dag.get(gather)?, 360);
@@ -323,7 +327,8 @@ async fn test_fork_join_with_barriers() -> DagResult<()> {
})) }))
.depends_on(barrier); .depends_on(barrier);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let _ = dag.get(join)?; let _ = dag.get(join)?;
assert_eq!(phase_counter.load(Ordering::SeqCst), 2); assert_eq!(phase_counter.load(Ordering::SeqCst), 2);
+8 -5
View File
@@ -2,7 +2,6 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner}; use dagx::{DagResult, DagRunner};
use futures::FutureExt;
#[tokio::test] #[tokio::test]
async fn test_2d_grid_pattern() -> DagResult<()> { async fn test_2d_grid_pattern() -> DagResult<()> {
@@ -37,7 +36,8 @@ async fn test_2d_grid_pattern() -> DagResult<()> {
} }
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Check corner values // Check corner values
let bottom_right = dag.get(grid[3][3].as_ref().unwrap())?; let bottom_right = dag.get(grid[3][3].as_ref().unwrap())?;
@@ -102,7 +102,8 @@ async fn test_3d_grid_pattern() -> DagResult<()> {
} }
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Check that all cells have values // Check that all cells have values
for row in &grid { for row in &grid {
@@ -176,7 +177,8 @@ async fn test_hexagonal_grid() -> DagResult<()> {
hex_grid.insert((q, r), task); hex_grid.insert((q, r), task);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify center and some ring values // Verify center and some ring values
assert_eq!(dag.get(hex_grid.get(&(0, 0)).unwrap())?, 100); assert_eq!(dag.get(hex_grid.get(&(0, 0)).unwrap())?, 100);
@@ -225,7 +227,8 @@ async fn test_toroidal_grid() -> DagResult<()> {
} }
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify all torus tasks completed // Verify all torus tasks completed
for task in torus_tasks { for task in torus_tasks {
+12 -7
View File
@@ -2,7 +2,6 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagResult, DagRunner, TaskHandle}; use dagx::{DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
#[tokio::test] #[tokio::test]
async fn test_binary_tree_reduction() -> DagResult<()> { async fn test_binary_tree_reduction() -> DagResult<()> {
@@ -36,7 +35,8 @@ async fn test_binary_tree_reduction() -> DagResult<()> {
let root = current_level[0]; let root = current_level[0];
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Sum of powers of 2 from 0 to 7: 1+2+4+8+16+32+64+128 = 255 // Sum of powers of 2 from 0 to 7: 1+2+4+8+16+32+64+128 = 255
assert_eq!(dag.get(root)?, 255); assert_eq!(dag.get(root)?, 255);
@@ -67,7 +67,8 @@ async fn test_n_ary_tree() -> DagResult<()> {
let root = build_tree(&dag, 3, 1); let root = build_tree(&dag, 3, 1);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let result = dag.get(root)?; let result = dag.get(root)?;
assert!(result > 0); assert!(result > 0);
@@ -114,7 +115,8 @@ async fn test_unbalanced_tree() -> DagResult<()> {
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a * b)) .add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a * b))
.depends_on((&a, &b)); .depends_on((&a, &b));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(f)?, 1); assert_eq!(dag.get(f)?, 1);
assert_eq!(dag.get(c)?, 2); assert_eq!(dag.get(c)?, 2);
@@ -166,7 +168,8 @@ async fn test_trie_like_structure() -> DagResult<()> {
.add_task(task_fn::<String, _, _>(|v: &String| format!("{}/log", v))) .add_task(task_fn::<String, _, _>(|v: &String| format!("{}/log", v)))
.depends_on(var); .depends_on(var);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(usr_bin)?, "root/usr/bin"); assert_eq!(dag.get(usr_bin)?, "root/usr/bin");
assert_eq!(dag.get(usr_lib)?, "root/usr/lib"); assert_eq!(dag.get(usr_lib)?, "root/usr/lib");
@@ -221,7 +224,8 @@ async fn test_balanced_k_ary_tree() -> DagResult<()> {
let root = create_balanced_tree(&dag, DEPTH, K, 0); let root = create_balanced_tree(&dag, DEPTH, K, 0);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let result = dag.get(root)?; let result = dag.get(root)?;
assert!(result > 0); assert!(result > 0);
@@ -268,7 +272,8 @@ async fn test_merkle_tree_pattern() -> DagResult<()> {
let root_hash = current_level[0]; let root_hash = current_level[0];
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
let result = dag.get(root_hash)?; let result = dag.get(root_hash)?;
assert!(result.starts_with("hash")); assert!(result.starts_with("hash"));
+3 -3
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::DagRunner; use dagx::DagRunner;
use futures::FutureExt;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -27,7 +27,7 @@ async fn test_deep_chain_100_levels() {
// Execute // Execute
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let exec_time = start.elapsed(); let exec_time = start.elapsed();
@@ -88,7 +88,7 @@ async fn test_stress_mixed_patterns() {
// Execute // Execute
let start = Instant::now(); let start = Instant::now();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
let exec_time = start.elapsed(); let exec_time = start.elapsed();
+2 -2
View File
@@ -1,7 +1,7 @@
//! Runtime integration tests - verify dagx works correctly across different runtimes //! Runtime integration tests - verify dagx works correctly across different runtimes
use dagx::{DagResult, DagRunner}; use dagx::{DagResult, DagRunner};
use futures::FutureExt;
struct Value(i32); struct Value(i32);
#[dagx::task] #[dagx::task]
@@ -27,7 +27,7 @@ async fn runtime_integration_tokio() -> DagResult<()> {
let b = dag.add_task(Value(20)); 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?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await?;
assert_eq!(dag.get(sum)?, 30); assert_eq!(dag.get(sum)?, 30);
Ok(()) Ok(())
+1 -1
View File
@@ -15,8 +15,8 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{DagRunner, TaskHandle}; use dagx::{DagRunner, TaskHandle};
use futures::task::SpawnExt;
use futures_executor::ThreadPool; use futures_executor::ThreadPool;
use futures_util::task::SpawnExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
+4 -4
View File
@@ -3,7 +3,7 @@ use crate::common::task_fn;
// Comprehensive test showing all three patterns working together // Comprehensive test showing all three patterns working together
use dagx::*; use dagx::*;
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -53,7 +53,7 @@ async fn test_all_three_task_patterns() {
// Pattern 3: Mutable accumulation // Pattern 3: Mutable accumulation
let accumulated = dag.add_task(MutableAccumulator(10)).depends_on(doubled); // 10 + 16 = 26 let accumulated = dag.add_task(MutableAccumulator(10)).depends_on(doubled); // 10 + 16 = 26
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -90,7 +90,7 @@ async fn test_parallel_execution() {
3 3
})); }));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -111,7 +111,7 @@ async fn test_task_fn_with_captured_state() {
.add_task(task_fn::<i32, _, _>(move |&x: &i32| x * multiplier)) .add_task(task_fn::<i32, _, _>(move |&x: &i32| x * multiplier))
.depends_on(base); .depends_on(base);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+3 -4
View File
@@ -3,7 +3,6 @@ use crate::common::task_fn;
// These tests verify the read-only state pattern using &self // These tests verify the read-only state pattern using &self
use dagx::*; use dagx::*;
use futures::FutureExt;
// Read-only state tasks // Read-only state tasks
struct ReadOnlyValue(i32); struct ReadOnlyValue(i32);
@@ -43,7 +42,7 @@ async fn test_readonly_state_basic() {
let value = dag.add_task(ReadOnlyValue(42)); let value = dag.add_task(ReadOnlyValue(42));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(value).unwrap(), 42); assert_eq!(dag.get(value).unwrap(), 42);
@@ -57,7 +56,7 @@ async fn test_readonly_state_with_input() {
let input = dag.add_task(task_fn::<(), _, _>(|_: ()| 5)); let input = dag.add_task(task_fn::<(), _, _>(|_: ()| 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(result).unwrap(), 35); assert_eq!(dag.get(result).unwrap(), 35);
@@ -84,7 +83,7 @@ async fn test_readonly_state_multiple_uses() {
}; };
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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(result1).unwrap(), 35); // (10 * 3) + 5 assert_eq!(dag.get(result1).unwrap(), 35); // (10 * 3) + 5
+8 -9
View File
@@ -1,6 +1,5 @@
// Stateless task pattern tests // Stateless task pattern tests
use crate::common::task_fn; use crate::common::task_fn;
use futures::FutureExt;
use dagx::*; use dagx::*;
@@ -86,7 +85,7 @@ async fn test_stateless_basic() {
let y = dag.add_task(task_fn::<(), _, _>(|_: ()| 20)); let y = dag.add_task(task_fn::<(), _, _>(|_: ()| 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(sum).unwrap(), 30); assert_eq!(dag.get(sum).unwrap(), 30);
@@ -100,7 +99,7 @@ async fn test_stateless_single_input() {
let input = dag.add_task(task_fn::<(), _, _>(|_: ()| 21)); let input = dag.add_task(task_fn::<(), _, _>(|_: ()| 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(doubled).unwrap(), 42); assert_eq!(dag.get(doubled).unwrap(), 42);
@@ -113,7 +112,7 @@ async fn test_stateless_no_input() {
let source = dag.add_task(StatelessSource); let source = dag.add_task(StatelessSource);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(source).unwrap(), 42); assert_eq!(dag.get(source).unwrap(), 42);
@@ -130,7 +129,7 @@ async fn test_stateless_multiple_inputs() {
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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
assert_eq!(dag.get(result).unwrap(), "test: 42 (true)"); assert_eq!(dag.get(result).unwrap(), "test: 42 (true)");
@@ -169,7 +168,7 @@ async fn test_stateless_mixed_with_stateful() {
// Stateful counter // Stateful counter
let counted = dag.add_task(Counter::new(10)).depends_on(product); let counted = dag.add_task(Counter::new(10)).depends_on(product);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -187,7 +186,7 @@ async fn test_stateless_chain() {
let step2 = dag.add_task(StatelessInc).depends_on(step1); let step2 = dag.add_task(StatelessInc).depends_on(step1);
let step3 = dag.add_task(StatelessInc).depends_on(step2); let step3 = dag.add_task(StatelessInc).depends_on(step2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -208,7 +207,7 @@ async fn test_stateless_parallel() {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -229,7 +228,7 @@ async fn test_stateless_with_string_types() {
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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+15 -8
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagResult, DagRunner, TaskHandle}; use dagx::{task, DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@@ -32,7 +32,8 @@ async fn test_concurrent_result_retrieval() -> DagResult<()> {
.collect(); .collect();
// Execute the DAG // Execute the DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Now try to get results concurrently from multiple threads // Now try to get results concurrently from multiple threads
let mut get_handles = Vec::new(); let mut get_handles = Vec::new();
@@ -83,7 +84,8 @@ async fn test_simultaneous_dag_building_and_execution() -> DagResult<()> {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
// Execute the DAG // Execute the DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Get the additional tasks // Get the additional tasks
let additional_tasks = build_handle.await.unwrap(); let additional_tasks = build_handle.await.unwrap();
@@ -97,7 +99,8 @@ async fn test_simultaneous_dag_building_and_execution() -> DagResult<()> {
// (they need another run cycle) // (they need another run cycle)
if building_complete.load(Ordering::SeqCst) { if building_complete.load(Ordering::SeqCst) {
// Run again for the new tasks // Run again for the new tasks
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Now they should have results // Now they should have results
for (i, task) in additional_tasks.iter().enumerate() { for (i, task) in additional_tasks.iter().enumerate() {
@@ -139,7 +142,8 @@ async fn test_concurrent_dependency_resolution() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Check all completed // Check all completed
assert_eq!(resolution_counter.load(Ordering::SeqCst), 101); assert_eq!(resolution_counter.load(Ordering::SeqCst), 101);
@@ -212,7 +216,8 @@ async fn test_read_write_race_patterns() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Verify readers saw their writer's data // Verify readers saw their writer's data
for reader in &readers { for reader in &readers {
@@ -265,7 +270,8 @@ async fn test_atomic_counter_races() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Final counter should be 200 * 100 = 20000 // Final counter should be 200 * 100 = 20000
assert_eq!(counter.load(Ordering::SeqCst), 20000); assert_eq!(counter.load(Ordering::SeqCst), 20000);
@@ -299,7 +305,8 @@ async fn test_multiple_dag_runners_interaction() -> DagResult<()> {
}) })
.collect(); .collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Collect results // Collect results
let mut results = Vec::new(); let mut results = Vec::new();
+9 -5
View File
@@ -2,7 +2,7 @@
use crate::common::task_fn; use crate::common::task_fn;
use dagx::{task, DagResult, DagRunner, TaskHandle}; use dagx::{task, DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Barrier; use tokio::sync::Barrier;
@@ -58,7 +58,8 @@ async fn test_forced_interleaving_with_barriers() -> DagResult<()> {
)) ))
.depends_on((t1, t2, t3)); .depends_on((t1, t2, t3));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(collector)?, 6); assert_eq!(dag.get(collector)?, 6);
@@ -186,7 +187,8 @@ async fn test_alternating_execution_pattern() -> DagResult<()> {
.depends_on(chain_b); .depends_on(chain_b);
} }
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Check alternating pattern // Check alternating pattern
let event_list = events.lock().clone(); let event_list = events.lock().clone();
@@ -262,7 +264,8 @@ async fn test_layered_interleaving() -> DagResult<()> {
}) })
.depends_on((&layer2[0], &layer2[1])); .depends_on((&layer2[0], &layer2[1]));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
// Sum of 0+1+2+3 = 6 // Sum of 0+1+2+3 = 6
assert_eq!(dag.get(layer3)?, 6); assert_eq!(dag.get(layer3)?, 6);
@@ -368,7 +371,8 @@ async fn test_cross_branch_synchronization() -> DagResult<()> {
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b)) .add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
.depends_on((&a2, &b2)); .depends_on((&a2, &b2));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?; dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await?;
assert_eq!(dag.get(merge)?, 13); // 2 + 11 assert_eq!(dag.get(merge)?, 13); // 2 + 11
+5 -5
View File
@@ -1,7 +1,7 @@
//! Tests with tracing feature enabled //! Tests with tracing feature enabled
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
use tracing_subscriber::{fmt, EnvFilter}; use tracing_subscriber::{fmt, EnvFilter};
struct Value(i32); struct Value(i32);
@@ -45,7 +45,7 @@ async fn test_tracing_with_subscriber() {
let b = dag.add_task(Value(3)); 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -68,7 +68,7 @@ async fn test_tracing_with_complex_dag() {
let right = dag.add_task(Multiply).depends_on((&source, &source)); let right = dag.add_task(Multiply).depends_on((&source, &source));
let sink = dag.add_task(Add).depends_on((&left, &right)); let sink = dag.add_task(Add).depends_on((&left, &right));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -94,7 +94,7 @@ async fn test_tracing_inline_execution() {
let b = dag.add_task(Add).depends_on((&a, &a)); let b = dag.add_task(Add).depends_on((&a, &a));
let c = dag.add_task(Multiply).depends_on((&b, &b)); let c = dag.add_task(Multiply).depends_on((&b, &b));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -128,7 +128,7 @@ async fn test_tracing_multiple_layers() {
// Layer 2 // Layer 2
let final_sum = dag.add_task(Add).depends_on((&sum12, &mul23)); let final_sum = dag.add_task(Add).depends_on((&sum12, &mul23));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+2 -3
View File
@@ -1,7 +1,6 @@
//! Tests that the library works correctly without tracing feature //! Tests that the library works correctly without tracing feature
use dagx::{task, DagRunner}; use dagx::{task, DagRunner};
use futures::FutureExt;
struct Value(i32); struct Value(i32);
@@ -29,7 +28,7 @@ async fn test_basic_dag_without_tracing() {
let b = dag.add_task(Value(3)); 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)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -50,7 +49,7 @@ async fn test_complex_dag_without_tracing() {
let sum34 = dag.add_task(Add).depends_on((v3, v4)); let sum34 = dag.add_task(Add).depends_on((v3, v4));
let final_sum = dag.add_task(Add).depends_on((&sum12, &sum34)); let final_sum = dag.add_task(Add).depends_on((&sum12, &sum34));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
+4 -4
View File
@@ -1,6 +1,6 @@
// Type safety tests for TaskHandle // Type safety tests for TaskHandle
use crate::common::task_fn; use crate::common::task_fn;
use futures::FutureExt;
// These tests verify dagx's compile-time type safety guarantees. // These tests verify dagx's compile-time type safety guarantees.
// Tests cover both runtime behavior (wrong types return None) and // Tests cover both runtime behavior (wrong types return None) and
// compile-time checking (type mismatches fail to compile). // compile-time checking (type mismatches fail to compile).
@@ -16,7 +16,7 @@ async fn test_get_with_wrong_type_returns_none() {
let int_task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42i32)); let int_task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42i32));
// Run DAG // Run DAG
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -37,7 +37,7 @@ async fn test_handle_preserves_type() {
let string_task = dag.add_task(task_fn::<(), _, _>(|_: ()| "hello".to_string())); let string_task = dag.add_task(task_fn::<(), _, _>(|_: ()| "hello".to_string()));
let int_task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42i32)); let int_task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42i32));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();
@@ -63,7 +63,7 @@ async fn test_type_safety_handle_reuse() {
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 3)) .add_task(task_fn::<i32, _, _>(|&x: &i32| x * 3))
.depends_on(source); .depends_on(source);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)) dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
.await .await
.unwrap(); .unwrap();