Skip to main content

node_flow/flows/sequential_flow/
builder.rs

1use std::marker::PhantomData;
2
3use super::SequentialFlow as Flow;
4use crate::{
5    flows::{ChainLink, NodeIOE, generic_defs::debug::impl_debug_for_builder},
6    node::{Node, NodeOutput as NodeOutputStruct},
7};
8
9/// Builder for [`SequentialFlow`](Flow).
10///
11/// This builder ensures:
12/// - `Input` into the flow can be converted into the input of the first node
13/// - output of the last node can be converted into the `Output` of the flow
14/// - error of all nodes can be converted into the `Error` of the flow
15/// - output of a previous node can be converted into the input of the next node
16///
17/// See also [`SequentialFlow`](Flow).
18pub struct Builder<Input, Output, Error, Context, NodeTypes = (), NodeIOETypes = ()>
19where
20    // Trait bounds for better and nicer errors
21    Input: Send,
22    Error: Send,
23    Context: Send,
24{
25    #[expect(clippy::type_complexity)]
26    _ioec: PhantomData<fn() -> (Input, Output, Error, Context)>,
27    _nodes_io: PhantomData<fn() -> NodeIOETypes>,
28    nodes: NodeTypes,
29}
30
31impl_debug_for_builder!(
32    "SequentialFlow",
33    Builder,
34    Input: Send,
35    Error: Send,
36    Context: Send
37);
38
39impl<Input, Output, Error, Context> Default for Builder<Input, Output, Error, Context>
40where
41    // Trait bounds for better and nicer errors
42    Input: Send,
43    Error: Send,
44    Context: Send,
45{
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51impl<Input, Output, Error, Context> Builder<Input, Output, Error, Context>
52where
53    // Trait bounds for better and nicer errors
54    Input: Send,
55    Error: Send,
56    Context: Send,
57{
58    /// Creates a new empty builder for [`SequentialFlow`](Flow).
59    #[must_use]
60    pub fn new() -> Self {
61        Self {
62            _ioec: PhantomData,
63            _nodes_io: PhantomData,
64            nodes: (),
65        }
66    }
67
68    /// Adds a new node.
69    ///
70    /// The new node must satisfy:
71    /// - `Self`: `Node<NodeInputType, NodeOutput<NodeOutputType>, NodeErrorType, _>`
72    /// - `Input`: `Into<NodeInputType>`,
73    /// - `NodeErrorType`: `Into<Error>`,
74    ///
75    /// # Returns
76    /// A new [`Builder`] with the added node.
77    #[expect(clippy::type_complexity, clippy::type_repetition_in_bounds)]
78    pub fn add_node<NodeType, NodeInput, NodeOutput, NodeError>(
79        self,
80        node: NodeType,
81    ) -> Builder<
82        Input,
83        Output,
84        Error,
85        Context,
86        (NodeType,),
87        ChainLink<(), NodeIOE<NodeInput, NodeOutput, NodeError>>,
88    >
89    where
90        Input: Into<NodeInput>,
91        NodeError: Into<Error>,
92        NodeType: Node<NodeInput, NodeOutputStruct<NodeOutput>, NodeError, Context>,
93        // Trait bounds for better and nicer errors
94        NodeType: Clone + Send + Sync,
95        NodeInput: Send,
96    {
97        Builder {
98            _ioec: PhantomData,
99            _nodes_io: PhantomData,
100            nodes: (node,),
101        }
102    }
103}
104
105impl<
106    Input,
107    Output,
108    Error,
109    Context,
110    NodeTypes,
111    LastNodeInType,
112    LastNodeOutType,
113    LastNodeErrType,
114    OtherNodeIOETypes,
115>
116    Builder<
117        Input,
118        Output,
119        Error,
120        Context,
121        NodeTypes,
122        ChainLink<OtherNodeIOETypes, NodeIOE<LastNodeInType, LastNodeOutType, LastNodeErrType>>,
123    >
124where
125    // Trait bounds for better and nicer errors
126    Input: Send,
127    Error: Send,
128    Context: Send,
129{
130    /// Adds a new node.
131    ///
132    /// The new node must satisfy:
133    /// - `Self`: `Node<NodeInputType, NodeOutput<NodeOutputType>, NodeErrorType, _>`
134    /// - `NodeErrorType`: `Into<Error>`,
135    /// - `LastNodeOutputType`: `Into<NodeInputType>`,
136    ///
137    /// # Returns
138    /// A new [`Builder`] with the added node.
139    #[expect(clippy::type_complexity, clippy::type_repetition_in_bounds)]
140    pub fn add_node<NodeType, NodeInput, NodeOutput, NodeError>(
141        self,
142        node: NodeType,
143    ) -> Builder<
144        Input,
145        Output,
146        Error,
147        Context,
148        ChainLink<NodeTypes, NodeType>,
149        ChainLink<
150            ChainLink<OtherNodeIOETypes, NodeIOE<LastNodeInType, LastNodeOutType, LastNodeErrType>>,
151            NodeIOE<NodeInput, NodeOutput, NodeError>,
152        >,
153    >
154    where
155        LastNodeOutType: Into<NodeInput>,
156        NodeError: Into<Error>,
157        NodeType: Node<NodeInput, NodeOutputStruct<NodeOutput>, NodeError, Context>,
158        // Trait bounds for better and nicer errors
159        NodeType: Clone + Send + Sync,
160        NodeInput: Send,
161    {
162        Builder {
163            _ioec: PhantomData,
164            _nodes_io: PhantomData,
165            nodes: (self.nodes, node),
166        }
167    }
168
169    /// Finalizes the builder and produces a [`SequentialFlow`](Flow) instance.
170    #[expect(clippy::type_complexity)]
171    pub fn build(
172        self,
173    ) -> Flow<
174        Input,
175        Output,
176        Error,
177        Context,
178        NodeTypes,
179        ChainLink<OtherNodeIOETypes, NodeIOE<LastNodeInType, LastNodeOutType, LastNodeErrType>>,
180    >
181    where
182        LastNodeOutType: Into<Output>,
183    {
184        Flow {
185            _ioec: PhantomData,
186            _nodes_io: PhantomData,
187            nodes: self.nodes,
188        }
189    }
190}