1use futures::future::FutureExt;
4
5use crate::{definitions, Error, Result};
6
7pub type ExecutionResult<'a> = futures::future::BoxFuture<'a, Result<()>>;
9
10pub trait Executors: Sync
18{
19 fn execute_seq(&self, tst_node: definitions::tst::Seq) -> ExecutionResult<'_>;
21 fn execute_conc(&self, tst_node: definitions::tst::Conc) -> ExecutionResult<'_>;
23 fn execute_move_to(&self, tst_node: definitions::tst::MoveTo) -> ExecutionResult<'_>;
25 fn execute_search_area(&self, tst_node: definitions::tst::SearchArea) -> ExecutionResult<'_>;
27}
28
29pub trait Executor<T>: Send
38{
39 fn execute<'b>(&self, executors: &'b impl Executors, t: T) -> ExecutionResult<'b>;
41}
42
43fn dispatch_execution(
46 executors: &impl Executors,
47 tst_node: definitions::tst::Node,
48) -> ExecutionResult<'_>
49{
50 match tst_node
51 {
52 definitions::tst::Node::Noop(_) => async { Ok(()) }.boxed(),
53 definitions::tst::Node::Seq(seq) => executors.execute_seq(seq),
54 definitions::tst::Node::Conc(conc) => executors.execute_conc(conc),
55 definitions::tst::Node::MoveTo(move_to) => executors.execute_move_to(move_to),
56 definitions::tst::Node::SearchArea(search_area) => executors.execute_search_area(search_area),
57 }
58}
59
60pub struct SeqExecutor;
69
70impl Executor<definitions::tst::Seq> for SeqExecutor
71{
72 fn execute<'b>(
73 &self,
74 executors: &'b impl Executors,
75 t: definitions::tst::Seq,
76 ) -> ExecutionResult<'b>
77 {
78 async move {
79 for sub_task in t.children.iter()
80 {
81 dispatch_execution(executors, sub_task.to_owned()).await?;
82 }
83 Ok::<(), Error>(())
84 }
85 .boxed()
86 }
87}
88
89pub struct ConcExecutor;
98
99impl Executor<definitions::tst::Conc> for ConcExecutor
100{
101 fn execute<'b>(
102 &self,
103 executors: &'b impl Executors,
104 t: definitions::tst::Conc,
105 ) -> ExecutionResult<'b>
106 {
107 async move {
108 let mut futures = vec![];
109 for sub_task in t.children.iter()
110 {
111 futures.push(dispatch_execution(executors, sub_task.to_owned()));
112 }
113 futures::future::try_join_all(futures).await?;
114 Ok::<(), Error>(())
115 }
116 .boxed()
117 }
118}
119
120pub struct NoExecutor<T: Send>
129{
130 ghost: std::marker::PhantomData<T>,
131}
132
133impl<T: Send> Executor<T> for NoExecutor<T>
134{
135 fn execute<'b>(&self, _executors: &'b impl Executors, _t: T) -> ExecutionResult<'b>
136 {
137 async move { Err::<(), Error>(Error::NoExecutor()) }.boxed()
138 }
139}
140
141pub trait Agent {}
150
151pub trait CreatableFromAgent<TAgent, T>
160{
161 fn from_agent(agent: &TAgent) -> T;
163}
164
165impl<TAgent> CreatableFromAgent<TAgent, SeqExecutor> for SeqExecutor
166{
167 fn from_agent(_agent: &TAgent) -> SeqExecutor
168 {
169 SeqExecutor {}
170 }
171}
172impl<TAgent> CreatableFromAgent<TAgent, ConcExecutor> for ConcExecutor
173{
174 fn from_agent(_agent: &TAgent) -> ConcExecutor
175 {
176 ConcExecutor {}
177 }
178}
179
180impl<TAgent, T: Send> CreatableFromAgent<TAgent, NoExecutor<T>> for NoExecutor<T>
181{
182 fn from_agent(_agent: &TAgent) -> NoExecutor<T>
183 {
184 NoExecutor {
185 ghost: Default::default(),
186 }
187 }
188}
189
190pub trait TreeExecutorTrait
198{
199 type SeqExecutor: Executor<definitions::tst::Seq>;
201 type ConcExecutor: Executor<definitions::tst::Conc>;
203 type MoveToExecutor: Executor<definitions::tst::MoveTo>;
205 type SearchAreaExecutor: Executor<definitions::tst::SearchArea>;
207
208 fn from_agent<TAgent>(agent: &TAgent) -> Self
210 where
211 Self::SeqExecutor: CreatableFromAgent<TAgent, Self::SeqExecutor>,
212 Self::ConcExecutor: CreatableFromAgent<TAgent, Self::ConcExecutor>,
213 Self::MoveToExecutor: CreatableFromAgent<TAgent, Self::MoveToExecutor>,
214 Self::SearchAreaExecutor: CreatableFromAgent<TAgent, Self::SearchAreaExecutor>;
215 fn execute(&self, t: definitions::tst::Node) -> ExecutionResult<'_>;
217}
218
219pub struct TreeExecutor<
227 TSeqExecutor: Executor<definitions::tst::Seq>,
228 TConcExecutor: Executor<definitions::tst::Conc>,
229 TMoveToExecutor: Executor<definitions::tst::MoveTo>,
230 TSearchAreaExecutor: Executor<definitions::tst::SearchArea>,
231> {
232 seq_executor: ccutils::sync::ArcMutex<TSeqExecutor>,
233 conc_executor: ccutils::sync::ArcMutex<TConcExecutor>,
234 move_to_executor: ccutils::sync::ArcMutex<TMoveToExecutor>,
235 search_area_executor: ccutils::sync::ArcMutex<TSearchAreaExecutor>,
236}
237
238impl<
239 TSeqExecutor: Executor<definitions::tst::Seq>,
240 TConcExecutor: Executor<definitions::tst::Conc>,
241 TMoveToExecutor: Executor<definitions::tst::MoveTo>,
242 TSearchAreaExecutor: Executor<definitions::tst::SearchArea>,
243 > TreeExecutorTrait
244 for TreeExecutor<TSeqExecutor, TConcExecutor, TMoveToExecutor, TSearchAreaExecutor>
245{
246 type SeqExecutor = TSeqExecutor;
247 type ConcExecutor = TConcExecutor;
248 type MoveToExecutor = TMoveToExecutor;
249 type SearchAreaExecutor = TSearchAreaExecutor;
250 fn from_agent<TAgent>(agent: &TAgent) -> Self
251 where
252 TSeqExecutor: CreatableFromAgent<TAgent, TSeqExecutor>,
253 TConcExecutor: CreatableFromAgent<TAgent, TConcExecutor>,
254 TMoveToExecutor: CreatableFromAgent<TAgent, TMoveToExecutor>,
255 TSearchAreaExecutor: CreatableFromAgent<TAgent, TSearchAreaExecutor>,
256 {
257 Self {
258 seq_executor: TSeqExecutor::from_agent(agent).into(),
259 conc_executor: TConcExecutor::from_agent(agent).into(),
260 move_to_executor: TMoveToExecutor::from_agent(agent).into(),
261 search_area_executor: TSearchAreaExecutor::from_agent(agent).into(),
262 }
263 }
264 fn execute(&self, t: definitions::tst::Node) -> ExecutionResult<'_>
265 {
266 dispatch_execution(self, t)
267 }
268}
269
270impl<
271 TSeqExecutor: Executor<definitions::tst::Seq>,
272 TConcExecutor: Executor<definitions::tst::Conc>,
273 TMoveToExecutor: Executor<definitions::tst::MoveTo>,
274 TSearchAreaExecutor: Executor<definitions::tst::SearchArea>,
275 > Executors for TreeExecutor<TSeqExecutor, TConcExecutor, TMoveToExecutor, TSearchAreaExecutor>
276{
277 fn execute_seq(&self, tst_node: definitions::tst::Seq) -> ExecutionResult<'_>
278 {
279 self.seq_executor.lock().unwrap().execute(self, tst_node)
280 }
281 fn execute_conc(&self, tst_node: definitions::tst::Conc) -> ExecutionResult<'_>
282 {
283 self.conc_executor.lock().unwrap().execute(self, tst_node)
284 }
285 fn execute_move_to(&self, tst_node: definitions::tst::MoveTo) -> ExecutionResult<'_>
286 {
287 self
288 .move_to_executor
289 .lock()
290 .unwrap()
291 .execute(self, tst_node)
292 }
293 fn execute_search_area(&self, tst_node: definitions::tst::SearchArea) -> ExecutionResult<'_>
294 {
295 self
296 .search_area_executor
297 .lock()
298 .unwrap()
299 .execute(self, tst_node)
300 }
301}
302
303pub type DefaultTreeExecutor<TMoveToExecutor, TSearchAreaExecutor> =
305 TreeExecutor<SeqExecutor, ConcExecutor, TMoveToExecutor, TSearchAreaExecutor>;
306
307#[cfg(test)]
308mod tests
309{
310 struct FakeAgentPosition
311 {
312 longitude: f64,
313 latitude: f64,
314 altitude: f64,
315 }
316 struct FakeAgent
317 {
318 position: ccutils::sync::ArcMutex<FakeAgentPosition>,
319 }
320 impl Agent for FakeAgent {}
321 struct FakeAgentMoveToExecutor
322 {
323 position: ccutils::sync::ArcMutex<FakeAgentPosition>,
324 }
325 impl CreatableFromAgent<FakeAgent, FakeAgentMoveToExecutor> for FakeAgentMoveToExecutor
326 {
327 fn from_agent(_agent: &FakeAgent) -> FakeAgentMoveToExecutor
328 {
329 FakeAgentMoveToExecutor {
330 position: _agent.position.clone(),
331 }
332 }
333 }
334 impl Executor<definitions::tst::MoveTo> for FakeAgentMoveToExecutor
335 {
336 fn execute<'b>(
337 &self,
338 _executors: &'b impl Executors,
339 t: definitions::tst::MoveTo,
340 ) -> ExecutionResult<'b>
341 {
342 let pos = self.position.clone();
343 async move {
344 let mut p = pos.lock().unwrap();
345 p.longitude = t.params.waypoint.longitude;
346 p.latitude = t.params.waypoint.latitude;
347 p.altitude = t.params.waypoint.altitude;
348 Ok::<(), Error>(())
349 }
350 .boxed()
351 }
352 }
353 use super::*;
354
355 #[test]
356 fn execute()
357 {
358 let node: definitions::tst::Node = definitions::tst::Seq::build(None)
359 .add(
360 definitions::tst::MoveToParameters {
361 waypoint: definitions::tst::GeoPoint {
362 longitude: 16.4,
363 latitude: 59.3,
364 altitude: 110.8,
365 },
366 ..Default::default()
367 },
368 None,
369 )
370 .add(
371 definitions::tst::MoveToParameters {
372 waypoint: definitions::tst::GeoPoint {
373 longitude: 16.5,
374 latitude: 59.5,
375 altitude: 110.7,
376 },
377 ..Default::default()
378 },
379 None,
380 )
381 .into();
382
383 let agent = FakeAgent {
384 position: FakeAgentPosition {
385 longitude: 0.0,
386 latitude: 0.0,
387 altitude: 0.0,
388 }
389 .into(),
390 };
391 let executor = TreeExecutor::<
392 SeqExecutor,
393 ConcExecutor,
394 FakeAgentMoveToExecutor,
395 NoExecutor<definitions::tst::SearchArea>,
396 >::from_agent(&agent);
397 let r = executor.execute(node);
398 let res = futures::executor::block_on(r);
399 assert!(res.is_ok());
400 let p = agent.position.lock().unwrap();
401 assert_eq!(p.longitude, 16.5);
402 assert_eq!(p.latitude, 59.5);
403 assert_eq!(p.altitude, 110.7);
404 }
405}