Depend on futures-util instead of futures
This commit is contained in:
1 parent
f342e33f16
commit
a75defa5a6
79 files changed
+447
-380
No files matched your search
+4
-4
@@ -22,7 +22,7 @@ use tracing::debug;
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use dagx::{task, DagRunner, Task};
|
||||
/// # use futures::FutureExt;
|
||||
/// #
|
||||
/// // Using tuple struct for simple constants
|
||||
/// struct Constant(i32);
|
||||
///
|
||||
@@ -57,7 +57,7 @@ use tracing::debug;
|
||||
/// let b = b.depends_on(a);
|
||||
/// // 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);
|
||||
/// # };
|
||||
/// ```
|
||||
@@ -81,7 +81,7 @@ impl<'a, Tk: Task, Deps> TaskBuilder<'a, Tk, Deps> {
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use dagx::{task, DagRunner, Task};
|
||||
/// # use futures::FutureExt;
|
||||
/// #
|
||||
/// // Tuple struct
|
||||
/// struct Value(i32);
|
||||
///
|
||||
@@ -118,7 +118,7 @@ impl<'a, Tk: Task, Deps> TaskBuilder<'a, Tk, Deps> {
|
||||
/// // Multiple dependencies: tuple form
|
||||
/// 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>
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ impl std::fmt::Display for DagError {
|
||||
f,
|
||||
"Result not found for task #{}.\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
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ fn test_dag_error_display_result_not_found() {
|
||||
|
||||
assert!(display.contains("Result not found"));
|
||||
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]
|
||||
|
||||
+14
-15
@@ -24,7 +24,6 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use dagx::{task, DagRunner, Task, TaskHandle};
|
||||
//! use futures::FutureExt; // for FutureExt::map
|
||||
//!
|
||||
//! // Source task with read-only state (tuple struct)
|
||||
//! struct Value(i32);
|
||||
@@ -53,7 +52,7 @@
|
||||
//! let sum = dag.add_task(Add).depends_on((x, &y));
|
||||
//!
|
||||
//! // Execute and retrieve results
|
||||
//! dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await.unwrap();
|
||||
//! dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() }).await.unwrap();
|
||||
//! assert_eq!(dag.get(sum).unwrap(), 5);
|
||||
//! # };
|
||||
//! ```
|
||||
@@ -291,7 +290,7 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use dagx::{task, DagRunner, Task};
|
||||
//! use futures::FutureExt;
|
||||
//!
|
||||
//!
|
||||
//! // Source task (tuple struct)
|
||||
//! struct Value(i32);
|
||||
@@ -324,7 +323,7 @@
|
||||
//! let plus1 = dag.add_task(Add(1)).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(times2).unwrap(), 20);
|
||||
@@ -337,7 +336,7 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use dagx::{task, DagRunner, Task};
|
||||
//! use futures::FutureExt;
|
||||
//!
|
||||
//!
|
||||
//! // Source task for String (tuple struct)
|
||||
//! struct Name(String);
|
||||
@@ -381,7 +380,7 @@
|
||||
//! let active = dag.add_task(Active(true));
|
||||
//! 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");
|
||||
//! # };
|
||||
@@ -393,7 +392,7 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use dagx::{task, DagRunner, Task};
|
||||
//! use futures::FutureExt;
|
||||
//!
|
||||
//!
|
||||
//! // Source task (tuple struct)
|
||||
//! struct Value(i32);
|
||||
@@ -434,7 +433,7 @@
|
||||
//! // Layer 3: Final result
|
||||
//! 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);
|
||||
//! # };
|
||||
@@ -447,7 +446,7 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use dagx::{task, DagRunner, Task};
|
||||
//! # use futures::FutureExt;
|
||||
//! #
|
||||
//!
|
||||
//! struct User {
|
||||
//! name: String,
|
||||
@@ -476,7 +475,7 @@
|
||||
//! let user = dag.add_task(CreateUser);
|
||||
//! 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");
|
||||
//! # };
|
||||
@@ -533,7 +532,7 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use dagx::{task, DagRunner, Task};
|
||||
//! # use futures::FutureExt;
|
||||
//! #
|
||||
//! # struct Value(i32);
|
||||
//! # #[task]
|
||||
//! # impl Value {
|
||||
@@ -543,11 +542,11 @@
|
||||
//! # let dag = DagRunner::new();
|
||||
//! # let node = dag.add_task(Value(42));
|
||||
//! // 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();
|
||||
//!
|
||||
//! // 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"),
|
||||
//! Err(e) => eprintln!("DAG execution failed: {}", e),
|
||||
//! }
|
||||
@@ -631,7 +630,7 @@
|
||||
//!
|
||||
//! ```
|
||||
//! # use dagx::{task, DagRunner, Task};
|
||||
//! # use futures::FutureExt;
|
||||
//! #
|
||||
//!
|
||||
//! // ✅ CORRECT: Just output Vec<String>, framework wraps in Arc internally
|
||||
//! struct FetchData;
|
||||
@@ -661,7 +660,7 @@
|
||||
//! let task2 = 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
@@ -9,14 +9,13 @@ use std::any::Any;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::future::Future;
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
};
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::{FutureExt, StreamExt, TryFutureExt};
|
||||
use futures_util::{stream::FuturesUnordered, FutureExt, StreamExt, TryFutureExt};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
@@ -28,6 +27,8 @@ use crate::node::{ExecutableNode, TypedNode};
|
||||
use crate::task::Task;
|
||||
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
|
||||
struct RunGuard<'a> {
|
||||
lock: &'a AtomicBool,
|
||||
@@ -56,7 +57,7 @@ impl<'a> Drop for RunGuard<'a> {
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use dagx::{task, DagRunner, Task};
|
||||
/// # use futures::FutureExt;
|
||||
/// #
|
||||
/// // Task with state constructed via ::new()
|
||||
/// struct LoadValue { value: i32 }
|
||||
///
|
||||
@@ -85,7 +86,7 @@ impl<'a> Drop for RunGuard<'a> {
|
||||
/// let y = dag.add_task(LoadValue::new(3));
|
||||
/// 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);
|
||||
/// # };
|
||||
@@ -150,7 +151,7 @@ impl DagRunner {
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use dagx::{task, DagRunner, Task};
|
||||
/// # use futures::FutureExt;
|
||||
/// #
|
||||
/// // Task with state - shows you construct with specific value
|
||||
/// struct LoadValue {
|
||||
/// initial: i32,
|
||||
@@ -192,7 +193,7 @@ impl DagRunner {
|
||||
/// // Construct task with offset of 1
|
||||
/// 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);
|
||||
/// # };
|
||||
/// ```
|
||||
@@ -236,7 +237,7 @@ impl DagRunner {
|
||||
///
|
||||
/// - `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:
|
||||
/// - Tokio: `|fut| { tokio::spawn(fut).map(Result::unwrap) }`
|
||||
/// - Tokio: `|fut| { tokio::spawn(fut).await.unwrap() }`
|
||||
/// - Smol: `|fut| { smol::spawn(fut) }`
|
||||
/// - Async-std: `|fut| { async_std::task::spawn(fut) }`
|
||||
/// - Single-threaded: `|fut| fut`
|
||||
@@ -256,7 +257,7 @@ impl DagRunner {
|
||||
///
|
||||
/// ```
|
||||
/// # use dagx::{task, DagRunner, Task};
|
||||
/// # use futures::FutureExt;
|
||||
/// #
|
||||
/// // Tuple struct
|
||||
/// struct Value(i32);
|
||||
///
|
||||
@@ -280,7 +281,7 @@ impl DagRunner {
|
||||
/// let b = dag.add_task(Value(2));
|
||||
/// 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]
|
||||
@@ -531,7 +532,7 @@ impl DagRunner {
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use dagx::{task, DagRunner, Task};
|
||||
/// # use futures::FutureExt;
|
||||
/// #
|
||||
/// struct Configuration {
|
||||
/// setting: i32,
|
||||
/// }
|
||||
@@ -553,7 +554,7 @@ impl DagRunner {
|
||||
/// // Construct task with specific setting value
|
||||
/// 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);
|
||||
/// # };
|
||||
|
||||
+9
-7
@@ -4,8 +4,6 @@ use crate::error::DagError;
|
||||
use crate::runner::DagRunner;
|
||||
use crate::types::TaskHandle;
|
||||
|
||||
use futures::FutureExt;
|
||||
|
||||
// Initialize tracing subscriber for tests (idempotent)
|
||||
#[cfg(feature = "tracing")]
|
||||
fn init_tracing() {
|
||||
@@ -69,7 +67,7 @@ async fn test_get_wrong_type() {
|
||||
let dag = DagRunner::new();
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
@@ -144,12 +142,14 @@ async fn test_concurrent_run_protection() {
|
||||
// Start two runs concurrently
|
||||
let handle1 = tokio::spawn(async move {
|
||||
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 {
|
||||
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)
|
||||
@@ -197,7 +197,7 @@ async fn test_invalid_node_id_in_get() {
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
dag.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -250,7 +250,9 @@ async fn test_task_panic_in_multi_task_layer() {
|
||||
let _good_task = dag.add_task(GoodTask).depends_on(source);
|
||||
|
||||
// Run the DAG - the panic should be caught
|
||||
let result = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await;
|
||||
let result = dag
|
||||
.run(|fut| async move { tokio::spawn(fut).await.unwrap() })
|
||||
.await;
|
||||
|
||||
// The run should fail due to the panic
|
||||
// Note: Tokio catches panics in spawned tasks, so the behavior depends on the runtime
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ pub struct NodeId(pub usize);
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use dagx::{task, DagRunner, Task};
|
||||
/// # use futures::FutureExt;
|
||||
/// #
|
||||
/// # struct LoadValue { value: i32 }
|
||||
/// # impl LoadValue { pub fn new(v: i32) -> Self { Self { value: v } } }
|
||||
/// # #[task]
|
||||
@@ -34,7 +34,7 @@ pub struct NodeId(pub usize);
|
||||
/// let dag = DagRunner::new();
|
||||
/// 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);
|
||||
/// # };
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
//! These tests ensure we hit line 71 in the From<TaskBuilder> implementation
|
||||
|
||||
use crate::{task, DagRunner, TaskHandle};
|
||||
use futures::FutureExt;
|
||||
|
||||
#[tokio::test]
|
||||
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
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
@@ -79,7 +78,7 @@ async fn test_unit_type_conversion_with_multiple_tasks() {
|
||||
let second_handle: TaskHandle<_> = second_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
|
||||
.unwrap();
|
||||
|
||||
@@ -118,7 +117,7 @@ async fn test_unit_struct_with_state() {
|
||||
// Explicit conversion - triggers line 71
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
@@ -144,7 +143,7 @@ async fn test_taskbuilder_conversion_assignment() {
|
||||
// This also uses From<TaskBuilder> implementation
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
@@ -181,7 +180,7 @@ async fn test_mixed_unit_and_dependent_tasks() {
|
||||
// Doubler needs dependencies, so we use it differently
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
|
||||
Reference in new issue
Block a user