node_flow/node/
base.rs

1use crate::describe::{Description, DescriptionBase};
2
3/// The `Node` trait serves as the core building block.
4///
5/// It defines how `Input` is processed into an `Output` (and `Error`) with a given `Context`.
6///
7/// # Type Parameters
8/// - `Input`: The type of data consumed by the node.
9/// - `Output`: The type of data produced by the node.
10/// - `Error`: The type representing possible errors.
11/// - `Context`: The type of context used during execution (it should always be a generic).
12///
13/// # Examples
14/// ```
15/// # use node_flow::node::{Node, NodeOutput};
16/// # use node_flow::describe::Description;
17/// #
18/// # struct ExampleNode;
19/// # struct MyError;
20/// #
21/// impl<Context: Send> Node<i32, NodeOutput<String>, MyError, Context> for ExampleNode {
22///     async fn run(
23///         &mut self,
24///         input: i32,
25///         _context: &mut Context,
26///     ) -> Result<NodeOutput<String>, MyError> {
27///         Ok(NodeOutput::Ok(format!("Processed: {}", input)))
28///     }
29///
30///     fn describe(&self) -> Description {
31///         Description::new_node::<Self, i32, String, MyError, Context>(self)
32///             .with_description("My example node")
33///     }
34/// }
35/// ```
36pub trait Node<Input, Output, Error, Context> {
37    /// Runs the node.
38    ///
39    /// This method performs the node's main computation or transformation logic.
40    ///
41    /// # Parameters
42    /// - `input`: The input data to process.
43    /// - `context`: Mutable reference to a context, which may be used for configuration, logging, or shared state.
44    ///
45    /// # Returns
46    /// A [`Future`] that resolves to a `Result<Output, Error>`.
47    ///
48    /// # Examples
49    /// ```
50    /// # use node_flow::node::Node;
51    /// #
52    /// # struct ExampleNode;
53    /// # struct MyError;
54    /// #
55    /// impl<Context: Send> Node<i32, String, MyError, Context> for ExampleNode {
56    ///     async fn run(
57    ///         &mut self,
58    ///         input: i32,
59    ///         _context: &mut Context,
60    ///     ) -> Result<String, MyError> {
61    ///         Ok(format!("Processed: {}", input))
62    ///     }
63    /// }
64    /// ```
65    fn run(
66        &mut self,
67        input: Input,
68        context: &mut Context,
69    ) -> impl Future<Output = Result<Output, Error>> + Send;
70
71    /// Describes this node, its type signature and other specifics.
72    ///
73    /// See [`Description`] for more details.
74    ///
75    /// # Examples
76    /// ```
77    /// # use node_flow::node::{Node, NodeOutput};
78    /// # use node_flow::describe::Description;
79    /// #
80    /// # struct ExampleNode;
81    /// # struct MyError;
82    /// #
83    /// impl<Context: Send> Node<i32, NodeOutput<String>, MyError, Context> for ExampleNode {
84    ///     async fn run(&mut self, input: i32, _context: &mut Context)
85    ///         -> Result<NodeOutput<String>, MyError> { todo!() }
86    ///
87    ///     fn describe(&self) -> Description {
88    ///         Description::new_node::<Self, i32, String, MyError, Context>(self)
89    ///             .with_description("My example node")
90    ///     }
91    /// }
92    /// ```
93    // if specialization is ever stabilized this whole function can be removed
94    // and Describe trait with default impl for Node<..> could be used
95    // https://github.com/rust-lang/rust/issues/31844
96    fn describe(&self) -> Description
97    where
98        Self: Sized,
99    {
100        let mut base = DescriptionBase::from::<Self, Input, Output, Error, Context>();
101
102        // remove NodeOutput<> from output name
103        let output_name = &mut base.output.name;
104        if let Some(b_pos) = output_name.find('<')
105            && output_name[..b_pos].contains("NodeOutput")
106        {
107            // remove `..::NodeOutput<`
108            output_name.replace_range(0..=b_pos, "");
109            // remove ending `>`
110            output_name.pop();
111        }
112
113        Description::Node { base }
114    }
115}