Skip to content

Commit 9ed0b03

Browse files
authored
Merge pull request #67 from samouwow/non-reactive-handling-of-running-state
Non reactive handling of running state
2 parents a75cc8e + 84a032d commit 9ed0b03

File tree

16 files changed

+503
-153
lines changed

16 files changed

+503
-153
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description = "Workflow framework based on the behavior trees"
44
authors = ["BorisZhguchev <[email protected]>"]
55
homepage = "https://github.com/besok/forester"
66
repository = "https://github.com/besok/forester"
7-
version = "0.3.1"
7+
version = "0.3.2"
88
edition = "2021"
99
license-file = "LICENSE"
1010

@@ -34,4 +34,5 @@ url = "2.4.1"
3434

3535
[dev-dependencies]
3636
wiremock = "0.6.0"
37-
forester-http = "0.1.0"
37+
forester-http = "0.1.0"
38+

docs/src/seq.md

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ Otherwise, (when a child returns `failure` a sequence aborted)
66
In the language, the tree definitions and lambda invocations of this element are marked with the key word `sequence`.
77

88
```f-tree
9-
impl store(key:string, value:string); // store a string value to a key in blackboard
9+
impl store(key:string, value:string); // store a string value to a key in blackboard
1010
1111
root main {
1212
sequence {
13-
store("a","1") // first tick and proceed if succeded
14-
store("b","2") // sec tick and proceed if succeded
15-
store("c","3") // thrd tick and finish if succeded
13+
store("a","1") // first tick and proceed if succeded
14+
store("b","2") // sec tick and proceed if succeded
15+
store("c","3") // thrd tick and finish if succeded
1616
}
1717
}
1818
```
@@ -23,11 +23,11 @@ with a graph representation
2323
strict digraph {
2424
1[label="root
2525
main ",shape=rect,color=black]
26-
1 -> 2
26+
1 -> 2
2727
2[label="sequence",shape=rect,color=darkred]
28-
2 -> 3
29-
2 -> 4
30-
2 -> 5
28+
2 -> 3
29+
2 -> 4
30+
2 -> 5
3131
3[label="store (key=a,default=1)",shape=component,color=green]
3232
4[label="store (key=b,default=2)",shape=component,color=green]
3333
5[label="store (key=c,default=3)",shape=component,color=green]
@@ -45,12 +45,12 @@ main ",shape=rect,color=black]
4545
## Intention
4646
Often, it is used as a straight chain of instructions
4747
```f-tree
48-
// if the definition has only one child
48+
// if the definition has only one child
4949
// (root has only one child) '{''}' can be omitted
5050
root main sequence {
51-
validate_env()
52-
perform_action()
53-
finish_and_save()
51+
validate_env()
52+
perform_action()
53+
finish_and_save()
5454
}
5555
5656
```
@@ -69,13 +69,16 @@ root main {
6969
retry(5) m_sequence {
7070
store("key",1) // returns success
7171
perform_action() // returns failure
72-
finish_and_save()
72+
finish_and_save()
7373
}
7474
}
7575
```
7676

7777
The node `perform_action` returns `failure` and the decorator `retry` restarts `sequence`.
78-
The main difference with a sequence is an execution starts from the node `perform_action` skipping the node`store`.
78+
The main difference with a sequence is an execution starts from the node `perform_action` skipping the node `store`.
79+
80+
The memory will be reset once the final action has returned `success`.
81+
That is, if `finish_and_save` returns `success`, the next iteration will start with `store` again.
7982

8083
## Reactive Sequence
8184

@@ -87,10 +90,10 @@ root main {
8790
m_sequence {
8891
store("key",1) // returns success
8992
perform_action() // returns running
90-
finish_and_save()
93+
finish_and_save()
9194
}
9295
}
9396
```
9497

95-
The node `perform_action` returns `running` and the whole sequence returns `running`
96-
but on the next tick it starts from the node `store` again.
98+
The node `perform_action` returns `running` and the whole sequence returns `running`
99+
but on the next tick it starts from the node `store` again.

src/runtime/args.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use itertools::Itertools;
1414

1515
use serde::{Deserialize, Serialize};
1616
use std::collections::HashMap;
17-
use std::fmt::{Display, Formatter};
17+
use std::fmt::{format, Display, Formatter};
1818

1919
/// Just a Key class for the arguments that represents the key in BB
2020
pub type RtAKey = String;
@@ -108,16 +108,16 @@ impl RtValueCast {
108108
}
109109
/// tries to convert to vec and map each element
110110
pub fn map_vec<Map, To>(self, map: Map) -> RtResult<Option<Vec<To>>>
111-
where
112-
Map: Fn(RtValue) -> To,
111+
where
112+
Map: Fn(RtValue) -> To,
113113
{
114114
self.with_ptr().map(|v| v.as_vec(map))
115115
}
116116

117117
/// tries to convert obj to map
118118
pub fn map_obj<Map, To>(self, map: Map) -> RtResult<Option<HashMap<String, To>>>
119-
where
120-
Map: Fn((String, RtValue)) -> (String, To),
119+
where
120+
Map: Fn((String, RtValue)) -> (String, To),
121121
{
122122
self.with_ptr().map(|v| v.as_map(map))
123123
}
@@ -151,17 +151,17 @@ impl RtValue {
151151
}
152152
}
153153
pub fn as_vec<Map, To>(self, map: Map) -> Option<Vec<To>>
154-
where
155-
Map: Fn(RtValue) -> To,
154+
where
155+
Map: Fn(RtValue) -> To,
156156
{
157157
match self {
158158
RtValue::Array(elems) => Some(elems.into_iter().map(map).collect()),
159159
_ => None,
160160
}
161161
}
162162
pub fn as_map<Map, To>(self, map: Map) -> Option<HashMap<String, To>>
163-
where
164-
Map: Fn((String, RtValue)) -> (String, To),
163+
where
164+
Map: Fn((String, RtValue)) -> (String, To),
165165
{
166166
match self {
167167
RtValue::Object(elems) => Some(HashMap::from_iter(
@@ -232,8 +232,8 @@ impl RtArgs {
232232
}
233233
/// takes the first one and transform
234234
pub fn first_as<M, To>(&self, map: M) -> Option<To>
235-
where
236-
M: Fn(RtValue) -> Option<To>,
235+
where
236+
M: Fn(RtValue) -> Option<To>,
237237
{
238238
self.0.first().and_then(|v| map(v.value.clone()))
239239
}
@@ -245,6 +245,14 @@ impl RtArgs {
245245
.find(|a| a.name == key)
246246
.map(|a| a.clone().value)
247247
}
248+
/// finds by name and transform
249+
pub fn find_as<M, To>(&self, key: RtAKey, map: M) -> Option<To>
250+
where
251+
M: Fn(RtValue) -> Option<To>,
252+
{
253+
self.find(key).and_then(|v| map(v.clone()))
254+
}
255+
248256
/// finds by name or takes by index
249257
pub fn find_or_ith(&self, key: RtAKey, ith: usize) -> Option<RtValue> {
250258
self.0
@@ -399,4 +407,4 @@ impl RtArgument {
399407
}
400408
}
401409
}
402-
}
410+
}

src/runtime/context.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub struct TreeContextRef {
4343
bb: BBRef,
4444
tracer: TracerRef,
4545
curr_ts: Timestamp,
46-
trimmer: TrimmingQueueRef,
46+
_trimmer: TrimmingQueueRef,
4747
env: RtEnvRef,
4848
}
4949

@@ -55,7 +55,13 @@ impl From<&mut TreeContext> for TreeContextRef {
5555

5656
impl TreeContextRef {
5757
pub fn from_ctx(ctx: &TreeContext, trimmer: Arc<Mutex<TrimmingQueue>>) -> Self {
58-
TreeContextRef::new(ctx.bb.clone(), ctx.tracer.clone(), ctx.curr_ts, trimmer, ctx.rt_env.clone())
58+
TreeContextRef::new(
59+
ctx.bb.clone(),
60+
ctx.tracer.clone(),
61+
ctx.curr_ts,
62+
trimmer,
63+
ctx.rt_env.clone(),
64+
)
5965
}
6066
/// A pointer to tracer struct.
6167
pub fn tracer(&self) -> TracerRef {
@@ -84,14 +90,14 @@ impl TreeContextRef {
8490
bb: Arc<Mutex<BlackBoard>>,
8591
tracer: Arc<Mutex<Tracer>>,
8692
curr_ts: Timestamp,
87-
trimmer: Arc<Mutex<TrimmingQueue>>,
93+
_trimmer: Arc<Mutex<TrimmingQueue>>,
8894
env: RtEnvRef,
8995
) -> Self {
9096
Self {
9197
bb,
9298
tracer,
9399
curr_ts,
94-
trimmer,
100+
_trimmer,
95101
env,
96102
}
97103
}
@@ -124,7 +130,6 @@ pub struct TreeContext {
124130
rt_env: RtEnvRef,
125131
}
126132

127-
128133
impl TreeContext {
129134
pub fn state(&self) -> &HashMap<RNodeId, RNodeState> {
130135
&self.state
@@ -216,12 +221,14 @@ impl TreeContext {
216221
self.trace(NewState(id, state.clone()))?;
217222
Ok(self.state.insert(id, state))
218223
}
219-
pub(crate) fn state_in_ts(&self, id: &RNodeId) -> RNodeState {
220-
let actual_state = self
221-
.state
224+
pub(crate) fn state_last_set(&self, id: &RNodeId) -> RNodeState {
225+
self.state
222226
.get(id)
223227
.cloned()
224-
.unwrap_or(RNodeState::Ready(RtArgs::default()));
228+
.unwrap_or(RNodeState::Ready(RtArgs::default()))
229+
}
230+
pub(crate) fn state_in_ts(&self, id: &RNodeId) -> RNodeState {
231+
let actual_state = self.state_last_set(id);
225232
if self.is_curr_ts(&id) {
226233
actual_state
227234
} else {

src/runtime/forester.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ pub mod decorator;
22
pub mod flow;
33
pub mod serv;
44

5-
65
use crate::runtime::action::keeper::ActionKeeper;
76
use crate::runtime::action::{recover, Tick};
87
use crate::runtime::args::RtArgs;
98
use crate::runtime::blackboard::BlackBoard;
109
use crate::runtime::context::{RNodeState, TreeContext, TreeContextRef};
1110
use crate::runtime::env::RtEnv;
12-
use crate::runtime::forester::flow::{FlowDecision, read_cursor, run_with, run_with_par};
11+
use crate::runtime::forester::flow::{read_cursor, run_with, run_with_par, FlowDecision};
1312
use crate::runtime::forester::serv::ServInfo;
1413
use crate::runtime::rtree::rnode::RNode;
1514
use crate::runtime::rtree::RuntimeTree;
@@ -20,7 +19,6 @@ use crate::runtime::{trimmer, RtOk, RtResult, RuntimeError};
2019
use crate::tracer::{Event, Tracer};
2120
use log::debug;
2221
use std::sync::{Arc, Mutex};
23-
2422
use tokio::task::JoinHandle;
2523

2624
/// The entry point to process execution.
@@ -32,7 +30,7 @@ use tokio::task::JoinHandle;
3230
/// - Optimizer holds tasks to modify the tree or other components on the fly
3331
///
3432
///# Note:
35-
/// Better to use `ForesterBuilder` to create a Forester.
33+
/// Better to use `ForesterBuilder` to create a Forester.
3634
pub struct Forester {
3735
pub tree: RuntimeTree,
3836
pub bb: Arc<Mutex<BlackBoard>>,
@@ -177,12 +175,11 @@ impl Forester {
177175
RNodeState::Ready(tick_args) => {
178176
let len = children.len() as i64;
179177
debug!(target:"flow[ready]", "tick:{}, {tpe}. Start node",ctx.curr_ts());
180-
let new_state =
181-
if tpe.is_par() {
182-
RNodeState::Running(run_with_par(tick_args, len))
183-
} else {
184-
RNodeState::Running(run_with(tick_args, 0, len))
185-
};
178+
let new_state = if tpe.is_par() {
179+
RNodeState::Running(run_with_par(tick_args, len))
180+
} else {
181+
RNodeState::Running(run_with(tick_args, 0, len))
182+
};
186183

187184
debug!(target:"flow[ready]", "tick:{}, {tpe}. Switch to the new_state:{}",ctx.curr_ts(),&new_state);
188185
ctx.new_state(id, new_state)?;
@@ -270,9 +267,15 @@ impl Forester {
270267
// since it is ready we need to prepare decorator to start
271268
// But then we do nothing but switch the state to running in the current tick.
272269
RNodeState::Ready(tick_args) => {
273-
debug!(target:"decorator[ready]", "tick:{}, {tpe}. Start decorator({init_args}) and child args({tick_args})",ctx.curr_ts());
274-
let new_state =
275-
decorator::prepare(tpe, init_args.clone(), tick_args, &mut ctx)?;
270+
let prev_state = ctx.state_last_set(&id);
271+
debug!(target:"decorator[ready]", "tick:{}, {tpe}. Start decorator({init_args}), child args({tick_args}) and prev state({prev_state})",ctx.curr_ts());
272+
// Decorators only prepare themselves if they didn't return Running in the previous tick
273+
let new_state = match prev_state {
274+
RNodeState::Running(_) => {
275+
RNodeState::Running(run_with(tick_args, 0, 1))
276+
}
277+
_ => decorator::prepare(tpe, init_args.clone(), tick_args, &mut ctx)?,
278+
};
276279
debug!(target:"decorator[ready]", "tick:{}, the new_state: {}",ctx.curr_ts(),&new_state);
277280
ctx.new_state(id, new_state)?;
278281
}
@@ -348,7 +351,6 @@ impl Forester {
348351
self.stop_http();
349352
self.env.lock().map(|mut e| e.stop_all_daemons())?;
350353

351-
352354
ctx.root_state(self.tree.root)
353355
}
354356

0 commit comments

Comments
 (0)