1use std::{collections::HashMap, io::Cursor, string::FromUtf8Error, sync::Arc};
2
3use futures::future::BoxFuture;
4use log::{debug, info};
5use quick_xml::{
6 events::{attributes::Attributes, Event},
7 name::QName,
8 Reader,
9};
10use thiserror::Error;
11
12use crate::{
13 basic_types::{
14 AttrsToMap, FromString, NodeCategory, NodeStatus, ParseBoolError, PortChecks,
15 PortDirection, PortsRemapping,
16 },
17 blackboard::{Blackboard, BlackboardString},
18 macros::build_node_ptr,
19 nodes::{self, NodeConfig, NodeResult, TreeNode},
20};
21
22#[derive(Debug, Error)]
23pub enum ParseError {
24 #[error("Port name [{0}] did not match Node [{1}] port list: {2:?}")]
25 InvalidPort(String, String, Vec<String>),
27 #[error("Error occurred parsing XML attribute: {0}")]
28 AttrError(#[from] quick_xml::events::attributes::AttrError),
29 #[error("Error occurred parsing XML: {0}")]
30 XMLError(#[from] quick_xml::Error),
31 #[error("Expected to find <root> start tag at start of XML. Found incorrect tag.")]
32 MissingRoot,
33 #[error("Expected to find <root> tag at start of XML. Found <{0}> instead.")]
34 ExpectedRoot(String),
35 #[error("Reached EOF of the XML unexpectedly.")]
36 UnexpectedEof,
37 #[error("Error parsing UTF8: {0}")]
38 Utf8Error(#[from] FromUtf8Error),
39 #[error("Attempted to parse node with unregistered name: {0}")]
40 UnknownNode(String),
41 #[error("Errors like this shouldn't happen. {0}")]
42 InternalError(String),
43 #[error("{0}")]
44 MissingAttribute(String),
45 #[error("Can't find tree [{0}]")]
46 UnknownTree(String),
47 #[error("Node type [] didn't had invalid presence/absence of children.")]
48 NodeTypeMismatch(String),
49 #[error("No main tree was provided, either in the XML or as a function parameter.")]
50 NoMainTree,
51 #[error("{0}")]
52 ParseStringError(#[from] ParseBoolError),
53}
54
55type NodeCreateFnDyn = dyn Fn(NodeConfig, Vec<TreeNode>) -> TreeNode + Send + Sync;
56
57enum TickOption {
58 WhileRunning,
59 ExactlyOnce,
60 OnceUnlessWokenUp,
61}
62
63#[derive(Debug)]
64pub struct AsyncTree {
65 root: TreeNode,
66}
67
68impl AsyncTree {
69 pub fn new(root: TreeNode) -> AsyncTree {
70 Self { root }
71 }
72
73 async fn tick_root(&mut self, opt: TickOption) -> NodeResult {
74 let mut status = NodeStatus::Idle;
75
76 while status == NodeStatus::Idle
77 || (matches!(opt, TickOption::WhileRunning) && matches!(status, NodeStatus::Running))
78 {
79 status = self.root.execute_tick().await?;
80
81 if status.is_completed() {
84 self.root.reset_status();
85 }
86 }
87
88 Ok(status)
89 }
90
91 pub async fn tick_exactly_once(&mut self) -> NodeResult {
92 self.tick_root(TickOption::ExactlyOnce).await
93 }
94
95 pub async fn tick_once(&mut self) -> NodeResult {
96 self.tick_root(TickOption::OnceUnlessWokenUp).await
97 }
98
99 pub async fn tick_while_running(&mut self) -> NodeResult {
100 self.tick_root(TickOption::WhileRunning).await
101 }
102
103 pub async fn root_blackboard(&self) -> Blackboard {
104 self.root.config().blackboard.clone()
105 }
106
107 pub async fn halt_tree(&mut self) {
108 self.root.halt().await;
109 }
110}
111
112#[derive(Debug)]
113pub struct SyncTree {
114 root: AsyncTree,
115}
116
117impl SyncTree {
118 pub fn new(root: TreeNode) -> SyncTree {
119 Self {
120 root: AsyncTree::new(root),
121 }
122 }
123
124 pub fn tick_exactly_once(&mut self) -> NodeResult {
125 futures::executor::block_on(self.root.tick_exactly_once())
126 }
127
128 pub fn tick_once(&mut self) -> NodeResult {
129 futures::executor::block_on(self.root.tick_once())
130 }
131
132 pub fn tick_while_running(&mut self) -> NodeResult {
133 futures::executor::block_on(self.root.tick_while_running())
134 }
135
136 pub fn root_blackboard(&self) -> Blackboard {
137 futures::executor::block_on(self.root.root_blackboard())
138 }
139
140 pub async fn halt_tree(&mut self) {
141 futures::executor::block_on(self.root.halt_tree());
142 }
143}
144
145pub struct Factory {
146 node_map: HashMap<String, (NodeCategory, Arc<NodeCreateFnDyn>)>,
147 blackboard: Blackboard,
148 tree_roots: HashMap<String, Reader<Cursor<Vec<u8>>>>,
149 main_tree_id: Option<String>,
150 tree_uid: std::sync::Mutex<u32>,
152}
153
154impl Factory {
155 pub fn new() -> Factory {
156 let blackboard = Blackboard::create();
157
158 Self {
159 node_map: builtin_nodes(),
160 blackboard,
161 tree_roots: HashMap::new(),
162 main_tree_id: None,
163 tree_uid: std::sync::Mutex::new(0),
164 }
165 }
166
167 pub fn blackboard(&mut self) -> &Blackboard {
168 &self.blackboard
169 }
170
171 pub fn set_blackboard(&mut self, blackboard: Blackboard) {
172 self.blackboard = blackboard;
173 }
174
175 pub fn register_node<F>(&mut self, name: impl AsRef<str>, node_fn: F, node_type: NodeCategory)
176 where
177 F: Fn(NodeConfig, Vec<TreeNode>) -> TreeNode + Send + Sync + 'static,
178 {
179 self.node_map
180 .insert(name.as_ref().into(), (node_type, Arc::new(node_fn)));
181 }
182
183 fn create_node(
184 &self,
185 node_fn: &Arc<NodeCreateFnDyn>,
186 config: NodeConfig,
187 children: Vec<TreeNode>,
188 ) -> TreeNode {
189 node_fn(config, children)
190 }
191
192 fn get_uid(&self) -> u32 {
193 let uid = *self.tree_uid.lock().unwrap();
194 *self.tree_uid.lock().unwrap() += 1;
195
196 uid
197 }
198
199 async fn recursively_build_subtree(
200 &self,
201 tree_id: &String,
202 tree_name: &String,
203 path_prefix: &String,
204 blackboard: Blackboard,
205 ) -> Result<TreeNode, ParseError> {
206 let mut reader = match self.tree_roots.get(tree_id) {
207 Some(root) => root.clone(),
208 None => {
209 return Err(ParseError::UnknownTree(tree_id.clone()));
210 }
211 };
212
213 match self
214 .build_child(&mut reader, &blackboard, tree_name, path_prefix)
215 .await?
216 {
217 Some(child) => Ok(child),
218 None => Err(ParseError::NodeTypeMismatch("SubTree".to_string())),
219 }
220 }
221
222 pub fn create_sync_tree_from_text(
223 &mut self,
224 text: String,
225 blackboard: &Blackboard,
226 ) -> Result<SyncTree, ParseError> {
227 self.register_bt_from_text(text)?;
228
229 if self.tree_roots.len() > 1 && self.main_tree_id.is_none() {
230 Err(ParseError::NoMainTree)
231 } else if self.tree_roots.len() == 1 {
232 let main_tree_id = self.tree_roots.iter().next().unwrap().0.clone();
234
235 self.instantiate_sync_tree(blackboard, &main_tree_id)
236 } else {
237 let main_tree_id = self.main_tree_id.clone().unwrap();
240 self.instantiate_sync_tree(blackboard, &main_tree_id)
241 }
242 }
243
244 pub async fn create_async_tree_from_text(
245 &mut self,
246 text: String,
247 blackboard: &Blackboard,
248 ) -> Result<AsyncTree, ParseError> {
249 self.register_bt_from_text(text)?;
250
251 if self.tree_roots.len() > 1 && self.main_tree_id.is_none() {
252 Err(ParseError::NoMainTree)
253 } else if self.tree_roots.len() == 1 {
254 let main_tree_id = self.tree_roots.iter().next().unwrap().0.clone();
256
257 self.instantiate_async_tree(blackboard, &main_tree_id).await
258 } else {
259 let main_tree_id = self.main_tree_id.clone().unwrap();
262 self.instantiate_async_tree(blackboard, &main_tree_id).await
263 }
264 }
265
266 pub fn instantiate_sync_tree(
267 &mut self,
268 blackboard: &Blackboard,
269 main_tree_id: &str,
270 ) -> Result<SyncTree, ParseError> {
271 let blackboard = blackboard.clone();
273
274 let main_tree_id = String::from(main_tree_id);
275
276 let root_node = futures::executor::block_on(self.recursively_build_subtree(
277 &main_tree_id,
278 &String::new(),
279 &String::new(),
280 blackboard,
281 ))?;
282
283 Ok(SyncTree::new(root_node))
284 }
285
286 pub async fn instantiate_async_tree(
287 &mut self,
288 blackboard: &Blackboard,
289 main_tree_id: &str,
290 ) -> Result<AsyncTree, ParseError> {
291 let blackboard = blackboard.clone();
293
294 let main_tree_id = String::from(main_tree_id);
295
296 let root_node = self
297 .recursively_build_subtree(&main_tree_id, &String::new(), &String::new(), blackboard)
298 .await?;
299
300 Ok(AsyncTree::new(root_node))
301 }
302
303 async fn build_leaf_node<'a>(
304 &self,
305 node_name: &String,
306 attributes: Attributes<'a>,
307 config: NodeConfig,
308 ) -> Result<TreeNode, ParseError> {
309 let (node_type, node_fn) = self
311 .node_map
312 .get(node_name)
313 .ok_or_else(|| ParseError::UnknownNode(node_name.clone()))?;
314 if !matches!(node_type, NodeCategory::Action) {
315 return Err(ParseError::NodeTypeMismatch(String::from("Action")));
316 }
317
318 let mut node = self.create_node(node_fn, config, Vec::new());
319
320 self.add_ports_to_node(&mut node, node_name, attributes)
321 .await?;
322
323 Ok(node)
324 }
325
326 async fn build_children(
327 &self,
328 reader: &mut Reader<Cursor<Vec<u8>>>,
329 blackboard: &Blackboard,
330 tree_name: &String,
331 path_prefix: &String,
332 ) -> Result<Vec<TreeNode>, ParseError> {
333 let mut nodes = Vec::new();
334
335 while let Some(node) = self
336 .build_child(reader, blackboard, tree_name, path_prefix)
337 .await?
338 {
339 nodes.push(node);
340 }
341
342 Ok(nodes)
343 }
344
345 async fn add_ports_to_node<'a>(
346 &self,
347 node_ptr: &mut TreeNode,
348 node_name: &str,
349 attributes: Attributes<'a>,
350 ) -> Result<(), ParseError> {
351 let config = node_ptr.config_mut();
352 let manifest = config.manifest()?;
353
354 let mut remap = PortsRemapping::new();
355
356 for (port_name, port_value) in attributes.to_map()? {
357 remap.insert(port_name, port_value);
358 }
359
360 for port_name in remap.keys() {
362 if !manifest.ports.contains_key(port_name) {
363 return Err(ParseError::InvalidPort(
364 port_name.clone(),
365 node_name.to_owned(),
366 manifest.ports.to_owned().into_keys().collect(),
367 ));
368 }
369 }
370
371 for (remap_name, remap_val) in remap {
373 if let Some(port) = manifest.ports.get(&remap_name) {
374 config.add_port(port.direction().clone(), remap_name, remap_val);
375 }
376 }
377
378 for (port_name, port_info) in manifest.ports.iter() {
380 let direction = port_info.direction();
381
382 if !matches!(direction, PortDirection::Output)
383 && !config.has_port(direction, port_name)
384 && port_info.default_value().is_some()
385 {
386 config.add_port(
387 PortDirection::Input,
388 port_name.clone(),
389 port_info.default_value_str().unwrap(),
390 );
391 }
392 }
393
394 Ok(())
395 }
396
397 fn build_child<'a>(
398 &'a self,
399 reader: &'a mut Reader<Cursor<Vec<u8>>>,
400 blackboard: &'a Blackboard,
401 tree_name: &'a String,
402 path_prefix: &'a String,
403 ) -> BoxFuture<Result<Option<TreeNode>, ParseError>> {
404 Box::pin(async move {
405 let mut buf = Vec::new();
406
407 let node = match reader.read_event_into(&mut buf)? {
408 Event::Eof => {
410 debug!("EOF");
411 return Err(ParseError::UnexpectedEof);
412 }
413 Event::Start(e) => {
415 let node_name = String::from_utf8(e.name().0.into())?;
416 let attributes = e.attributes();
417
418 debug!("build_child Start: {node_name}");
419
420 let mut config = NodeConfig::new(blackboard.clone());
421 config.path = path_prefix.to_owned() + &node_name;
422
423 let (node_type, node_fn) = self
424 .node_map
425 .get(&node_name)
426 .ok_or_else(|| ParseError::UnknownNode(node_name.clone()))?;
427
428 let node = match node_type {
429 NodeCategory::Control => {
430 let children = self
431 .build_children(
432 reader,
433 blackboard,
434 tree_name,
435 &(config.path.to_owned() + "/"),
436 )
437 .await?;
438
439 let mut node = self.create_node(node_fn, config, children);
440
441 self.add_ports_to_node(&mut node, &node_name, attributes)
442 .await?;
443
444 node
445 }
446 NodeCategory::Decorator => {
447 let child = match self
448 .build_child(
449 reader,
450 blackboard,
451 tree_name,
452 &(config.path.to_owned() + "/"),
453 )
454 .await?
455 {
456 Some(node) => node,
457 None => {
458 return Err(ParseError::NodeTypeMismatch(
459 "Decorator".to_string(),
460 ));
461 }
462 };
463
464 let mut node = self.create_node(node_fn, config, vec![child]);
465
466 self.add_ports_to_node(&mut node, &node_name, attributes)
467 .await?;
468
469 let mut buf = Vec::new();
471 reader.read_event_into(&mut buf)?;
472
473 node
474 }
475 x => return Err(ParseError::NodeTypeMismatch(format!("{x:?}"))),
477 };
478
479 Some(node)
480 }
481 Event::Empty(e) => {
483 let node_name = String::from_utf8(e.name().0.into())?;
484 debug!("[Leaf node]: {node_name}");
485 let attributes = e.attributes();
486
487 let mut config = NodeConfig::new(blackboard.clone());
488 config.path = path_prefix.to_owned() + &node_name;
489
490 let node = match node_name.as_str() {
491 "SubTree" => {
492 let attributes = attributes.to_map()?;
493 let mut child_blackboard = Blackboard::with_parent(blackboard);
494
495 for (attr, value) in attributes.iter() {
497 if attr == "_autoremap" {
499 child_blackboard.enable_auto_remapping(
500 <bool as FromString>::from_string(value)?,
501 );
502 continue;
503 } else if !attr.is_allowed_port_name() {
504 continue;
505 }
506
507 if let Some(port_name) = value.strip_bb_pointer() {
508 child_blackboard.add_subtree_remapping(attr.clone(), port_name);
510 } else {
511 child_blackboard.set(attr, value.clone());
513 }
514 }
515
516 let id = match attributes.get("ID") {
517 Some(id) => id,
518 None => return Err(ParseError::MissingAttribute("ID".to_string())),
519 };
520
521 let mut subtree_name = tree_name.clone();
522 if !subtree_name.is_empty() {
523 subtree_name += "/";
524 }
525
526 if let Some(name_attr) = attributes.get("name") {
527 subtree_name += name_attr;
528 } else {
529 subtree_name += &format!("{id}::{}", self.get_uid());
530 }
531
532 let new_prefix = format!("{subtree_name}/");
533
534 self.recursively_build_subtree(
535 id,
536 &subtree_name,
537 &new_prefix,
538 child_blackboard,
539 )
540 .await?
541 }
542 _ => self.build_leaf_node(&node_name, attributes, config).await?,
543 };
544
545 Some(node)
546 }
547 Event::End(_e) => None,
548 Event::Comment(content) => {
549 debug!("Comment - \"{content:?}\"");
550 None
551 },
552 e => {
553 debug!("Other - SHOULDN'T BE HERE");
554 debug!("{e:?}");
555
556 return Err(ParseError::InternalError(
557 "Didn't match one of the expected XML tag types.".to_string(),
558 ));
559 }
560 };
561
562 Ok(node)
563 })
564 }
565
566 pub fn register_bt_from_text(&mut self, xml: String) -> Result<(), ParseError> {
567 let mut reader = Reader::from_reader(Cursor::new(xml.as_bytes().to_vec()));
568 reader.trim_text(true);
569
570 let mut buf = Vec::new();
571
572 loop {
577 match reader.read_event_into(&mut buf)? {
579 Event::Decl(_) => buf.clear(),
581 Event::Start(e) => {
582 let name = String::from_utf8(e.name().0.into())?;
583 let attributes = e.attributes().to_map()?;
584
585 if name.as_str() != "root" {
586 buf.clear();
587 continue;
588 }
589
590 if let Some(tree_id) = attributes.get("main_tree_to_execute") {
591 info!("Found main tree ID: {tree_id}");
592 self.main_tree_id = Some(tree_id.clone());
593 }
594
595 buf.clear();
596 break;
597 }
598 _ => return Err(ParseError::MissingRoot),
599 }
600 }
601
602 loop {
604 let event = { reader.read_event_into(&mut buf)? };
605
606 match event {
607 Event::Start(e) => {
608 let name = String::from_utf8(e.name().0.into())?;
609 let attributes = e.attributes().to_map()?;
610
611 let end = e.to_end();
614 let end_name = end.name().as_ref().to_vec().clone();
615 let end_name = QName(end_name.as_slice());
616
617 if name.as_str() == "TreeNodesModel" {
620 reader.read_to_end_into(end_name, &mut buf)?;
621 } else {
622 if name.as_str() != "BehaviorTree" {
624 return Err(ParseError::ExpectedRoot(name));
625 }
626
627 if let Some(id) = attributes.get("ID") {
629 self.tree_roots.insert(id.clone(), reader.clone());
630 } else {
631 return Err(ParseError::MissingAttribute("Found BehaviorTree definition without ID. Cannot continue parsing.".to_string()));
632 }
633
634 reader.read_to_end_into(end_name, &mut buf)?;
635 }
636 }
637 Event::End(e) => {
638 let name = String::from_utf8(e.name().0.into())?;
639 if name != "root" {
640 return Err(ParseError::InternalError("A non-root end tag was found. This should not happen. Please report this.".to_string()));
641 } else {
642 break;
643 }
644 }
645 Event::Comment(_) => (),
646 x => {
647 return Err(ParseError::InternalError(
648 format!("Something bad has happened. Please report this. {x:?}")
649 ))
650 }
651 };
652 }
653
654 buf.clear();
655
656 Ok(())
657 }
658}
659
660impl Default for Factory {
661 fn default() -> Self {
662 Self::new()
663 }
664}
665
666fn builtin_nodes() -> HashMap<String, (NodeCategory, Arc<NodeCreateFnDyn>)> {
667 let mut node_map = HashMap::new();
668
669 let node = Arc::new(
671 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
672 let mut node = build_node_ptr!(config, "Sequence", nodes::control::SequenceNode);
673 node.data.children = children;
674 node
675 },
676 ) as Arc<NodeCreateFnDyn>;
677 node_map.insert(String::from("Sequence"), (NodeCategory::Control, node));
678
679 let node = Arc::new(
680 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
681 let mut node = build_node_ptr!(
682 config,
683 "ReactiveSequence",
684 nodes::control::ReactiveSequenceNode
685 );
686 node.data.children = children;
687 node
688 },
689 );
690 node_map.insert(
691 String::from("ReactiveSequence"),
692 (NodeCategory::Control, node),
693 );
694
695 let node = Arc::new(
696 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
697 let mut node = build_node_ptr!(
698 config,
699 "SequenceStar",
700 nodes::control::SequenceWithMemoryNode
701 );
702 node.data.children = children;
703 node
704 },
705 );
706 node_map.insert(String::from("SequenceStar"), (NodeCategory::Control, node));
707
708 let node = Arc::new(
709 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
710 let mut node = build_node_ptr!(config, "Parallel", nodes::control::ParallelNode);
711 node.data.children = children;
712 node
713 },
714 );
715 node_map.insert(String::from("Parallel"), (NodeCategory::Control, node));
716
717 let node = Arc::new(
718 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
719 let mut node = build_node_ptr!(config, "ParallelAll", nodes::control::ParallelAllNode);
720 node.data.children = children;
721 node
722 },
723 );
724 node_map.insert(String::from("ParallelAll"), (NodeCategory::Control, node));
725
726 let node = Arc::new(
727 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
728 let mut node = build_node_ptr!(config, "Fallback", nodes::control::FallbackNode);
729 node.data.children = children;
730 node
731 },
732 );
733 node_map.insert(String::from("Fallback"), (NodeCategory::Control, node));
734
735 let node = Arc::new(
736 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
737 let mut node = build_node_ptr!(
738 config,
739 "ReactiveFallback",
740 nodes::control::ReactiveFallbackNode
741 );
742 node.data.children = children;
743 node
744 },
745 );
746 node_map.insert(
747 String::from("ReactiveFallback"),
748 (NodeCategory::Control, node),
749 );
750
751 let node = Arc::new(
752 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
753 let mut node = build_node_ptr!(config, "IfThenElse", nodes::control::IfThenElseNode);
754 node.data.children = children;
755 node
756 },
757 );
758 node_map.insert(String::from("IfThenElse"), (NodeCategory::Control, node));
759
760 let node = Arc::new(
761 move |config: NodeConfig, children: Vec<TreeNode>| -> TreeNode {
762 let mut node = build_node_ptr!(config, "WhileDoElse", nodes::control::WhileDoElseNode);
763 node.data.children = children;
764 node
765 },
766 );
767 node_map.insert(String::from("WhileDoElse"), (NodeCategory::Control, node));
768
769 let node = Arc::new(
771 move |config: NodeConfig, mut children: Vec<TreeNode>| -> TreeNode {
772 let mut node =
773 build_node_ptr!(config, "ForceFailure", nodes::decorator::ForceFailureNode);
774 node.data.children = vec![children.remove(0)];
775 node
776 },
777 );
778 node_map.insert(
779 String::from("ForceFailure"),
780 (NodeCategory::Decorator, node),
781 );
782
783 let node = Arc::new(
784 move |config: NodeConfig, mut children: Vec<TreeNode>| -> TreeNode {
785 let mut node =
786 build_node_ptr!(config, "ForceSuccess", nodes::decorator::ForceSuccessNode);
787 node.data.children = vec![children.remove(0)];
788 node
789 },
790 );
791 node_map.insert(
792 String::from("ForceSuccess"),
793 (NodeCategory::Decorator, node),
794 );
795
796 let node = Arc::new(
797 move |config: NodeConfig, mut children: Vec<TreeNode>| -> TreeNode {
798 let mut node = build_node_ptr!(config, "Inverter", nodes::decorator::InverterNode);
799 node.data.children = vec![children.remove(0)];
800 node
801 },
802 );
803 node_map.insert(String::from("Inverter"), (NodeCategory::Decorator, node));
804
805 let node = Arc::new(
806 move |config: NodeConfig, mut children: Vec<TreeNode>| -> TreeNode {
807 let mut node = build_node_ptr!(
808 config,
809 "KeepRunningUntilFailure",
810 nodes::decorator::KeepRunningUntilFailureNode
811 );
812 node.data.children = vec![children.remove(0)];
813 node
814 },
815 );
816 node_map.insert(
817 String::from("KeepRunningUntilFailure"),
818 (NodeCategory::Decorator, node),
819 );
820
821 let node = Arc::new(
822 move |config: NodeConfig, mut children: Vec<TreeNode>| -> TreeNode {
823 let mut node = build_node_ptr!(config, "Repeat", nodes::decorator::RepeatNode);
824 node.data.children = vec![children.remove(0)];
825 node
826 },
827 );
828 node_map.insert(String::from("Repeat"), (NodeCategory::Decorator, node));
829
830 let node = Arc::new(
831 move |config: NodeConfig, mut children: Vec<TreeNode>| -> TreeNode {
832 let mut node = build_node_ptr!(config, "Retry", nodes::decorator::RetryNode);
833 node.data.children = vec![children.remove(0)];
834 node
835 },
836 );
837 node_map.insert(String::from("Retry"), (NodeCategory::Decorator, node));
838
839 let node = Arc::new(
840 move |config: NodeConfig, mut children: Vec<TreeNode>| -> TreeNode {
841 let mut node = build_node_ptr!(config, "RunOnce", nodes::decorator::RunOnceNode);
842 node.data.children = vec![children.remove(0)];
843 node
844 },
845 );
846 node_map.insert(String::from("RunOnce"), (NodeCategory::Decorator, node));
847
848 node_map
849}