behaviortree_rs/nodes/
mod.rs

1use std::{
2    any::{Any, TypeId},
3    collections::HashMap,
4    sync::Arc,
5};
6
7use futures::future::BoxFuture;
8use thiserror::Error;
9
10use crate::{
11    basic_types::{
12        get_remapped_key, FromString, NodeCategory, ParseStr, PortDirection, PortValue,
13        PortsRemapping, TreeNodeManifest,
14    },
15    blackboard::BlackboardString,
16    tree::ParseError,
17    Blackboard,
18};
19
20pub use crate::basic_types::{NodeStatus, PortsList};
21
22pub mod action;
23pub mod control;
24pub mod decorator;
25
26pub type NodeResult<Output = NodeStatus> = Result<Output, NodeError>;
27type TickFn = for<'a> fn(
28    &'a mut TreeNodeData,
29    &'a mut Box<dyn Any + Send + Sync>,
30) -> BoxFuture<'a, Result<NodeStatus, NodeError>>;
31type HaltFn = for<'a> fn(&'a mut TreeNodeData, &'a mut Box<dyn Any + Send + Sync>) -> BoxFuture<'a, ()>;
32type PortsFn = fn() -> PortsList;
33
34#[derive(Clone, Copy, Debug)]
35pub enum NodeType {
36    Control,
37    Decorator,
38    StatefulAction,
39    SyncAction,
40}
41
42#[derive(Debug)]
43pub struct TreeNodeData {
44    pub name: String,
45    pub type_str: String,
46    pub node_type: NodeType,
47    pub node_category: NodeCategory,
48    pub config: NodeConfig,
49    pub status: NodeStatus,
50    /// Vector of child nodes
51    pub children: Vec<TreeNode>,
52    pub ports_fn: PortsFn,
53}
54
55#[derive(Debug)]
56pub struct TreeNode {
57    pub data: TreeNodeData,
58    pub context: Box<dyn Any + Send + Sync>,
59    /// Function pointer to tick
60    pub tick_fn: TickFn,
61    /// Function pointer to on_start function (if StatefulActionNode)
62    /// Otherwise points to tick_fn
63    pub start_fn: TickFn,
64    /// Function pointer to halt
65    pub halt_fn: HaltFn,
66}
67
68impl TreeNode {
69    /// Returns the current node's status
70    pub fn status(&self) -> NodeStatus {
71        self.data.status
72    }
73
74    /// Resets the status back to `NodeStatus::Idle`
75    pub fn reset_status(&mut self) {
76        self.data.status = NodeStatus::Idle;
77    }
78
79    /// Update the node's status
80    pub fn set_status(&mut self, status: NodeStatus) {
81        self.data.status = status;
82    }
83
84    /// Internal-only, calls the action-type-specific tick
85    async fn action_tick(&mut self) -> NodeResult {
86        match self.data.node_type {
87            NodeType::StatefulAction => {
88                let prev_status = self.data.status;
89
90                let new_status = match prev_status {
91                    NodeStatus::Idle => {
92                        ::log::debug!("[behaviortree_rs]: {}::on_start()", &self.data.config.path);
93                        // let mut wrapper = ArgWrapper::new(&mut self.data, &mut self.context);
94                        let new_status = (self.start_fn)(&mut self.data, &mut self.context).await?;
95                        // drop(wrapper);
96                        if matches!(new_status, NodeStatus::Idle) {
97                            return Err(NodeError::StatusError(
98                                format!("{}::on_start()", self.data.config.path),
99                                "Idle".to_string(),
100                            ));
101                        }
102                        new_status
103                    }
104                    NodeStatus::Running => {
105                        ::log::debug!(
106                            "[behaviortree_rs]: {}::on_running()",
107                            &self.data.config.path
108                        );
109                        let new_status = (self.tick_fn)(&mut self.data, &mut self.context).await?;
110                        if matches!(new_status, NodeStatus::Idle) {
111                            return Err(NodeError::StatusError(
112                                format!("{}::on_running()", self.data.config.path),
113                                "Idle".to_string(),
114                            ));
115                        }
116                        new_status
117                    }
118                    prev_status => prev_status,
119                };
120
121                self.set_status(new_status);
122
123                Ok(new_status)
124            }
125            NodeType::SyncAction => {
126                match (self.tick_fn)(&mut self.data, &mut self.context).await? {
127                    status @ (NodeStatus::Running | NodeStatus::Idle) => {
128                        Err(::behaviortree_rs::nodes::NodeError::StatusError(
129                            self.data.config.path.clone(),
130                            status.to_string(),
131                        ))
132                    }
133                    status => Ok(status),
134                }
135            }
136            _ => panic!(
137                "This should not be possible, action_tick() was called for a non-action node"
138            ),
139        }
140    }
141
142    /// Tick the node
143    pub async fn execute_tick(&mut self) -> NodeResult {
144        match self.data.node_type {
145            NodeType::Control | NodeType::Decorator => {
146                (self.tick_fn)(&mut self.data, &mut self.context).await
147            }
148            NodeType::StatefulAction | NodeType::SyncAction => self.action_tick().await,
149        }
150    }
151
152    /// Halt the node
153    pub async fn halt(&mut self) {
154        (self.halt_fn)(&mut self.data, &mut self.context).await;
155    }
156
157    /// Get the name of the node
158    pub fn name(&self) -> &str {
159        &self.data.name
160    }
161
162    /// Get a mutable reference to the `NodeConfig`
163    pub fn config_mut(&mut self) -> &mut NodeConfig {
164        &mut self.data.config
165    }
166
167    /// Get a reference to the `NodeConfig`
168    pub fn config(&self) -> &NodeConfig {
169        &self.data.config
170    }
171
172    /// Get the node's `NodeType`, which is only:
173    /// * `NodeType::Control`
174    /// * `NodeType::Decorator`
175    /// * `NodeType::SyncAction`
176    /// * `NodeType::StatefulAction`
177    pub fn node_type(&self) -> NodeType {
178        self.data.node_type
179    }
180
181    /// Get the node's `NodeCategory`, which is more general than `NodeType`
182    pub fn node_category(&self) -> NodeCategory {
183        self.data.node_category
184    }
185
186    /// Call the node's `ports()` function if it has one, returning the
187    /// `PortsList` object
188    pub fn provided_ports(&self) -> PortsList {
189        (self.data.ports_fn)()
190    }
191
192    /// Return an iterator over the children. Returns `None` if this node
193    /// has no children (i.e. an `Action` node)
194    pub fn children(&self) -> Option<impl Iterator<Item = &TreeNode>> {
195        if self.data.children.is_empty() {
196            None
197        } else {
198            Some(self.data.children.iter())
199        }
200    }
201
202    /// Return a mutable iterator over the children. Returns `None` if this node
203    /// has no children (i.e. an `Action` node)
204    pub fn children_mut(&mut self) -> Option<impl Iterator<Item = &mut TreeNode>> {
205        if self.data.children.is_empty() {
206            None
207        } else {
208            Some(self.data.children.iter_mut())
209        }
210    }
211}
212
213impl TreeNodeData {
214    /// Halt children from this index to the end.
215    ///
216    /// # Errors
217    ///
218    /// Returns `NodeError::IndexError` if `start` is out of bounds.
219    pub async fn halt_children(&mut self, start: usize) -> NodeResult<()> {
220        if start >= self.children.len() {
221            return Err(NodeError::IndexError);
222        }
223
224        let end = self.children.len();
225
226        for i in start..end {
227            self.halt_child_idx(i).await?;
228        }
229
230        Ok(())
231    }
232
233    /// Halts and resets all children
234    pub async fn reset_children(&mut self) {
235        self.halt_children(0)
236            .await
237            .expect("reset_children failed, shouldn't be possible. Report this")
238    }
239
240    /// Halt child at the `index`. Not to be confused with `halt_child()`, which is
241    /// a helper that calls `halt_child_idx(0)`, primarily used for `Decorator` nodes.
242    pub async fn halt_child_idx(&mut self, index: usize) -> NodeResult<()> {
243        let child = self.children.get_mut(index).ok_or(NodeError::IndexError)?;
244        if child.status() == ::behaviortree_rs::nodes::NodeStatus::Running {
245            child.halt().await;
246        }
247        child.reset_status();
248        Ok(())
249    }
250
251    /// Sets the status of this node
252    pub fn set_status(&mut self, status: NodeStatus) {
253        self.status = status;
254    }
255
256    /// Calls `halt_child_idx(0)`. This should only be used in
257    /// `Decorator` nodes
258    pub async fn halt_child(&mut self) {
259        self.reset_child().await
260    }
261
262    /// Halts and resets the first child. This should only be used in
263    /// `Decorator` nodes
264    pub async fn reset_child(&mut self) {
265        if let Some(child) = self.children.get_mut(0) {
266            if matches!(child.status(), NodeStatus::Running) {
267                child.halt().await;
268            }
269
270            child.reset_status();
271        }
272    }
273
274    /// Gets a mutable reference to the first child. Helper for
275    /// `Decorator` nodes to get their child.
276    pub fn child(&mut self) -> Option<&mut TreeNode> {
277        self.children.get_mut(0)
278    }
279}
280
281// =============================
282// Enum Definitions
283// =============================
284
285#[derive(Debug, Error)]
286pub enum NodeError {
287    #[error(
288        "Child node of [{0}] returned invalid status [NodeStatus::{1}] when it is not allowed"
289    )]
290    StatusError(String, String),
291    #[error("Out of bounds index")]
292    IndexError,
293    #[error("Couldn't find port [{0}]")]
294    PortError(String),
295    #[error("Couldn't parse port [{0}] value into specified type [{1}]")]
296    /// # Arguments
297    /// * Port name
298    /// * Expected type
299    PortValueParseError(String, String),
300    #[error("Couldn't find entry in blackboard [{0}]")]
301    BlackboardError(String),
302    #[error("{0}")]
303    UserError(#[from] anyhow::Error),
304    #[error("{0}")]
305    NodeStructureError(String),
306    #[error("Decorator node does not have a child.")]
307    ChildMissing,
308    #[error("Blackboard lock was poisoned.")]
309    LockPoisoned,
310    #[error("A tick method was called that should have been unreachable. Please report this.")]
311    UnreachableTick,
312}
313
314/// TODO: Not currently used
315#[derive(Clone, Debug)]
316pub enum PreCond {
317    FailureIf,
318    SuccessIf,
319    SkipIf,
320    WhileTrue,
321    Count,
322}
323
324/// TODO: Not currently used
325#[derive(Clone, Debug)]
326pub enum PostCond {
327    OnHalted,
328    OnFailure,
329    OnSuccess,
330    Always,
331    Count,
332}
333
334#[derive(Clone, Debug)]
335pub enum NodeRuntime {
336    Async,
337    Sync,
338    All,
339}
340
341// =========================================
342// Struct Definitions and Implementations
343// =========================================
344
345/// Contains all common configuration that all types of nodes use.
346#[derive(Clone, Debug)]
347pub struct NodeConfig {
348    pub blackboard: Blackboard,
349    pub input_ports: PortsRemapping,
350    pub output_ports: PortsRemapping,
351    pub manifest: Option<Arc<TreeNodeManifest>>,
352    pub uid: u16,
353    /// TODO: doesn't show actual path yet
354    pub path: String,
355    /// TODO: not used
356    _pre_conditions: HashMap<PreCond, String>,
357    /// TODO: not used
358    _post_conditions: HashMap<PostCond, String>,
359}
360
361impl NodeConfig {
362    pub fn new(blackboard: Blackboard) -> NodeConfig {
363        Self {
364            blackboard,
365            input_ports: HashMap::new(),
366            output_ports: HashMap::new(),
367            manifest: None,
368            uid: 1,
369            path: String::from("TODO"),
370            _pre_conditions: HashMap::new(),
371            _post_conditions: HashMap::new(),
372        }
373    }
374
375    /// Returns a reference to the blackboard.
376    pub fn blackboard(&self) -> &Blackboard {
377        &self.blackboard
378    }
379
380    /// Adds a port to the config based on the direction. Used during XML parsing.
381    pub fn add_port(&mut self, direction: PortDirection, name: String, value: String) {
382        match direction {
383            PortDirection::Input => {
384                self.input_ports.insert(name, value);
385            }
386            PortDirection::Output => {
387                self.output_ports.insert(name, value);
388            }
389            _ => {}
390        };
391    }
392
393    pub fn has_port(&self, direction: &PortDirection, name: &String) -> bool {
394        match direction {
395            PortDirection::Input => self.input_ports.contains_key(name),
396            PortDirection::Output => self.output_ports.contains_key(name),
397            _ => false,
398        }
399    }
400
401    /// Returns a pointer to the `TreeNodeManifest` for this node.
402    /// Only used during XML parsing.
403    pub fn manifest(&self) -> Result<Arc<TreeNodeManifest>, ParseError> {
404        match self.manifest.as_ref() {
405            Some(manifest) => Ok(Arc::clone(manifest)),
406            None => Err(ParseError::InternalError(
407                "Missing manifest. This shouldn't happen; please report this.".to_string(),
408            )),
409        }
410    }
411
412    /// Replace the inner manifest.
413    pub fn set_manifest(&mut self, manifest: Arc<TreeNodeManifest>) {
414        let _ = self.manifest.insert(manifest);
415    }
416
417    /// Returns the value of the input port at the `port` key as a `Result<T, NodeError>`.
418    /// The value is `Err` in the following situations:
419    /// - The port wasn't found at that key
420    /// - `T` doesn't match the type of the stored value
421    /// - If a default value is needed (value is empty), couldn't parse default value
422    /// - If a remapped key (e.g. a port value of `"{foo}"` references the blackboard
423    /// key `"foo"`), blackboard entry wasn't found or couldn't be read as `T`
424    /// - If port value is a string, couldn't convert it to `T` using `parse_str()`.
425    pub fn get_input<T>(&mut self, port: &str) -> Result<T, NodeError>
426    where
427        T: FromString + Clone + Send + 'static,
428    {
429        match self.input_ports.get(port) {
430            Some(val) => {
431                // Check if default is needed
432                if val.is_empty() {
433                    match self.manifest() {
434                        Ok(manifest) => {
435                            let port_info = manifest.ports.get(port).unwrap();
436                            match port_info.default_value() {
437                                Some(default) => match default.parse_str() {
438                                    Ok(value) => Ok(value),
439                                    Err(_) => Err(NodeError::PortError(String::from(port))),
440                                },
441                                None => Err(NodeError::PortError(String::from(port))),
442                            }
443                        }
444                        Err(_) => Err(NodeError::PortError(String::from(port))),
445                    }
446                } else {
447                    match get_remapped_key(port, val) {
448                        // Value is a Blackboard pointer
449                        Some(key) => match self.blackboard.get::<T>(&key) {
450                            Some(val) => Ok(val),
451                            None => Err(NodeError::BlackboardError(key)),
452                        },
453                        // Value is just a normal string
454                        None => match <T as FromString>::from_string(val) {
455                            Ok(val) => Ok(val),
456                            Err(_) => Err(NodeError::PortValueParseError(
457                                String::from(port),
458                                format!("{:?}", TypeId::of::<T>()),
459                            )),
460                        },
461                    }
462                }
463            }
464            // Port not found
465            None => Err(NodeError::PortError(String::from(port))),
466        }
467    }
468
469    /// Sets `value` into the blackboard. The key is based on the value provided
470    /// to the port at `port`.
471    ///
472    /// # Examples
473    ///
474    /// - Port value: `"="`: uses the port name as the blackboard key
475    /// - `"foo"` uses `"foo"` as the blackboard key
476    /// - `"{foo}"` uses `"foo"` as the blackboard key
477    pub async fn set_output<T>(&mut self, port: &str, value: T) -> Result<(), NodeError>
478    where
479        T: Clone + Send + 'static,
480    {
481        match self.output_ports.get(port) {
482            Some(port_value) => {
483                let blackboard_key = match port_value.as_str() {
484                    "=" => port.to_string(),
485                    value => match value.is_bb_pointer() {
486                        true => value.strip_bb_pointer().unwrap(),
487                        false => value.to_string(),
488                    },
489                };
490
491                self.blackboard.set(blackboard_key, value);
492
493                Ok(())
494            }
495            None => Err(NodeError::PortError(port.to_string())),
496        }
497    }
498
499    /// Sync version of `set_output<T>`
500    ///
501    /// Sets `value` into the blackboard. The key is based on the value provided
502    /// to the port at `port`.
503    ///
504    /// # Examples
505    ///
506    /// - Port value: `"="`: uses the port name as the blackboard key
507    /// - `"foo"` uses `"foo"` as the blackboard key
508    /// - `"{foo}"` uses `"foo"` as the blackboard key
509    pub async fn set_output_sync<T>(&mut self, port: &str, value: T) -> Result<(), NodeError>
510    where
511        T: Clone + Send + 'static,
512    {
513        futures::executor::block_on(self.set_output(port, value))
514    }
515}
516
517impl Clone for Box<dyn PortValue> {
518    fn clone(&self) -> Box<dyn PortValue> {
519        self.clone_port()
520    }
521}