Skip to main content

behaviortree_rs/nodes/control/
if_then_else.rs

1use behaviortree_rs_derive::bt_node;
2use log::warn;
3
4use crate::{
5    basic_types::NodeStatus,
6    nodes::{NodeError, NodeResult},
7};
8
9/// IfThenElseNode must have exactly 2 or 3 children. This node is NOT reactive.
10///
11/// The first child is the "statement" of the if.
12///
13/// If that return SUCCESS, then the second child is executed.
14///
15/// Instead, if it returned FAILURE, the third child is executed.
16///
17/// If you have only 2 children, this node will return FAILURE whenever the
18/// statement returns FAILURE.
19///
20/// This is equivalent to add AlwaysFailure as 3rd child.
21#[bt_node(ControlNode)]
22pub struct IfThenElseNode {
23    #[bt(default = "0")]
24    child_idx: usize,
25}
26
27#[bt_node(ControlNode)]
28impl IfThenElseNode {
29    async fn tick(&mut self) -> NodeResult {
30        let children_count = node_.children.len();
31        // Node should only have 2 or 3 children
32        if !(2..=3).contains(&children_count) {
33            return Err(NodeError::NodeStructureError(
34                "IfThenElseNode must have either 2 or 3 children.".to_string(),
35            ));
36        }
37
38        node_.status = NodeStatus::Running;
39
40        if self.child_idx == 0 {
41            let status = node_.children[0].execute_tick().await?;
42            match status {
43                NodeStatus::Running => return Ok(NodeStatus::Running),
44                NodeStatus::Success => self.child_idx += 1,
45                NodeStatus::Failure => {
46                    if children_count == 3 {
47                        self.child_idx = 2;
48                    } else {
49                        return Ok(NodeStatus::Failure);
50                    }
51                }
52                NodeStatus::Idle => {
53                    return Err(NodeError::StatusError(
54                        "Node name here".to_string(),
55                        "Idle".to_string(),
56                    ))
57                }
58                _ => warn!("Condition node of IfThenElseNode returned Skipped"),
59            }
60        }
61
62        if self.child_idx > 0 {
63            let status = node_.children[self.child_idx].execute_tick().await?;
64            match status {
65                NodeStatus::Running => return Ok(NodeStatus::Running),
66                status => {
67                    node_.reset_children().await;
68                    self.child_idx = 0;
69                    return Ok(status);
70                }
71            }
72        }
73
74        Err(NodeError::NodeStructureError(
75            "Something unexpected happened in IfThenElseNode".to_string(),
76        ))
77    }
78
79    async fn halt(&mut self) {
80        self.child_idx = 0;
81        node_.reset_children().await;
82    }
83}