Address soundness hole in cycle prevention

This commit is contained in:
TechnoPorg committed 2026-01-29 06:56:17 +01:00
1 parent 4ad88bcd68
commit f82205baf4
80 files changed
+730 -717

No files matched your search

+11 -11
View File
@@ -12,7 +12,7 @@ async fn test_1000_level_deep_chain() -> DagResult<()> {
let dag = DagRunner::new();
let first = dag.add_task(task_fn(|_: ()| async { 0 }));
let mut current = (&first).into(); // Convert to TaskHandle
let mut current = first.into(); // Convert to TaskHandle
for _i in 1..1000 {
current = dag
@@ -32,7 +32,7 @@ async fn test_deep_chain_with_branches() -> DagResult<()> {
let dag = DagRunner::new();
let first = dag.add_task(task_fn(|_: ()| async { 0 }));
let mut main_chain: dagx::TaskHandle<i32> = (&first).into();
let mut main_chain: dagx::TaskHandle<i32> = first.into();
let mut branches = Vec::new();
for i in 1..500 {
@@ -72,7 +72,7 @@ async fn test_multiple_parallel_deep_chains() -> DagResult<()> {
for chain_id in 0..8 {
let first = dag.add_task(task_fn(move |_: ()| async move { chain_id * 1000 }));
let mut current: dagx::TaskHandle<i32> = (&first).into();
let mut current: dagx::TaskHandle<i32> = first.into();
for _ in 0..500 {
current = dag
@@ -136,7 +136,7 @@ async fn test_deep_chain_execution_order() -> DagResult<()> {
}
}
}));
let mut current: dagx::TaskHandle<i32> = (&first).into();
let mut current: dagx::TaskHandle<i32> = first.into();
for expected in 1..100 {
current = dag
@@ -169,7 +169,7 @@ async fn test_deep_binary_tree() -> DagResult<()> {
fn build_tree(dag: &DagRunner, depth: usize, value: i32) -> dagx::TaskHandle<i32> {
if depth == 0 {
let task = dag.add_task(task_fn(move |_: ()| async move { value }));
(&task).into() // Convert TaskBuilder to TaskHandle
task.into() // Convert TaskBuilder to TaskHandle
} else {
let left = build_tree(dag, depth - 1, value * 2);
let right = build_tree(dag, depth - 1, value * 2 + 1);
@@ -199,8 +199,8 @@ async fn test_fibonacci_chain() -> DagResult<()> {
let f0_builder = dag.add_task(task_fn(|_: ()| async { 0i64 }));
let f1_builder = dag.add_task(task_fn(|_: ()| async { 1i64 }));
let mut prev2: dagx::TaskHandle<i64> = (&f0_builder).into();
let mut prev1: dagx::TaskHandle<i64> = (&f1_builder).into();
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
@@ -226,7 +226,7 @@ async fn test_deep_chain_with_accumulator() -> DagResult<()> {
// Use a simpler accumulation pattern - just sum
let first = dag.add_task(task_fn(|_: ()| async { 0i64 }));
let mut current: dagx::TaskHandle<i64> = (&first).into();
let mut current: dagx::TaskHandle<i64> = first.into();
for i in 1..=200 {
current = dag
@@ -250,8 +250,8 @@ async fn test_zigzag_dependencies() -> DagResult<()> {
let a_first = dag.add_task(task_fn(|_: ()| async { 1 }));
let b_first = dag.add_task(task_fn(|_: ()| async { 2 }));
let mut chain_a: dagx::TaskHandle<i32> = (&a_first).into();
let mut chain_b: dagx::TaskHandle<i32> = (&b_first).into();
let mut chain_a: dagx::TaskHandle<i32> = a_first.into();
let mut chain_b: dagx::TaskHandle<i32> = b_first.into();
for i in 0..100 {
if i % 2 == 0 {
@@ -287,7 +287,7 @@ async fn test_10000_level_chain_stress() -> DagResult<()> {
let dag = DagRunner::new();
let first = dag.add_task(task_fn(|_: ()| async { 0u64 }));
let mut current: dagx::TaskHandle<u64> = (&first).into();
let mut current: dagx::TaskHandle<u64> = first.into();
for _ in 1..10_000 {
current = dag
+11 -8
View File
@@ -13,7 +13,7 @@ async fn test_10000_independent_tasks() -> DagResult<()> {
let counter = Arc::new(AtomicUsize::new(0));
let tasks: Vec<_> = (0..10_000)
let mut tasks: Vec<_> = (0..10_000)
.map(|i| {
let counter = counter.clone();
dag.add_task(task_fn(move |_: ()| {
@@ -32,9 +32,9 @@ async fn test_10000_independent_tasks() -> DagResult<()> {
assert_eq!(counter.load(Ordering::Relaxed), 10_000);
// Spot check some results
assert_eq!(dag.get(&tasks[0])?, 0);
assert_eq!(dag.get(&tasks[9_999])?, 9_999);
assert_eq!(dag.get(&tasks[5_000])?, 5_000);
assert_eq!(dag.get(tasks.swap_remove(9_999))?, 9_999);
assert_eq!(dag.get(tasks.swap_remove(5_000))?, 5_000);
assert_eq!(dag.get(tasks.swap_remove(0))?, 0);
Ok(())
}
@@ -55,7 +55,7 @@ async fn test_5000_node_pyramid() -> DagResult<()> {
0
}
}));
(&task).into()
task.into()
})
.collect();
@@ -126,7 +126,7 @@ async fn test_5000_node_pyramid_single_threaded() -> DagResult<()> {
0
}
}));
(&task).into()
task.into()
})
.collect();
@@ -188,7 +188,10 @@ async fn test_wide_dag_1000_sources_1000_sinks() -> DagResult<()> {
// Create 1000 source tasks
let sources: Vec<_> = (0..1000)
.map(|i| dag.add_task(task_fn(move |_: ()| async move { i % 10 })))
.map(|i| {
dag.add_task(task_fn(move |_: ()| async move { i % 10 }))
.into()
})
.collect();
// Create 1000 sink tasks, each depending on 3 random sources
@@ -238,7 +241,7 @@ async fn test_10000_node_linear_chain_segments() -> DagResult<()> {
}
}
}));
let mut current: dagx::TaskHandle<i32> = (&first).into();
let mut current: dagx::TaskHandle<i32> = first.into();
for _i in 1..100 {
current = dag
+14 -14
View File
@@ -1,7 +1,7 @@
//! Tests for type system edge cases and limits
use crate::common::task_fn;
use dagx::{DagResult, DagRunner};
use dagx::{DagResult, DagRunner, TaskHandle};
use futures::FutureExt;
use std::marker::PhantomData;
@@ -22,7 +22,7 @@ async fn test_zero_sized_types_throughout() -> DagResult<()> {
let t1 = dag.add_task(task_fn(|_: ()| async { Empty }));
// Task that also produces ZST (independent since we can't extract custom types)
let t2 = dag.add_task(task_fn(|_: ()| async { 42 }));
let t2: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into();
// Task with PhantomData
let _t3 = dag.add_task(task_fn(|_: ()| async {
@@ -37,7 +37,7 @@ async fn test_zero_sized_types_throughout() -> DagResult<()> {
assert_eq!(val, 42);
"success"
}))
.depends_on(&t2);
.depends_on(t2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -72,7 +72,7 @@ async fn test_large_value_types() -> DagResult<()> {
.add_task(task_fn(|val: usize| async move {
val // Just pass through to verify
}))
.depends_on(&t1);
.depends_on(t1);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -86,12 +86,12 @@ async fn test_unit_type_chains() -> DagResult<()> {
// Test chains of unit type operations
let dag = DagRunner::new();
let t1 = dag.add_task(task_fn(|_: ()| async {}));
let t2 = dag.add_task(task_fn(|_: ()| async {})).depends_on(&t1);
let t1: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async {})).into();
let t2 = dag.add_task(task_fn(|_: ()| async {})).depends_on(t1);
let t3 = dag.add_task(task_fn(|_: ()| async {})).depends_on(t2);
let t4 = dag
.add_task(task_fn(|_: ()| async { "done" }))
.depends_on(&t3);
.depends_on(t3);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -122,7 +122,7 @@ async fn test_nested_option_result_types() -> DagResult<()> {
_ => 0,
}
}))
.depends_on(&t1);
.depends_on(t1);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -146,7 +146,7 @@ async fn test_tuple_of_tuples() -> DagResult<()> {
a + b + c + d + e + f + g + h
},
))
.depends_on((&t1, &t2));
.depends_on((t1, t2));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -180,7 +180,7 @@ async fn test_string_types_variety() -> DagResult<()> {
std::sync::Arc<&str>,
)| async move { format!("{} {} {} {} {} {}", s1, s2, s3, s4, s5, s6) },
))
.depends_on((&t1, &t2, &t3, &t4, &t5, &t6));
.depends_on((t1, t2, t3, t4, t5, t6));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -209,7 +209,7 @@ async fn test_generic_type_constraints() -> DagResult<()> {
format!("{:?} {:?} {:?}", w1, w2, w3)
},
))
.depends_on((&t1, &t2, &t3));
.depends_on((t1, t2, t3));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -235,7 +235,7 @@ async fn test_reference_wrapper_types() -> DagResult<()> {
let t2 = dag
.add_task(task_fn(|val: i32| async move { val * 2 }))
.depends_on(&t1);
.depends_on(t1);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -260,7 +260,7 @@ async fn test_array_types() -> DagResult<()> {
}
sum
}))
.depends_on((&t1, &t2));
.depends_on((t1, t2));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
@@ -299,7 +299,7 @@ async fn test_enum_variants() -> DagResult<()> {
&& matches!(e4, MyEnum::LargeVariant(_))
},
))
.depends_on((&t1, &t2, &t3, &t4));
.depends_on((t1, t2, t3, t4));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
+3 -3
View File
@@ -64,7 +64,7 @@ async fn test_zero_sized_type_task() -> DagResult<()> {
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
assert_eq!(dag.get(&task)?, ZeroSized);
assert_eq!(dag.get(task)?, ZeroSized);
Ok(())
}
@@ -91,7 +91,7 @@ async fn test_dag_with_only_source_tasks() -> DagResult<()> {
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
for (i, task) in tasks.iter().enumerate() {
for (i, task) in tasks.into_iter().enumerate() {
assert_eq!(dag.get(task)?, i);
}
@@ -155,7 +155,7 @@ async fn test_dag_with_never_type_simulation() -> DagResult<()> {
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
assert_eq!(dag.get(&task)?, Ok(42));
assert_eq!(dag.get(task)?, Ok(42));
Ok(())
}