dagrs/node/
default_node.rs

1use std::sync::Arc;
2
3use async_trait::async_trait;
4
5use crate::{
6    connection::{in_channel::InChannels, out_channel::OutChannels},
7    utils::{env::EnvVar, output::Output},
8};
9
10use super::{
11    action::{Action, EmptyAction},
12    node::{Node, NodeId, NodeName, NodeTable},
13};
14
15/// # Default node type
16///
17/// [`DefaultNode`] is a default implementation of the [`Node`] trait. Users can use this node
18/// type to build tasks to meet most needs.
19///
20/// ## Create a `DefaultNode`:
21/// - use the method `new`. Required attributes: node's name; [`NodeTable`](for id allocation).
22///
23/// ```rust
24/// use dagrs::{NodeName, NodeTable, DefaultNode};
25///
26/// let node_name = "Node X";
27/// let mut node_table = NodeTable::new();
28/// let mut node = DefaultNode::new(
29///     NodeName::from(node_name),
30///     &mut node_table,
31/// );
32/// ```
33///
34/// - use the method `with_action`. Required attributes: node's name; [`NodeTable`](for id allocation);
35/// execution logic [`Action`].
36///
37/// ```rust
38/// use dagrs::{NodeName, NodeTable, DefaultNode, EmptyAction};
39///
40/// let node_name = "Node X";
41/// let mut node_table = NodeTable::new();
42/// let mut node = DefaultNode::with_action(
43///     NodeName::from(node_name),
44///     EmptyAction,
45///     &mut node_table,
46/// );
47/// ```
48pub struct DefaultNode {
49    id: NodeId,
50    name: NodeName,
51    action: Box<dyn Action>,
52    in_channels: InChannels,
53    out_channels: OutChannels,
54}
55#[async_trait]
56impl Node for DefaultNode {
57    fn id(&self) -> NodeId {
58        self.id
59    }
60
61    fn name(&self) -> NodeName {
62        self.name.clone()
63    }
64
65    fn input_channels(&mut self) -> &mut InChannels {
66        &mut self.in_channels
67    }
68
69    fn output_channels(&mut self) -> &mut OutChannels {
70        &mut self.out_channels
71    }
72
73    async fn run(&mut self, env: Arc<EnvVar>) -> Output {
74        self.action
75            .run(&mut self.in_channels, &mut self.out_channels, env)
76            .await
77    }
78}
79
80impl DefaultNode {
81    pub fn new(name: NodeName, node_table: &mut NodeTable) -> Self {
82        Self {
83            id: node_table.alloc_id_for(&name),
84            name,
85            action: Box::new(EmptyAction),
86            in_channels: InChannels::default(),
87            out_channels: OutChannels::default(),
88        }
89    }
90
91    pub fn with_action(
92        name: NodeName,
93        action: impl Action + 'static,
94        node_table: &mut NodeTable,
95    ) -> Self {
96        Self {
97            id: node_table.alloc_id_for(&name),
98            name,
99            action: Box::new(action),
100            in_channels: InChannels::default(),
101            out_channels: OutChannels::default(),
102        }
103    }
104
105    pub fn set_action(&mut self, action: impl Action + 'static) {
106        self.action = Box::new(action)
107    }
108}
109
110#[cfg(test)]
111mod test_default_node {
112
113    use std::sync::Arc;
114
115    use crate::{Content, EnvVar, InChannels, Node, NodeName, NodeTable, OutChannels, Output};
116
117    use super::{Action, DefaultNode};
118
119    use async_trait::async_trait;
120
121    /// An implementation of [`Action`] that returns [`Output::Out`] containing a String "Hello world".
122    #[derive(Default)]
123    pub struct HelloAction;
124    #[async_trait]
125    impl Action for HelloAction {
126        async fn run(&self, _: &mut InChannels, _: &mut OutChannels, _: Arc<EnvVar>) -> Output {
127            Output::Out(Some(Content::new("Hello world".to_string())))
128        }
129    }
130
131    impl HelloAction {
132        pub fn new() -> Self {
133            Self::default()
134        }
135    }
136
137    /// Test for create a default node.
138    ///
139    /// Step 1: create a [`DefaultNode`] with [`HelloAction`].
140    ///
141    /// Step 2: run the node and verify its output.
142    #[test]
143    fn create_default_node() {
144        let node_name = "Test Node";
145
146        let mut node_table = NodeTable::new();
147        let mut node = DefaultNode::with_action(
148            NodeName::from(node_name),
149            HelloAction::new(),
150            &mut node_table,
151        );
152
153        // Check if node table has key-value pair (node.name, node.id)
154        assert_eq!(node_table.get(node_name).unwrap(), &node.id());
155
156        let env = Arc::new(EnvVar::new(node_table));
157        let out = tokio::runtime::Runtime::new()
158            .unwrap()
159            .block_on(async { node.run(env).await.get_out().unwrap() });
160        let out: &String = out.get().unwrap();
161        assert_eq!(out, "Hello world");
162    }
163}