synaptic_graph/command.rs
1use std::sync::Arc;
2
3use tokio::sync::Mutex;
4
5/// A graph execution command that can override normal edge routing.
6///
7/// Commands provide dynamic control flow within graph nodes, allowing
8/// nodes to redirect execution to specific nodes or end the graph
9/// without relying solely on edge definitions.
10#[derive(Debug, Clone)]
11pub enum GraphCommand {
12 /// Go to a specific node next, overriding normal routing.
13 Goto(String),
14 /// End the graph execution immediately.
15 End,
16}
17
18/// A context that nodes can use to issue graph execution commands.
19///
20/// The `GraphContext` is shared between the graph execution loop and
21/// individual nodes. Nodes call `goto()` or `end()` to signal the
22/// desired control flow, and the compiled graph checks for these
23/// commands after each node execution.
24///
25/// # Example
26///
27/// ```ignore
28/// use synaptic_graph::GraphContext;
29///
30/// async fn my_node_logic(ctx: &GraphContext) {
31/// // Skip normal routing and go directly to "summary" node
32/// ctx.goto("summary").await;
33/// }
34/// ```
35#[derive(Clone)]
36pub struct GraphContext {
37 command: Arc<Mutex<Option<GraphCommand>>>,
38}
39
40impl GraphContext {
41 /// Create a new `GraphContext`.
42 pub fn new() -> Self {
43 Self {
44 command: Arc::new(Mutex::new(None)),
45 }
46 }
47
48 /// Signal the graph to go to a specific node next, overriding normal routing.
49 pub async fn goto(&self, node: impl Into<String>) {
50 *self.command.lock().await = Some(GraphCommand::Goto(node.into()));
51 }
52
53 /// Signal the graph to end execution immediately.
54 pub async fn end(&self) {
55 *self.command.lock().await = Some(GraphCommand::End);
56 }
57
58 /// Take the current command (if any), clearing it from the slot.
59 ///
60 /// This is used internally by `CompiledGraph` after each node execution.
61 pub(crate) async fn take_command(&self) -> Option<GraphCommand> {
62 self.command.lock().await.take()
63 }
64}
65
66impl Default for GraphContext {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72impl std::fmt::Debug for GraphContext {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 f.debug_struct("GraphContext").finish()
75 }
76}