1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! Build and run typed task graphs.
//!
//! Tasks connect [`TaskNode`] implementations into a small execution graph. Each node receives a
//! typed input, produces a typed output, and hands control to the next step through a
//! [`Transition`].
//!
//! The main entry points are:
//! - [`Task`] to define and run a graph
//! - [`Transition`] to describe how execution should continue after a node finishes
//! - [`Task::register_node_fn`] for lightweight synchronous closure nodes
//! - [`NodeId`] helpers such as [`NodeId::transitions_with`] and [`NodeId::join`] for the common
//! next-step and join cases
//! - [`Transition::fan_out`] for typed static fan-out branches
//!
//! # Examples
//!
//! A small linear task:
//!
//! ```no_run
//! use swiftide_tasks::{NodeError, Task, TaskRunOutcome};
//!
//! # #[tokio::main(flavor = "current_thread")]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut task = Task::<i32, i32>::new();
//!
//! let start = task.register_node_fn(|input: &i32| -> Result<i32, NodeError> { Ok(*input + 1) });
//! let finish =
//! task.register_node_fn(|input: &i32| -> Result<i32, NodeError> { Ok(*input * 2) });
//!
//! task.starts_with(start);
//! task.register_transition(start, move |value| finish.transitions_with(value))?;
//! task.register_transition(finish, task.transitions_to_finish())?;
//!
//! let result = task.run(2).await?;
//! assert_eq!(result, TaskRunOutcome::Completed(6));
//! # Ok(())
//! # }
//! ```
//!
//! A fan-out with an explicit join:
//!
//! ```no_run
//! use swiftide_tasks::{JoinInput, NodeError, Task, TaskRunOutcome, Transition};
//!
//! # #[tokio::main(flavor = "current_thread")]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut task = Task::<i32, i32>::new();
//!
//! let start = task.register_node_fn(|input: &i32| -> Result<i32, NodeError> { Ok(*input) });
//! let double =
//! task.register_node_fn(|input: &i32| -> Result<i32, NodeError> { Ok(*input * 2) });
//! let increment =
//! task.register_node_fn(|input: &i32| -> Result<i32, NodeError> { Ok(*input + 1) });
//! let join = task.register_node_fn(|input: &JoinInput<i32>| -> Result<i32, NodeError> {
//! Ok(input.iter().copied().sum())
//! });
//!
//! task.starts_with(start);
//! task.register_transition(start, move |value| {
//! // `join_with` defines the branch group and the join node that waits for it.
//! Transition::fan_out(&double, value)
//! .and(&increment, value)
//! .join_with(join.join())
//! })?;
//! // Branches still decide where their own output goes before the join can run. Fan-out branches
//! // cannot finish independently; use a join node as the single place that finishes the task.
//! task.register_transition(double, join.join())?;
//! task.register_transition(increment, join.join())?;
//! task.register_transition(join, task.transitions_to_finish())?;
//!
//! let result = task.run(3).await?;
//! assert_eq!(result, TaskRunOutcome::Completed(10));
//! # Ok(())
//! # }
//! ```
pub use ;
pub use ;
pub use NodeId;
pub use ;
pub use ;
pub use ;