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 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 pub tick_fn: TickFn,
61 pub start_fn: TickFn,
64 pub halt_fn: HaltFn,
66}
67
68impl TreeNode {
69 pub fn status(&self) -> NodeStatus {
71 self.data.status
72 }
73
74 pub fn reset_status(&mut self) {
76 self.data.status = NodeStatus::Idle;
77 }
78
79 pub fn set_status(&mut self, status: NodeStatus) {
81 self.data.status = status;
82 }
83
84 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 new_status = (self.start_fn)(&mut self.data, &mut self.context).await?;
95 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 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 pub async fn halt(&mut self) {
154 (self.halt_fn)(&mut self.data, &mut self.context).await;
155 }
156
157 pub fn name(&self) -> &str {
159 &self.data.name
160 }
161
162 pub fn config_mut(&mut self) -> &mut NodeConfig {
164 &mut self.data.config
165 }
166
167 pub fn config(&self) -> &NodeConfig {
169 &self.data.config
170 }
171
172 pub fn node_type(&self) -> NodeType {
178 self.data.node_type
179 }
180
181 pub fn node_category(&self) -> NodeCategory {
183 self.data.node_category
184 }
185
186 pub fn provided_ports(&self) -> PortsList {
189 (self.data.ports_fn)()
190 }
191
192 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 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 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 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 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 pub fn set_status(&mut self, status: NodeStatus) {
253 self.status = status;
254 }
255
256 pub async fn halt_child(&mut self) {
259 self.reset_child().await
260 }
261
262 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 pub fn child(&mut self) -> Option<&mut TreeNode> {
277 self.children.get_mut(0)
278 }
279}
280
281#[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 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#[derive(Clone, Debug)]
316pub enum PreCond {
317 FailureIf,
318 SuccessIf,
319 SkipIf,
320 WhileTrue,
321 Count,
322}
323
324#[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#[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 pub path: String,
355 _pre_conditions: HashMap<PreCond, String>,
357 _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 pub fn blackboard(&self) -> &Blackboard {
377 &self.blackboard
378 }
379
380 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 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 pub fn set_manifest(&mut self, manifest: Arc<TreeNodeManifest>) {
414 let _ = self.manifest.insert(manifest);
415 }
416
417 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 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 Some(key) => match self.blackboard.get::<T>(&key) {
450 Some(val) => Ok(val),
451 None => Err(NodeError::BlackboardError(key)),
452 },
453 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 None => Err(NodeError::PortError(String::from(port))),
466 }
467 }
468
469 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 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}