forester_rs/runtime/
context.rs

1use crate::runtime::action::Tick;
2use crate::runtime::args::{RtArgs, RtValue};
3use crate::runtime::blackboard::{BBRef, BlackBoard};
4use crate::runtime::env::RtEnvRef;
5use crate::runtime::forester::flow::REASON;
6use crate::runtime::rtree::rnode::RNodeId;
7use crate::runtime::trimmer::{TrimmingQueue, TrimmingQueueRef};
8use crate::runtime::{RtOk, RtResult, RuntimeError, TickResult};
9use crate::tracer::Event::NewState;
10use crate::tracer::{Event, Tracer};
11use std::collections::{HashMap, VecDeque};
12use std::fmt::{Display, Formatter};
13use std::sync::Arc;
14use std::sync::Mutex;
15
16use super::rtree::rnode::RNode;
17
18pub type Timestamp = usize;
19pub type TracerRef = Arc<Mutex<Tracer>>;
20
21/// The remote context ref for the remote actions.
22/// Since, the context is supposed to help to send
23/// the information to the remote action it does not have the actual copy of the blackboard and tracer.
24///
25/// #Note
26/// The port defines the port of the http server
27/// that is used to send the information to the remote action(current http server).
28pub struct TreeRemoteContextRef {
29    pub curr_ts: Timestamp,
30    pub port: u16,
31    pub env: RtEnvRef,
32}
33
34impl TreeRemoteContextRef {
35    pub fn new(curr_ts: Timestamp, port: u16, env: RtEnvRef) -> Self {
36        Self { curr_ts, port, env }
37    }
38}
39
40/// The context ref for the tree to help the actions to implement the logic.
41/// The context ref is supposed to be used by the actions
42/// to get the information about the current state of the tree.
43#[derive(Clone)]
44pub struct TreeContextRef {
45    bb: BBRef,
46    tracer: TracerRef,
47    curr_ts: Timestamp,
48    _trimmer: TrimmingQueueRef,
49    env: RtEnvRef,
50}
51
52impl From<&mut TreeContext> for TreeContextRef {
53    fn from(value: &mut TreeContext) -> Self {
54        TreeContextRef::from_ctx(value, Default::default())
55    }
56}
57
58impl TreeContextRef {
59    pub fn from_ctx(ctx: &TreeContext, trimmer: Arc<Mutex<TrimmingQueue>>) -> Self {
60        TreeContextRef::new(
61            ctx.bb.clone(),
62            ctx.tracer.clone(),
63            ctx.curr_ts,
64            trimmer,
65            ctx.rt_env.clone(),
66        )
67    }
68    /// A pointer to tracer struct.
69    pub fn tracer(&self) -> TracerRef {
70        self.tracer.clone()
71    }
72    /// create a trace message
73    pub fn trace(&self, ev: String) -> RtOk {
74        self.tracer.lock()?.trace(self.curr_ts, Event::Custom(ev))
75    }
76    pub fn trace_ev(&self, ev: Event) -> RtOk {
77        self.tracer.lock()?.trace(self.curr_ts, ev)
78    }
79    /// A pointer to bb struct.
80    pub fn bb(&self) -> BBRef {
81        self.bb.clone()
82    }
83
84    pub fn env(&self) -> RtEnvRef {
85        self.env.clone()
86    }
87    /// A current tick.
88    pub fn current_tick(&self) -> Timestamp {
89        self.curr_ts
90    }
91    pub fn new(
92        bb: Arc<Mutex<BlackBoard>>,
93        tracer: Arc<Mutex<Tracer>>,
94        curr_ts: Timestamp,
95        _trimmer: Arc<Mutex<TrimmingQueue>>,
96        env: RtEnvRef,
97    ) -> Self {
98        Self {
99            bb,
100            tracer,
101            curr_ts,
102            _trimmer,
103            env,
104        }
105    }
106}
107
108/// The runtime context.
109/// It is used to store the information about the current state of the tree.
110pub struct TreeContext {
111    /// Storage
112    bb: BBRef,
113    /// Tracer to save the tracing information.
114    tracer: TracerRef,
115
116    /// The call stack
117    stack: VecDeque<RNodeId>,
118
119    /// The latest state for the node
120    state: HashMap<RNodeId, RNodeState>,
121
122    /// The latest tick for the node
123    ts_map: HashMap<RNodeId, Timestamp>,
124
125    /// Current tick
126    curr_ts: Timestamp,
127
128    /// the max amount of ticks
129    tick_limit: Timestamp,
130
131    /// The runtime environment
132    rt_env: RtEnvRef,
133}
134
135impl TreeContext {
136    pub fn state(&self) -> &HashMap<RNodeId, RNodeState> {
137        &self.state
138    }
139
140    /// A pointer to bb struct.
141    pub fn bb(&mut self) -> Arc<Mutex<BlackBoard>> {
142        self.bb.clone()
143    }
144    pub fn tracer(&mut self) -> Arc<Mutex<Tracer>> {
145        self.tracer.clone()
146    }
147    pub fn new(bb: BBRef, tracer: TracerRef, tick_limit: Timestamp, rt_env: RtEnvRef) -> Self {
148        Self {
149            bb,
150            tracer,
151            stack: Default::default(),
152            state: Default::default(),
153            ts_map: Default::default(),
154            curr_ts: 1,
155            tick_limit,
156            rt_env,
157        }
158    }
159}
160
161impl TreeContext {
162    /// Adds a custom record to the tracer.
163    /// Preferably to use `Event::Custom(..)` for that
164    pub fn trace(&mut self, ev: Event) -> RtOk {
165        self.tracer.lock()?.trace(self.curr_ts, ev)
166    }
167
168    pub(crate) fn next_tick(&mut self) -> RtOk {
169        self.curr_ts += 1;
170        self.trace(Event::NextTick)?;
171        debug!(target:"root", "tick up the flow to:{}",self.curr_ts);
172        if self.tick_limit != 0 && self.curr_ts >= self.tick_limit {
173            Err(RuntimeError::Stopped(format!(
174                "the limit of ticks are exceeded on {}",
175                self.curr_ts
176            )))
177        } else {
178            Ok(())
179        }
180    }
181
182    pub(crate) fn root_state(&self, root: RNodeId) -> Tick {
183        self.state
184            .get(&root)
185            .ok_or(RuntimeError::uex(format!("the root node {root} is absent")))
186            .and_then(RNodeState::to_tick_result)
187    }
188
189    pub(crate) fn is_curr_ts(&self, id: &RNodeId) -> bool {
190        self.ts_map
191            .get(id)
192            .map(|e| *e == self.curr_ts)
193            .unwrap_or(false)
194    }
195    pub fn curr_ts(&self) -> Timestamp {
196        self.curr_ts
197    }
198
199    pub(crate) fn push(&mut self, id: RNodeId) -> RtOk {
200        self.tracer.lock()?.right();
201        self.stack.push_back(id);
202        Ok(())
203    }
204    pub(crate) fn pop(&mut self) -> RtResult<Option<RNodeId>> {
205        let pop_node = self.stack.pop_back();
206        self.tracer.lock()?.left();
207        Ok(pop_node)
208    }
209    pub(crate) fn peek(&self) -> RtResult<Option<&RNodeId>> {
210        if self.stack.is_empty() {
211            Ok(None)
212        } else {
213            Ok(self.stack.back())
214        }
215    }
216
217    pub(crate) fn force_to_halting_state(&mut self, id: RNodeId) -> RtResult<Option<RNodeState>> {
218        self.ts_map.insert(id, self.curr_ts);
219        let new_state = RNodeState::Halting(self.state_last_set(&id).args());
220
221        // Trace the state change with an extra indent
222        self.tracer.lock()?.right();
223        self.trace(NewState(id, new_state.clone()))?;
224        self.tracer.lock()?.left();
225
226        Ok(self.state.insert(id, new_state))
227    }
228    pub(crate) fn new_state(
229        &mut self,
230        id: RNodeId,
231        state: RNodeState,
232    ) -> RtResult<Option<RNodeState>> {
233        self.ts_map.insert(id, self.curr_ts);
234        self.trace(NewState(id, state.clone()))?;
235        Ok(self.state.insert(id, state))
236    }
237    pub(crate) fn state_last_set(&self, id: &RNodeId) -> RNodeState {
238        self.state
239            .get(id)
240            .cloned()
241            .unwrap_or(RNodeState::Ready(RtArgs::default()))
242    }
243    pub(crate) fn state_in_ts(&self, id: &RNodeId) -> RNodeState {
244        let actual_state = self.state_last_set(id);
245        if self.is_curr_ts(&id) {
246            actual_state
247        } else {
248            RNodeState::Ready(actual_state.args())
249        }
250    }
251}
252
253/// The current state of the node.
254/// RtArgs here represent the arguments that are passed between ticks and used as meta info
255#[derive(Clone, Debug)]
256pub enum RNodeState {
257    Ready(RtArgs),
258    Running(RtArgs),
259    Success(RtArgs),
260    Failure(RtArgs),
261    Halting(RtArgs),
262}
263
264impl Display for RNodeState {
265    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
266        match self {
267            RNodeState::Ready(args) => {
268                f.write_str(format!("Ready({})", args).as_str())?;
269            }
270            RNodeState::Running(args) => {
271                f.write_str(format!("Running({})", args).as_str())?;
272            }
273            RNodeState::Success(args) => {
274                f.write_str(format!("Success({})", args).as_str())?;
275            }
276            RNodeState::Failure(args) => {
277                f.write_str(format!("Failure({})", args).as_str())?;
278            }
279            RNodeState::Halting(args) => {
280                f.write_str(format!("Halting({})", args).as_str())?;
281            }
282        }
283        Ok(())
284    }
285}
286
287impl RNodeState {
288    pub fn from(tick_args: RtArgs, res: TickResult) -> RNodeState {
289        match res {
290            TickResult::Success => RNodeState::Success(tick_args),
291            TickResult::Failure(v) => RNodeState::Failure(tick_args.with(REASON, RtValue::str(v))),
292            TickResult::Running => RNodeState::Running(tick_args),
293        }
294    }
295    pub fn to_tick_result(&self) -> RtResult<TickResult> {
296        match &self {
297            RNodeState::Ready(_) => Err(RuntimeError::uex(
298                "the ready is the unexpected state for ".to_string(),
299            )),
300            RNodeState::Running(_) | RNodeState::Halting(_) => Ok(TickResult::running()),
301            RNodeState::Success(_) => Ok(TickResult::success()),
302            RNodeState::Failure(args) => {
303                let reason = args
304                    .find(REASON.to_string())
305                    .and_then(RtValue::as_string)
306                    .unwrap_or_default();
307
308                Ok(TickResult::Failure(reason))
309            }
310        }
311    }
312
313    pub fn is_running(&self) -> bool {
314        matches!(self, RNodeState::Running { .. })
315    }
316    pub fn is_ready(&self) -> bool {
317        matches!(self, RNodeState::Ready(_))
318    }
319    pub fn is_finished(&self) -> bool {
320        matches!(self, RNodeState::Success(_) | RNodeState::Failure(_))
321    }
322
323    pub fn args(&self) -> RtArgs {
324        match self {
325            RNodeState::Ready(tick_args)
326            | RNodeState::Running(tick_args)
327            | RNodeState::Failure(tick_args)
328            | RNodeState::Success(tick_args)
329            | RNodeState::Halting(tick_args) => tick_args.clone(),
330        }
331    }
332}