Address soundness hole in cycle prevention
This commit is contained in:
1 parent
4ad88bcd68
commit
f82205baf4
80 files changed
+730
-717
No files matched your search
@@ -83,8 +83,8 @@ async fn main() {
|
||||
// Step 4: Add source tasks (tasks with no dependencies)
|
||||
//
|
||||
// add_task() returns a TaskHandle<T> where T is the task's output type
|
||||
let x = dag.add_task(Value::new(2)); // TaskHandle<i32>
|
||||
let y = dag.add_task(Value::new(3)); // TaskHandle<i32>
|
||||
let x = dag.add_task(Value::new(2)).into(); // TaskHandle<i32>
|
||||
let y = dag.add_task(Value::new(3)).into(); // TaskHandle<i32>
|
||||
|
||||
// Step 5: Add a task with dependencies
|
||||
//
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
//! Squared: 100
|
||||
//! ```
|
||||
|
||||
use dagx::{task, DagRunner};
|
||||
use dagx::{task, DagRunner, TaskHandle};
|
||||
use futures::FutureExt;
|
||||
|
||||
// Source task with a value field
|
||||
@@ -131,13 +131,13 @@ async fn main() {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Single source task - constructed with ::new()
|
||||
let source = dag.add_task(Source::new(10));
|
||||
let source: TaskHandle<_> = dag.add_task(Source::new(10)).into();
|
||||
|
||||
// Multiple downstream tasks consuming the same value
|
||||
// Each constructed differently to show flexibility
|
||||
let plus_one = dag.add_task(AddOffset::new(1)).depends_on(&source);
|
||||
let times_two = dag.add_task(Multiply::new(2)).depends_on(&source);
|
||||
let squared = dag.add_task(Power { exponent: 2 }).depends_on(&source);
|
||||
let plus_one = dag.add_task(AddOffset::new(1)).depends_on(source);
|
||||
let times_two = dag.add_task(Multiply::new(2)).depends_on(source);
|
||||
let squared = dag.add_task(Power { exponent: 2 }).depends_on(source);
|
||||
|
||||
// Run the DAG
|
||||
println!("Running fan-out DAG...\n");
|
||||
|
||||
@@ -130,7 +130,7 @@ async fn main() {
|
||||
// Single downstream task consuming all values
|
||||
let profile = dag
|
||||
.add_task(BuildProfile)
|
||||
.depends_on((&name, &age, &city, &active));
|
||||
.depends_on((name, age, city, active));
|
||||
|
||||
// Run the DAG
|
||||
println!("Running fan-in DAG...\n");
|
||||
|
||||
@@ -123,9 +123,7 @@ async fn main() -> DagResult<()> {
|
||||
let sum3 = dag.add_task(ComputeSum::new(501, 751, WORK_DELAY));
|
||||
let sum4 = dag.add_task(ComputeSum::new(751, 1001, WORK_DELAY));
|
||||
|
||||
let total = dag
|
||||
.add_task(Aggregate)
|
||||
.depends_on((&sum1, &sum2, &sum3, &sum4));
|
||||
let total = dag.add_task(Aggregate).depends_on((sum1, sum2, sum3, sum4));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await?;
|
||||
|
||||
|
||||
@@ -448,7 +448,7 @@ async fn main() {
|
||||
|
||||
let fallback5 = dag
|
||||
.add_task(FallbackService::new("ServiceCall-5"))
|
||||
.depends_on(&call5);
|
||||
.depends_on(call5);
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
|
||||
@@ -184,8 +184,8 @@ async fn main() -> DagResult<()> {
|
||||
let source_b = dag.add_task(LoadData::new("B"));
|
||||
|
||||
// Transform: Process each source (parallel)
|
||||
let transform_a = dag.add_task(Transform::new(2)).depends_on(&source_a);
|
||||
let transform_b = dag.add_task(Transform::new(3)).depends_on(&source_b);
|
||||
let transform_a = dag.add_task(Transform::new(2)).depends_on(source_a);
|
||||
let transform_b = dag.add_task(Transform::new(3)).depends_on(source_b);
|
||||
|
||||
// Combine: Merge the transformed datasets
|
||||
let combined = dag
|
||||
|
||||
@@ -128,9 +128,9 @@ async fn main() -> DagResult<()> {
|
||||
let processed3 = dag.add_task(ValidateAndDouble::new(20)); // Valid: 40
|
||||
|
||||
// Categorize each result (also parallel, threshold = 25)
|
||||
let cat1 = dag.add_task(Categorize::new(25)).depends_on(&processed1); // 20 < 25 = "low"
|
||||
let cat2 = dag.add_task(Categorize::new(25)).depends_on(&processed2); // 0 = "invalid"
|
||||
let cat3 = dag.add_task(Categorize::new(25)).depends_on(&processed3); // 40 >= 25 = "high"
|
||||
let cat1 = dag.add_task(Categorize::new(25)).depends_on(processed1); // 20 < 25 = "low"
|
||||
let cat2 = dag.add_task(Categorize::new(25)).depends_on(processed2); // 0 = "invalid"
|
||||
let cat3 = dag.add_task(Categorize::new(25)).depends_on(processed3); // 40 >= 25 = "high"
|
||||
|
||||
// Combine results
|
||||
let summary = dag
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
//! Validation: Alice is valid (age 30 >= 18)
|
||||
//! ```
|
||||
|
||||
use dagx::{task, DagRunner};
|
||||
use dagx::{task, DagRunner, TaskHandle};
|
||||
use futures::FutureExt;
|
||||
|
||||
// Custom type - just derive Clone!
|
||||
@@ -97,15 +97,17 @@ async fn main() {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Create a task that produces a custom User type
|
||||
let user_task = dag.add_task(CreateUser {
|
||||
name: "Alice".to_string(),
|
||||
age: 30,
|
||||
});
|
||||
let user_task: TaskHandle<_> = dag
|
||||
.add_task(CreateUser {
|
||||
name: "Alice".to_string(),
|
||||
age: 30,
|
||||
})
|
||||
.into();
|
||||
|
||||
// Two different tasks consume the same custom User type
|
||||
// dagx automatically handles Arc wrapping, so both tasks get &User
|
||||
let greeting = dag.add_task(GreetUser).depends_on(&user_task);
|
||||
let validation = dag.add_task(ValidateUser).depends_on(&user_task);
|
||||
let greeting = dag.add_task(GreetUser).depends_on(user_task);
|
||||
let validation = dag.add_task(ValidateUser).depends_on(user_task);
|
||||
|
||||
// Execute the DAG
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
|
||||
@@ -191,15 +191,15 @@ async fn main() {
|
||||
// Stage 2: Data transformation (with stateful tasks)
|
||||
let transformed_1 = dag
|
||||
.add_task(DataTransformer::new(1.5))
|
||||
.depends_on(&raw_value_1);
|
||||
.depends_on(raw_value_1);
|
||||
|
||||
let transformed_2 = dag
|
||||
.add_task(DataTransformer::new(2.0))
|
||||
.depends_on(&raw_value_2);
|
||||
.depends_on(raw_value_2);
|
||||
|
||||
let transformed_3 = dag
|
||||
.add_task(DataTransformer::new(0.5))
|
||||
.depends_on(&raw_value_3);
|
||||
.depends_on(raw_value_3);
|
||||
|
||||
// Stage 3: Statistical analysis (parallel operations on transformed data)
|
||||
let sum = dag
|
||||
|
||||
@@ -398,7 +398,7 @@ async fn main() {
|
||||
// Aggregate traces
|
||||
let summary = dag
|
||||
.add_task(TraceAggregator::new(correlation_id))
|
||||
.depends_on((&inventory, &payment, &shipping));
|
||||
.depends_on((inventory, payment, shipping));
|
||||
|
||||
// Run the DAG
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
|
||||
@@ -214,7 +214,7 @@ async fn main() {
|
||||
|
||||
let input = dag.add_task(StringSource("42"));
|
||||
|
||||
let parsed = dag.add_task(ParseInt).depends_on(&input);
|
||||
let parsed = dag.add_task(ParseInt).depends_on(input);
|
||||
|
||||
let validated = dag
|
||||
.add_task(ValidateRange { min: 0, max: 100 })
|
||||
@@ -240,7 +240,7 @@ async fn main() {
|
||||
|
||||
let input = dag.add_task(StringSource("not a number"));
|
||||
|
||||
let parsed = dag.add_task(ParseInt).depends_on(&input);
|
||||
let parsed = dag.add_task(ParseInt).depends_on(input);
|
||||
|
||||
let validated = dag
|
||||
.add_task(ValidateRange { min: 0, max: 100 })
|
||||
@@ -266,7 +266,7 @@ async fn main() {
|
||||
|
||||
let input = dag.add_task(StringSource("150"));
|
||||
|
||||
let parsed = dag.add_task(ParseInt).depends_on(&input);
|
||||
let parsed = dag.add_task(ParseInt).depends_on(input);
|
||||
|
||||
let validated = dag
|
||||
.add_task(ValidateRange { min: 0, max: 100 })
|
||||
@@ -292,7 +292,7 @@ async fn main() {
|
||||
|
||||
let input = dag.add_task(StringSource("invalid"));
|
||||
|
||||
let parsed = dag.add_task(ParseInt).depends_on(&input);
|
||||
let parsed = dag.add_task(ParseInt).depends_on(input);
|
||||
|
||||
let with_fallback = dag
|
||||
.add_task(WithFallback { fallback: 0 })
|
||||
|
||||
@@ -192,7 +192,7 @@ async fn main() {
|
||||
|
||||
// Verify a few results
|
||||
let sum: i32 = tasks
|
||||
.iter()
|
||||
.into_iter()
|
||||
.take(10)
|
||||
.map(|t| dag.get(t).unwrap())
|
||||
.fold(0i32, |acc, x| acc.wrapping_add(x));
|
||||
@@ -208,7 +208,7 @@ async fn main() {
|
||||
|
||||
// Create a deep chain by combining adjacent task pairs
|
||||
let tasks: Vec<_> = (0..100)
|
||||
.map(|i| dag.add_task(Compute { value: i }))
|
||||
.map(|i| dag.add_task(Compute { value: i }).into())
|
||||
.collect();
|
||||
let mut chain_tasks = vec![];
|
||||
for i in 0..99 {
|
||||
@@ -246,7 +246,7 @@ async fn main() {
|
||||
// Process all levels reducing by combining pairs
|
||||
let mut level = 0;
|
||||
let mut layer: Vec<dagx::TaskHandle<i32>> =
|
||||
current_level.iter().map(|b| b.into()).collect();
|
||||
current_level.into_iter().map(|b| b.into()).collect();
|
||||
|
||||
while layer.len() > 1 {
|
||||
level += 1;
|
||||
@@ -291,7 +291,7 @@ async fn main() {
|
||||
|
||||
// Layer 1: 50 source tasks
|
||||
let sources: Vec<_> = (0..50)
|
||||
.map(|i| dag.add_task(Compute { value: i }))
|
||||
.map(|i| dag.add_task(Compute { value: i }).into())
|
||||
.collect();
|
||||
|
||||
// Layer 2: 50 tasks, each depends on all sources
|
||||
@@ -361,11 +361,11 @@ async fn main() {
|
||||
|
||||
// Verify results are accessible
|
||||
let i32_sum: i32 = small_tasks
|
||||
.iter()
|
||||
.into_iter()
|
||||
.map(|t| dag.get(t).unwrap())
|
||||
.fold(0i32, |acc, x| acc.wrapping_add(x));
|
||||
let string_count = string_tasks
|
||||
.iter()
|
||||
.into_iter()
|
||||
.map(|t| dag.get(t).unwrap().len())
|
||||
.sum::<usize>();
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ async fn main() {
|
||||
let elapsed = start.elapsed();
|
||||
|
||||
// Verify all tasks completed correctly
|
||||
for (i, task) in tasks.iter().enumerate() {
|
||||
for (i, task) in tasks.into_iter().enumerate() {
|
||||
assert_eq!(dag.get(task).unwrap(), i as u32);
|
||||
}
|
||||
|
||||
|
||||
+10
-8
@@ -98,7 +98,7 @@
|
||||
//! === Timeout Example Complete ===
|
||||
//! ```
|
||||
|
||||
use dagx::{task, DagRunner};
|
||||
use dagx::{task, DagRunner, TaskHandle};
|
||||
use futures::FutureExt;
|
||||
use tokio::time::{sleep, timeout, Duration};
|
||||
|
||||
@@ -196,7 +196,7 @@ async fn main() {
|
||||
timeout_ms: 200,
|
||||
});
|
||||
|
||||
let processed = dag.add_task(ProcessResult).depends_on(&timed);
|
||||
let processed = dag.add_task(ProcessResult).depends_on(timed);
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
@@ -241,13 +241,15 @@ async fn main() {
|
||||
{
|
||||
let dag = DagRunner::new();
|
||||
|
||||
let source = dag.add_task(TaskWithTimeout {
|
||||
work_duration_ms: 500,
|
||||
timeout_ms: 100,
|
||||
});
|
||||
let source: TaskHandle<_> = dag
|
||||
.add_task(TaskWithTimeout {
|
||||
work_duration_ms: 500,
|
||||
timeout_ms: 100,
|
||||
})
|
||||
.into();
|
||||
|
||||
let processed1 = dag.add_task(ProcessResult).depends_on(&source);
|
||||
let processed2 = dag.add_task(ProcessResult).depends_on(&source);
|
||||
let processed1 = dag.add_task(ProcessResult).depends_on(source);
|
||||
let processed2 = dag.add_task(ProcessResult).depends_on(source);
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
|
||||
@@ -87,7 +87,7 @@ async fn main() {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Layer 0: Source
|
||||
let source = dag.add_task(Value(10));
|
||||
let source = dag.add_task(Value(10)).into();
|
||||
|
||||
// Layer 1: Two parallel computations
|
||||
let left = dag.add_task(Add).depends_on((&source, &source));
|
||||
@@ -112,7 +112,7 @@ async fn main() {
|
||||
|
||||
// Create a linear chain - each layer has only one task
|
||||
// This should trigger inline execution optimization
|
||||
let a = dag.add_task(Value(1));
|
||||
let a = dag.add_task(Value(1)).into();
|
||||
let b = dag.add_task(Add).depends_on((&a, &a));
|
||||
let c = dag.add_task(Multiply).depends_on((&b, &b));
|
||||
let d = dag.add_task(Add).depends_on((&c, &c));
|
||||
@@ -132,10 +132,10 @@ async fn main() {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Layer 0: Multiple sources
|
||||
let v1 = dag.add_task(Value(1));
|
||||
let v2 = dag.add_task(Value(2));
|
||||
let v3 = dag.add_task(Value(3));
|
||||
let v4 = dag.add_task(Value(4));
|
||||
let v1 = dag.add_task(Value(1)).into();
|
||||
let v2 = dag.add_task(Value(2)).into();
|
||||
let v3 = dag.add_task(Value(3)).into();
|
||||
let v4 = dag.add_task(Value(4)).into();
|
||||
|
||||
// Layer 1: Multiple parallel computations
|
||||
let sum12 = dag.add_task(Add).depends_on((&v1, &v2));
|
||||
|
||||
Reference in new issue
Block a user