Update tests, examples, benches
This commit is contained in:
1 parent
0137296fb4
commit
86787b3a0d
71 files changed
+1791
-3547
No files matched your search
@@ -11,12 +11,12 @@ async fn test_1000_level_deep_chain() -> DagResult<()> {
|
||||
// Test a linear chain of 1000 tasks
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let first = dag.add_task(task_fn(|_: ()| async { 0 }));
|
||||
let first = dag.add_task(task_fn::<(), _, _>(|_: ()| 0));
|
||||
let mut current = first.into(); // Convert to TaskHandle
|
||||
|
||||
for _i in 1..1000 {
|
||||
current = dag
|
||||
.add_task(task_fn(move |prev: i32| async move { prev + 1 }))
|
||||
.add_task(task_fn::<i32, _, _>(move |&prev: &i32| prev + 1))
|
||||
.depends_on(current);
|
||||
}
|
||||
|
||||
@@ -31,20 +31,20 @@ async fn test_deep_chain_with_branches() -> DagResult<()> {
|
||||
// Test a deep chain where each node has a side branch
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let first = dag.add_task(task_fn(|_: ()| async { 0 }));
|
||||
let first = dag.add_task(task_fn::<(), _, _>(|_: ()| 0));
|
||||
let mut main_chain: dagx::TaskHandle<i32> = first.into();
|
||||
let mut branches = Vec::new();
|
||||
|
||||
for i in 1..500 {
|
||||
// Main chain continues
|
||||
main_chain = dag
|
||||
.add_task(task_fn(move |prev: i32| async move { prev + 1 }))
|
||||
.add_task(task_fn::<i32, _, _>(move |&prev: &i32| prev + 1))
|
||||
.depends_on(main_chain);
|
||||
|
||||
// Create a branch at every 10th node
|
||||
if i % 10 == 0 {
|
||||
let branch = dag
|
||||
.add_task(task_fn(move |main_val: i32| async move { main_val * 2 }))
|
||||
.add_task(task_fn::<i32, _, _>(move |main_val: &i32| main_val * 2))
|
||||
.depends_on(main_chain);
|
||||
branches.push(branch);
|
||||
}
|
||||
@@ -71,12 +71,12 @@ async fn test_multiple_parallel_deep_chains() -> DagResult<()> {
|
||||
let mut chain_ends = Vec::new();
|
||||
|
||||
for chain_id in 0..8 {
|
||||
let first = dag.add_task(task_fn(move |_: ()| async move { chain_id * 1000 }));
|
||||
let first = dag.add_task(task_fn::<(), _, _>(move |_: ()| chain_id * 1000));
|
||||
let mut current: dagx::TaskHandle<i32> = first.into();
|
||||
|
||||
for _ in 0..500 {
|
||||
current = dag
|
||||
.add_task(task_fn(|prev: i32| async move { prev + 1 }))
|
||||
.add_task(task_fn::<i32, _, _>(|&prev: &i32| prev + 1))
|
||||
.depends_on(current);
|
||||
}
|
||||
|
||||
@@ -85,8 +85,8 @@ async fn test_multiple_parallel_deep_chains() -> DagResult<()> {
|
||||
|
||||
// Add a final task that depends on all chains
|
||||
let final_task = dag
|
||||
.add_task(task_fn(
|
||||
|inputs: (i32, i32, i32, i32, i32, i32, i32, i32)| async move {
|
||||
.add_task(task_fn::<(i32, i32, i32, i32, i32, i32, i32, i32), _, _>(
|
||||
|inputs: (&i32, &i32, &i32, &i32, &i32, &i32, &i32, &i32)| {
|
||||
inputs.0
|
||||
+ inputs.1
|
||||
+ inputs.2
|
||||
@@ -126,28 +126,24 @@ async fn test_deep_chain_execution_order() -> DagResult<()> {
|
||||
let dag = DagRunner::new();
|
||||
let order = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
let first = dag.add_task(task_fn({
|
||||
let first = dag.add_task(task_fn::<(), _, _>({
|
||||
let order = order.clone();
|
||||
move |_: ()| {
|
||||
let order = order.clone();
|
||||
async move {
|
||||
assert_eq!(order.fetch_add(1, Ordering::SeqCst), 0);
|
||||
0
|
||||
}
|
||||
assert_eq!(order.fetch_add(1, Ordering::SeqCst), 0);
|
||||
0
|
||||
}
|
||||
}));
|
||||
let mut current: dagx::TaskHandle<i32> = first.into();
|
||||
|
||||
for expected in 1..100 {
|
||||
current = dag
|
||||
.add_task(task_fn({
|
||||
.add_task(task_fn::<i32, _, _>({
|
||||
let order = order.clone();
|
||||
move |prev: i32| {
|
||||
move |&prev: &i32| {
|
||||
let order = order.clone();
|
||||
async move {
|
||||
assert_eq!(order.fetch_add(1, Ordering::SeqCst), expected);
|
||||
prev + 1
|
||||
}
|
||||
assert_eq!(order.fetch_add(1, Ordering::SeqCst), expected);
|
||||
prev + 1
|
||||
}
|
||||
}))
|
||||
.depends_on(current);
|
||||
@@ -168,14 +164,16 @@ async fn test_deep_binary_tree() -> DagResult<()> {
|
||||
|
||||
fn build_tree(dag: &DagRunner, depth: usize, value: i32) -> dagx::TaskHandle<i32> {
|
||||
if depth == 0 {
|
||||
let task = dag.add_task(task_fn(move |_: ()| async move { value }));
|
||||
let task = dag.add_task(task_fn::<(), _, _>(move |_: ()| value));
|
||||
task.into() // Convert TaskBuilder to TaskHandle
|
||||
} else {
|
||||
let left = build_tree(dag, depth - 1, value * 2);
|
||||
let right = build_tree(dag, depth - 1, value * 2 + 1);
|
||||
|
||||
dag.add_task(task_fn(move |(l, r): (i32, i32)| async move { l + r }))
|
||||
.depends_on((&left, &right))
|
||||
dag.add_task(task_fn::<(i32, i32), _, _>(move |(l, r): (&i32, &i32)| {
|
||||
l + r
|
||||
}))
|
||||
.depends_on((&left, &right))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,15 +194,15 @@ async fn test_fibonacci_chain() -> DagResult<()> {
|
||||
// Test a Fibonacci-like dependency pattern
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let f0_builder = dag.add_task(task_fn(|_: ()| async { 0i64 }));
|
||||
let f1_builder = dag.add_task(task_fn(|_: ()| async { 1i64 }));
|
||||
let f0_builder = dag.add_task(task_fn::<(), _, _>(|_: ()| 0i64));
|
||||
let f1_builder = dag.add_task(task_fn::<(), _, _>(|_: ()| 1i64));
|
||||
|
||||
let mut prev2: dagx::TaskHandle<i64> = f0_builder.into();
|
||||
let mut prev1: dagx::TaskHandle<i64> = f1_builder.into();
|
||||
|
||||
for _ in 2..50 {
|
||||
let next = dag
|
||||
.add_task(task_fn(|(a, b): (i64, i64)| async move { a + b }))
|
||||
.add_task(task_fn::<(i64, i64), _, _>(|(a, b): (&i64, &i64)| a + b))
|
||||
.depends_on((&prev2, &prev1));
|
||||
|
||||
prev2 = prev1;
|
||||
@@ -225,12 +223,12 @@ async fn test_deep_chain_with_accumulator() -> DagResult<()> {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Use a simpler accumulation pattern - just sum
|
||||
let first = dag.add_task(task_fn(|_: ()| async { 0i64 }));
|
||||
let first = dag.add_task(task_fn::<(), _, _>(|_: ()| 0i64));
|
||||
let mut current: dagx::TaskHandle<i64> = first.into();
|
||||
|
||||
for i in 1..=200 {
|
||||
current = dag
|
||||
.add_task(task_fn(move |sum: i64| async move { sum + i as i64 }))
|
||||
.add_task(task_fn::<i64, _, _>(move |sum: &i64| sum + i as i64))
|
||||
.depends_on(current);
|
||||
}
|
||||
|
||||
@@ -247,8 +245,8 @@ async fn test_zigzag_dependencies() -> DagResult<()> {
|
||||
// Test a zigzag pattern: two chains that cross-reference each other
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let a_first = dag.add_task(task_fn(|_: ()| async { 1 }));
|
||||
let b_first = dag.add_task(task_fn(|_: ()| async { 2 }));
|
||||
let a_first = dag.add_task(task_fn::<(), _, _>(|_: ()| 1));
|
||||
let b_first = dag.add_task(task_fn::<(), _, _>(|_: ()| 2));
|
||||
|
||||
let mut chain_a: dagx::TaskHandle<i32> = a_first.into();
|
||||
let mut chain_b: dagx::TaskHandle<i32> = b_first.into();
|
||||
@@ -257,19 +255,19 @@ async fn test_zigzag_dependencies() -> DagResult<()> {
|
||||
if i % 2 == 0 {
|
||||
// A depends on B
|
||||
chain_a = dag
|
||||
.add_task(task_fn(move |b_val: i32| async move { b_val + 1 }))
|
||||
.add_task(task_fn::<i32, _, _>(move |b_val: &i32| b_val + 1))
|
||||
.depends_on(chain_b);
|
||||
} else {
|
||||
// B depends on A
|
||||
chain_b = dag
|
||||
.add_task(task_fn(move |a_val: i32| async move { a_val + 2 }))
|
||||
.add_task(task_fn::<i32, _, _>(move |a_val: &i32| a_val + 2))
|
||||
.depends_on(chain_a);
|
||||
}
|
||||
}
|
||||
|
||||
// Final task depends on both chains
|
||||
let final_task = dag
|
||||
.add_task(task_fn(|(a, b): (i32, i32)| async move { a + b }))
|
||||
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
|
||||
.depends_on((&chain_a, &chain_b));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
@@ -286,12 +284,12 @@ async fn test_10000_level_chain_stress() -> DagResult<()> {
|
||||
// Ultimate deep chain test
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let first = dag.add_task(task_fn(|_: ()| async { 0u64 }));
|
||||
let first = dag.add_task(task_fn::<(), _, _>(|_: ()| 0u64));
|
||||
let mut current: dagx::TaskHandle<u64> = first.into();
|
||||
|
||||
for _ in 1..10_000 {
|
||||
current = dag
|
||||
.add_task(task_fn(|prev: u64| async move { prev + 1 }))
|
||||
.add_task(task_fn::<u64, _, _>(|prev: &u64| prev + 1))
|
||||
.depends_on(current);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,9 @@ async fn test_10000_independent_tasks() -> DagResult<()> {
|
||||
let mut tasks: Vec<_> = (0..10_000)
|
||||
.map(|i| {
|
||||
let counter = counter.clone();
|
||||
dag.add_task(task_fn(move |_: ()| {
|
||||
let counter = counter.clone();
|
||||
async move {
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
i
|
||||
}
|
||||
dag.add_task(task_fn::<(), _, _>(move |_: ()| {
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
i
|
||||
}))
|
||||
})
|
||||
.collect();
|
||||
@@ -48,13 +45,15 @@ async fn test_5000_node_pyramid() -> DagResult<()> {
|
||||
// Bottom layer: 2048 nodes - convert to TaskHandles
|
||||
let mut current_layer: Vec<dagx::TaskHandle<i32>> = (0..2048)
|
||||
.map(|i| {
|
||||
let task = dag.add_task(task_fn(move |_: ()| async move {
|
||||
if i < 1024 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}));
|
||||
let task = dag.add_task(task_fn::<(), _, _>(
|
||||
move |_: ()| {
|
||||
if i < 1024 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
},
|
||||
));
|
||||
task.into()
|
||||
})
|
||||
.collect();
|
||||
@@ -74,20 +73,20 @@ async fn test_5000_node_pyramid() -> DagResult<()> {
|
||||
|
||||
let task = match deps.len() {
|
||||
1 => dag
|
||||
.add_task(task_fn(|a: i32| async move { a }))
|
||||
.add_task(task_fn::<i32, _, _>(|&a: &i32| a))
|
||||
.depends_on(deps[0]),
|
||||
2 => dag
|
||||
.add_task(task_fn(|(a, b): (i32, i32)| async move { a + b }))
|
||||
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
|
||||
.depends_on((deps[0], deps[1])),
|
||||
3 => dag
|
||||
.add_task(task_fn(
|
||||
|(a, b, c): (i32, i32, i32)| async move { a + b + c },
|
||||
.add_task(task_fn::<(i32, i32, i32), _, _>(
|
||||
|(a, b, c): (&i32, &i32, &i32)| a + b + c,
|
||||
))
|
||||
.depends_on((deps[0], deps[1], deps[2])),
|
||||
4 => dag
|
||||
.add_task(task_fn(|(a, b, c, d): (i32, i32, i32, i32)| async move {
|
||||
a + b + c + d
|
||||
}))
|
||||
.add_task(task_fn::<(i32, i32, i32, i32), _, _>(
|
||||
|(a, b, c, d): (&i32, &i32, &i32, &i32)| a + b + c + d,
|
||||
))
|
||||
.depends_on((deps[0], deps[1], deps[2], deps[3])),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@@ -98,7 +97,7 @@ async fn test_5000_node_pyramid() -> DagResult<()> {
|
||||
|
||||
// Final layer combines the last 2
|
||||
let root = dag
|
||||
.add_task(task_fn(|(a, b): (i32, i32)| async move { a + b }))
|
||||
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
|
||||
.depends_on((¤t_layer[0], ¤t_layer[1]));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
@@ -119,13 +118,15 @@ async fn test_5000_node_pyramid_single_threaded() -> DagResult<()> {
|
||||
// Bottom layer: 2048 nodes - convert to TaskHandles
|
||||
let mut current_layer: Vec<dagx::TaskHandle<i32>> = (0..2048)
|
||||
.map(|i| {
|
||||
let task = dag.add_task(task_fn(move |_: ()| async move {
|
||||
if i < 1024 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}));
|
||||
let task = dag.add_task(task_fn::<(), _, _>(
|
||||
move |_: ()| {
|
||||
if i < 1024 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
},
|
||||
));
|
||||
task.into()
|
||||
})
|
||||
.collect();
|
||||
@@ -145,20 +146,20 @@ async fn test_5000_node_pyramid_single_threaded() -> DagResult<()> {
|
||||
|
||||
let task = match deps.len() {
|
||||
1 => dag
|
||||
.add_task(task_fn(|a: i32| async move { a }))
|
||||
.add_task(task_fn::<i32, _, _>(|&a: &i32| a))
|
||||
.depends_on(deps[0]),
|
||||
2 => dag
|
||||
.add_task(task_fn(|(a, b): (i32, i32)| async move { a + b }))
|
||||
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
|
||||
.depends_on((deps[0], deps[1])),
|
||||
3 => dag
|
||||
.add_task(task_fn(
|
||||
|(a, b, c): (i32, i32, i32)| async move { a + b + c },
|
||||
.add_task(task_fn::<(i32, i32, i32), _, _>(
|
||||
|(a, b, c): (&i32, &i32, &i32)| a + b + c,
|
||||
))
|
||||
.depends_on((deps[0], deps[1], deps[2])),
|
||||
4 => dag
|
||||
.add_task(task_fn(|(a, b, c, d): (i32, i32, i32, i32)| async move {
|
||||
a + b + c + d
|
||||
}))
|
||||
.add_task(task_fn::<(i32, i32, i32, i32), _, _>(
|
||||
|(a, b, c, d): (&i32, &i32, &i32, &i32)| a + b + c + d,
|
||||
))
|
||||
.depends_on((deps[0], deps[1], deps[2], deps[3])),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@@ -169,7 +170,7 @@ async fn test_5000_node_pyramid_single_threaded() -> DagResult<()> {
|
||||
|
||||
// Final layer combines the last 2
|
||||
let root = dag
|
||||
.add_task(task_fn(|(a, b): (i32, i32)| async move { a + b }))
|
||||
.add_task(task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b))
|
||||
.depends_on((¤t_layer[0], ¤t_layer[1]));
|
||||
|
||||
dag.run(|fut| fut).await?;
|
||||
@@ -189,7 +190,7 @@ async fn test_wide_dag_1000_sources_1000_sinks() -> DagResult<()> {
|
||||
// Create 1000 source tasks
|
||||
let sources: Vec<_> = (0..1000)
|
||||
.map(|i| {
|
||||
dag.add_task(task_fn(move |_: ()| async move { i % 10 }))
|
||||
dag.add_task(task_fn::<(), _, _>(move |_: ()| i % 10))
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
@@ -201,9 +202,9 @@ async fn test_wide_dag_1000_sources_1000_sinks() -> DagResult<()> {
|
||||
let idx2 = (i * 13) % 1000;
|
||||
let idx3 = (i * 17) % 1000;
|
||||
|
||||
dag.add_task(task_fn(move |(a, b, c): (i32, i32, i32)| async move {
|
||||
a + b + c + i as i32
|
||||
}))
|
||||
dag.add_task(task_fn::<(i32, i32, i32), _, _>(
|
||||
move |(a, b, c): (&i32, &i32, &i32)| a + b + c + i as i32,
|
||||
))
|
||||
.depends_on((&sources[idx1], &sources[idx2], &sources[idx3]))
|
||||
})
|
||||
.collect();
|
||||
@@ -231,28 +232,24 @@ async fn test_10000_node_linear_chain_segments() -> DagResult<()> {
|
||||
let mut chain_ends = Vec::new();
|
||||
|
||||
for chain_id in 0..100 {
|
||||
let first = dag.add_task(task_fn({
|
||||
let first = dag.add_task(task_fn::<(), _, _>({
|
||||
let counter = counter.clone();
|
||||
move |_: ()| {
|
||||
let counter = counter.clone();
|
||||
async move {
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
chain_id * 100
|
||||
}
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
chain_id * 100
|
||||
}
|
||||
}));
|
||||
let mut current: dagx::TaskHandle<i32> = first.into();
|
||||
|
||||
for _i in 1..100 {
|
||||
current = dag
|
||||
.add_task(task_fn({
|
||||
.add_task(task_fn::<i32, _, _>({
|
||||
let counter = counter.clone();
|
||||
move |prev: i32| {
|
||||
move |&prev: &i32| {
|
||||
let counter = counter.clone();
|
||||
async move {
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
prev + 1
|
||||
}
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
prev + 1
|
||||
}
|
||||
}))
|
||||
.depends_on(current);
|
||||
@@ -291,12 +288,10 @@ async fn test_100000_nodes_stress() -> DagResult<()> {
|
||||
.map(|i| {
|
||||
let completed = completed.clone();
|
||||
let task_id = batch * batch_size + i;
|
||||
dag.add_task(task_fn(move |_: ()| {
|
||||
dag.add_task(task_fn::<(), _, _>(move |_: ()| {
|
||||
let completed = completed.clone();
|
||||
async move {
|
||||
completed.fetch_add(1, Ordering::Relaxed);
|
||||
task_id
|
||||
}
|
||||
completed.fetch_add(1, Ordering::Relaxed);
|
||||
task_id
|
||||
}))
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -19,21 +19,19 @@ async fn test_zero_sized_types_throughout() -> DagResult<()> {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Task producing ZST
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async { Empty }));
|
||||
let t1 = dag.add_task(task_fn::<(), _, _>(|_: ()| Empty));
|
||||
|
||||
// Task that also produces ZST (independent since we can't extract custom types)
|
||||
let t2: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into();
|
||||
let t2: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| 42)).into();
|
||||
|
||||
// Task with PhantomData
|
||||
let _t3 = dag.add_task(task_fn(|_: ()| async {
|
||||
PhantomWrapper::<i32> {
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
let _t3 = dag.add_task(task_fn::<(), _, _>(|_: ()| PhantomWrapper::<i32> {
|
||||
_phantom: PhantomData,
|
||||
}));
|
||||
|
||||
// Task that depends on t2 (uses primitive type)
|
||||
let t4 = dag
|
||||
.add_task(task_fn(|val: i32| async move {
|
||||
.add_task(task_fn::<i32, _, _>(|&val: &i32| {
|
||||
assert_eq!(val, 42);
|
||||
"success"
|
||||
}))
|
||||
@@ -59,7 +57,7 @@ async fn test_large_value_types() -> DagResult<()> {
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async {
|
||||
let t1 = dag.add_task(task_fn::<(), _, _>(|_: ()| {
|
||||
let large = LargeStruct {
|
||||
data: [42; 8192],
|
||||
more_data: vec![1; 1000],
|
||||
@@ -69,7 +67,7 @@ async fn test_large_value_types() -> DagResult<()> {
|
||||
}));
|
||||
|
||||
let t2 = dag
|
||||
.add_task(task_fn(|val: usize| async move {
|
||||
.add_task(task_fn::<usize, _, _>(|&val: &usize| {
|
||||
val // Just pass through to verify
|
||||
}))
|
||||
.depends_on(t1);
|
||||
@@ -86,12 +84,16 @@ async fn test_unit_type_chains() -> DagResult<()> {
|
||||
// Test chains of unit type operations
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async {})).into();
|
||||
let t2 = dag.add_task(task_fn(|_: ()| async {})).depends_on(t1);
|
||||
let t3 = dag.add_task(task_fn(|_: ()| async {})).depends_on(t2);
|
||||
let t1: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| {})).into();
|
||||
let t2 = dag
|
||||
.add_task(task_fn::<(), _, _>(|_: ()| {}))
|
||||
.depends_on((t1,));
|
||||
let t3 = dag
|
||||
.add_task(task_fn::<(), _, _>(|_: ()| {}))
|
||||
.depends_on((t2,));
|
||||
let t4 = dag
|
||||
.add_task(task_fn(|_: ()| async { "done" }))
|
||||
.depends_on(t3);
|
||||
.add_task(task_fn::<(), _, _>(|_: ()| "done"))
|
||||
.depends_on((t3,));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
|
||||
@@ -103,82 +105,43 @@ async fn test_unit_type_chains() -> DagResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_nested_option_result_types() -> DagResult<()> {
|
||||
// Test deeply nested generic types
|
||||
type ComplexType = Result<Option<Result<Vec<Option<i32>>, String>>, &'static str>;
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async {
|
||||
let val: ComplexType = Ok(Some(Ok(vec![Some(42), None, Some(13)])));
|
||||
val
|
||||
}));
|
||||
|
||||
let t2 = dag
|
||||
.add_task(task_fn(|complex: ComplexType| async move {
|
||||
match complex {
|
||||
Ok(Some(Ok(vec))) => vec.iter().filter_map(|x| *x).sum::<i32>(),
|
||||
_ => 0,
|
||||
}
|
||||
}))
|
||||
.depends_on(t1);
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
|
||||
assert_eq!(dag.get(t2)?, 55);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_tuple_of_tuples() -> DagResult<()> {
|
||||
// Test nested tuple types
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async { ((1, 2), (3, 4)) }));
|
||||
let t2 = dag.add_task(task_fn(|_: ()| async { ((5, 6), (7, 8)) }));
|
||||
|
||||
let t3 = dag
|
||||
.add_task(task_fn(
|
||||
|inputs: (((i32, i32), (i32, i32)), ((i32, i32), (i32, i32)))| async move {
|
||||
let (((a, b), (c, d)), ((e, f), (g, h))) = inputs;
|
||||
a + b + c + d + e + f + g + h
|
||||
},
|
||||
))
|
||||
.depends_on((t1, t2));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
|
||||
assert_eq!(dag.get(t3)?, 36);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_string_types_variety() -> DagResult<()> {
|
||||
// Test various string types
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async { "static str" }));
|
||||
let t2 = dag.add_task(task_fn(|_: ()| async { String::from("owned string") }));
|
||||
let t3 = dag.add_task(task_fn(|_: ()| async {
|
||||
let t1 = dag.add_task(task_fn::<(), _, _>(|_: ()| "static str"));
|
||||
let t2 = dag.add_task(task_fn::<(), _, _>(|_: ()| String::from("owned string")));
|
||||
let t3 = dag.add_task(task_fn::<(), _, _>(|_: ()| {
|
||||
std::borrow::Cow::Borrowed("cow str")
|
||||
}));
|
||||
let t4 = dag.add_task(task_fn(|_: ()| async { Box::new("boxed str") }));
|
||||
let t5 = dag.add_task(task_fn(|_: ()| async { std::sync::Arc::new("arc str 2") }));
|
||||
let t6 = dag.add_task(task_fn(|_: ()| async { std::sync::Arc::new("arc str") }));
|
||||
let t4 = dag.add_task(task_fn::<(), _, _>(|_: ()| Box::new("boxed str")));
|
||||
let t5 = dag.add_task(task_fn::<(), _, _>(|_: ()| {
|
||||
std::sync::Arc::new("arc str 2")
|
||||
}));
|
||||
let t6 = dag.add_task(task_fn::<(), _, _>(|_: ()| std::sync::Arc::new("arc str")));
|
||||
|
||||
let combined = dag
|
||||
.add_task(task_fn(
|
||||
|(s1, s2, s3, s4, s5, s6): (
|
||||
.add_task(task_fn::<
|
||||
(
|
||||
&str,
|
||||
String,
|
||||
std::borrow::Cow<str>,
|
||||
Box<&str>,
|
||||
std::sync::Arc<&str>,
|
||||
std::sync::Arc<&str>,
|
||||
)| async move { format!("{} {} {} {} {} {}", s1, s2, s3, s4, s5, s6) },
|
||||
),
|
||||
_,
|
||||
_,
|
||||
>(
|
||||
|(s1, s2, s3, s4, s5, s6): (
|
||||
&&str,
|
||||
&String,
|
||||
&std::borrow::Cow<str>,
|
||||
&Box<&str>,
|
||||
&std::sync::Arc<&str>,
|
||||
&std::sync::Arc<&str>,
|
||||
)| { format!("{} {} {} {} {} {}", s1, s2, s3, s4, s5, s6) },
|
||||
))
|
||||
.depends_on((t1, t2, t3, t4, t5, t6));
|
||||
|
||||
@@ -199,13 +162,17 @@ async fn test_generic_type_constraints() -> DagResult<()> {
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async { Wrapper(42) }));
|
||||
let t2 = dag.add_task(task_fn(|_: ()| async { Wrapper("hello") }));
|
||||
let t3 = dag.add_task(task_fn(|_: ()| async { Wrapper(vec![1, 2, 3]) }));
|
||||
let t1 = dag.add_task(task_fn::<(), _, _>(|_: ()| Wrapper(42)));
|
||||
let t2 = dag.add_task(task_fn::<(), _, _>(|_: ()| Wrapper("hello")));
|
||||
let t3 = dag.add_task(task_fn::<(), _, _>(|_: ()| Wrapper(vec![1, 2, 3])));
|
||||
|
||||
let combined = dag
|
||||
.add_task(task_fn(
|
||||
|(w1, w2, w3): (Wrapper<i32>, Wrapper<&str>, Wrapper<Vec<i32>>)| async move {
|
||||
.add_task(task_fn::<
|
||||
(Wrapper<i32>, Wrapper<&str>, Wrapper<Vec<i32>>),
|
||||
_,
|
||||
_,
|
||||
>(
|
||||
|(w1, w2, w3): (&Wrapper<i32>, &Wrapper<&str>, &Wrapper<Vec<i32>>)| {
|
||||
format!("{:?} {:?} {:?}", w1, w2, w3)
|
||||
},
|
||||
))
|
||||
@@ -226,7 +193,7 @@ async fn test_reference_wrapper_types() -> DagResult<()> {
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async {
|
||||
let t1 = dag.add_task(task_fn::<(), _, _>(|_: ()| {
|
||||
let arc = Arc::new(Mutex::new(100));
|
||||
// Extract value instead of passing Arc
|
||||
let guard = arc.lock().unwrap();
|
||||
@@ -234,7 +201,7 @@ async fn test_reference_wrapper_types() -> DagResult<()> {
|
||||
}));
|
||||
|
||||
let t2 = dag
|
||||
.add_task(task_fn(|val: i32| async move { val * 2 }))
|
||||
.add_task(task_fn::<i32, _, _>(|&val: &i32| val * 2))
|
||||
.depends_on(t1);
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
@@ -249,17 +216,19 @@ async fn test_array_types() -> DagResult<()> {
|
||||
// Test with fixed-size arrays
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async { [1, 2, 3, 4, 5] }));
|
||||
let t2 = dag.add_task(task_fn(|_: ()| async { [6, 7, 8, 9, 10] }));
|
||||
let t1 = dag.add_task(task_fn::<(), _, _>(|_: ()| [1, 2, 3, 4, 5]));
|
||||
let t2 = dag.add_task(task_fn::<(), _, _>(|_: ()| [6, 7, 8, 9, 10]));
|
||||
|
||||
let t3 = dag
|
||||
.add_task(task_fn(|(a1, a2): ([i32; 5], [i32; 5])| async move {
|
||||
let mut sum = 0;
|
||||
for i in 0..5 {
|
||||
sum += a1[i] + a2[i];
|
||||
}
|
||||
sum
|
||||
}))
|
||||
.add_task(task_fn::<([i32; 5], [i32; 5]), _, _>(
|
||||
|(a1, a2): (&[i32; 5], &[i32; 5])| {
|
||||
let mut sum = 0;
|
||||
for i in 0..5 {
|
||||
sum += a1[i] + a2[i];
|
||||
}
|
||||
sum
|
||||
},
|
||||
))
|
||||
.depends_on((t1, t2));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
@@ -283,16 +252,16 @@ async fn test_enum_variants() -> DagResult<()> {
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let t1 = dag.add_task(task_fn(|_: ()| async { MyEnum::Unit }));
|
||||
let t2 = dag.add_task(task_fn(|_: ()| async {
|
||||
let t1 = dag.add_task(task_fn::<(), _, _>(|_: ()| MyEnum::Unit));
|
||||
let t2 = dag.add_task(task_fn::<(), _, _>(|_: ()| {
|
||||
MyEnum::Tuple(42, "test".to_string())
|
||||
}));
|
||||
let t3 = dag.add_task(task_fn(|_: ()| async { MyEnum::Struct { x: 10, y: 20 } }));
|
||||
let t4 = dag.add_task(task_fn(|_: ()| async { MyEnum::LargeVariant([0; 1024]) }));
|
||||
let t3 = dag.add_task(task_fn::<(), _, _>(|_: ()| MyEnum::Struct { x: 10, y: 20 }));
|
||||
let t4 = dag.add_task(task_fn::<(), _, _>(|_: ()| MyEnum::LargeVariant([0; 1024])));
|
||||
|
||||
let combined = dag
|
||||
.add_task(task_fn(
|
||||
|(e1, e2, e3, e4): (MyEnum, MyEnum, MyEnum, MyEnum)| async move {
|
||||
.add_task(task_fn::<(MyEnum, MyEnum, MyEnum, MyEnum), _, _>(
|
||||
|(e1, e2, e3, e4): (&MyEnum, &MyEnum, &MyEnum, &MyEnum)| {
|
||||
matches!(e1, MyEnum::Unit)
|
||||
&& matches!(e2, MyEnum::Tuple(42, _))
|
||||
&& matches!(e3, MyEnum::Struct { x: 10, y: 20 })
|
||||
|
||||
@@ -5,6 +5,7 @@ use dagx::{task, DagResult, DagRunner};
|
||||
use futures::FutureExt;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tokio::task::yield_now;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_empty_dag_execution() -> DagResult<()> {
|
||||
@@ -22,7 +23,7 @@ async fn test_single_task_no_deps() -> DagResult<()> {
|
||||
// Test the absolute minimum: one task with no dependencies
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let task = dag.add_task(task_fn(|_: ()| async { 42 }));
|
||||
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
|
||||
@@ -38,11 +39,9 @@ async fn test_single_task_unit_input_output() -> DagResult<()> {
|
||||
let executed = Arc::new(AtomicUsize::new(0));
|
||||
let exec_clone = executed.clone();
|
||||
|
||||
let task = dag.add_task(task_fn(move |_: ()| {
|
||||
let task = dag.add_task(task_fn::<(), _, _>(move |_: ()| {
|
||||
let exec = exec_clone.clone();
|
||||
async move {
|
||||
exec.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
exec.fetch_add(1, Ordering::SeqCst);
|
||||
}));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
@@ -60,7 +59,7 @@ async fn test_zero_sized_type_task() -> DagResult<()> {
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let task = dag.add_task(task_fn(|_: ()| async { ZeroSized }));
|
||||
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| ZeroSized));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
|
||||
@@ -86,7 +85,7 @@ async fn test_dag_with_only_source_tasks() -> DagResult<()> {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let tasks: Vec<_> = (0..100)
|
||||
.map(|i| dag.add_task(task_fn(move |_: ()| async move { i })))
|
||||
.map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i)))
|
||||
.collect();
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
@@ -132,7 +131,7 @@ async fn test_alternating_empty_and_filled_dag_runs() -> DagResult<()> {
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
} else {
|
||||
// DAG with a task
|
||||
let task = dag.add_task(task_fn(move |_: ()| async move { i }));
|
||||
let task = dag.add_task(task_fn::<(), _, _>(move |_: ()| i));
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
assert_eq!(dag.get(task)?, i);
|
||||
}
|
||||
@@ -151,7 +150,7 @@ async fn test_dag_with_never_type_simulation() -> DagResult<()> {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// This task completes immediately but returns a Result containing "never" type
|
||||
let task = dag.add_task(task_fn(|_: ()| async { 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?;
|
||||
|
||||
@@ -164,11 +163,17 @@ async fn test_minimal_task_with_minimal_async_work() -> DagResult<()> {
|
||||
// Test a task that does the absolute minimum async work
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let task = dag.add_task(task_fn(|_: ()| async {
|
||||
// Just yield once to the runtime
|
||||
tokio::task::yield_now().await;
|
||||
1337
|
||||
}));
|
||||
struct YieldTask;
|
||||
|
||||
#[task]
|
||||
impl YieldTask {
|
||||
async fn run() -> i32 {
|
||||
yield_now().await;
|
||||
1337
|
||||
}
|
||||
}
|
||||
|
||||
let task = dag.add_task(YieldTask);
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
|
||||
|
||||
Reference in new issue
Block a user