behavior_tree/
testing.rs

1//! Nodes in this module are intended for testing. While they're being
2//! used to internally test this library they could also prove to be useful
3//! for testing custom node types in user code.
4use std::{cell::RefCell, rc::Rc};
5
6use crate::prelude::*;
7
8/// Node that will panic upon being dropped if it hasn't ticked
9/// at least once.
10///
11/// Inspired by https://github.com/danieleades/aspen/blob/master/src/std_nodes/testing.rs
12#[derive(Default)]
13pub struct YesTick {
14    pub ticked: bool,
15}
16
17impl YesTick {
18    pub fn action<T>() -> Node<T> {
19        Node::stateful_action("yes", Box::new(YesTick::default()))
20    }
21}
22
23impl<T> StatefulAction<T> for YesTick {
24    fn tick(&mut self, _data: &mut T) -> Status {
25        self.ticked = true;
26        Status::Success
27    }
28
29    fn reset(&mut self) {
30        // no-op
31    }
32}
33
34impl Drop for YesTick {
35    fn drop(&mut self) {
36        assert!(self.ticked, "YesTick dropped without being ticked");
37    }
38}
39
40/// Node that will panic when it ticks.
41///
42/// Inspired by https://github.com/danieleades/aspen/blob/master/src/std_nodes/testing.rs
43#[derive(Default)]
44pub struct NoTick;
45
46impl NoTick {
47    pub fn action<T>() -> Node<T> {
48        Node::stateful_action("no", Box::new(NoTick::default()))
49    }
50}
51
52impl<T> StatefulAction<T> for NoTick {
53    fn tick(&mut self, _data: &mut T) -> Status {
54        panic!("NoTick node should never be ticked");
55    }
56
57    fn reset(&mut self) {
58        // no-op to allow testing reset on bigger trees
59    }
60}
61
62/// Node that always runs.
63pub struct AlwaysRunning;
64
65impl AlwaysRunning {
66    pub fn action<T>() -> Node<T> {
67        Node::action("running", |_| Status::Running)
68    }
69}
70
71/// Node that always returns a given status when ticked, but exposes the status
72/// to be modified from the outside.
73pub struct ConstAction {
74    pub return_status: Rc<RefCell<Status>>,
75}
76
77impl ConstAction {
78    pub fn new(status: Status) -> Self {
79        Self {
80            return_status: Rc::new(RefCell::new(status)),
81        }
82    }
83}
84
85impl<T> StatefulAction<T> for ConstAction {
86    fn tick(&mut self, _data: &mut T) -> Status {
87        *self.return_status.borrow()
88    }
89
90    fn reset(&mut self) {}
91}
92// impl<T> StatefulAction<T> for AlwaysRunning {
93//     fn tick(&mut self, _data: &mut T) -> Status {
94//         Status::Running
95//     }
96//
97//     fn reset(&mut self) {
98//         panic!("AlwaysRunning should never be reset");
99//     }
100// }
101
102#[derive(Default)]
103pub struct Counter {
104    pub value: Rc<RefCell<i32>>,
105    resettable: bool,
106}
107
108impl Counter {
109    pub fn action<T>(resettable: bool) -> (Rc<RefCell<Node<T>>>, Rc<RefCell<i32>>) {
110        let value = Rc::new(RefCell::new(0));
111        (
112            Rc::new(RefCell::new(Node::stateful_action(
113                "counter",
114                Box::new(Self {
115                    value: value.clone(),
116                    resettable,
117                }),
118            ))),
119            value,
120        )
121    }
122}
123
124impl<T> StatefulAction<T> for Counter {
125    fn tick(&mut self, _data: &mut T) -> Status {
126        *self.value.borrow_mut() += 1;
127        Status::Success
128    }
129
130    fn reset(&mut self) {
131        if self.resettable {
132            *self.value.borrow_mut() = 0;
133        }
134    }
135}