use futures::future::FutureExt;
pub type ExecutionResult<'a> = futures::future::BoxFuture<'a, Result<()>>;
use crate::definitions::tst as definitions_tst;
use crate::{utils, Error, Result};
pub trait Executors: Sync
{
fn execute_seq(&self, tst_node: definitions_tst::Seq) -> ExecutionResult;
fn execute_conc(&self, tst_node: definitions_tst::Conc) -> ExecutionResult;
fn execute_move_to(&self, tst_node: definitions_tst::MoveTo) -> ExecutionResult;
fn execute_search_area(&self, tst_node: definitions_tst::SearchArea) -> ExecutionResult;
}
pub trait Executor<T>: Send
{
fn execute<'a, 'b>(&'a self, executors: &'b impl Executors, t: T) -> ExecutionResult<'b>;
}
fn dispatch_execution(
executors: &impl Executors,
tst_node: definitions_tst::Node,
) -> ExecutionResult
{
match tst_node
{
definitions_tst::Node::Noop(noop) => async { Ok(()) }.boxed(),
definitions_tst::Node::Seq(seq) => executors.execute_seq(seq),
definitions_tst::Node::Conc(conc) => executors.execute_conc(conc),
definitions_tst::Node::MoveTo(move_to) => executors.execute_move_to(move_to),
definitions_tst::Node::SearchArea(search_area) => executors.execute_search_area(search_area),
}
}
pub struct SeqExecutor;
impl Executor<definitions_tst::Seq> for SeqExecutor
{
fn execute<'a, 'b>(
&'a self,
executors: &'b impl Executors,
t: definitions_tst::Seq,
) -> ExecutionResult<'b>
{
async move {
for sub_task in t.children.iter()
{
dispatch_execution(executors, sub_task.to_owned()).await?;
}
Ok::<(), Error>(())
}
.boxed()
}
}
pub struct ConcExecutor;
impl Executor<definitions_tst::Conc> for ConcExecutor
{
fn execute<'a, 'b>(
&'a self,
executors: &'b impl Executors,
t: definitions_tst::Conc,
) -> ExecutionResult<'b>
{
async move {
let mut futures = vec![];
for sub_task in t.children.iter()
{
futures.push(dispatch_execution(executors, sub_task.to_owned()));
}
futures::future::try_join_all(futures).await?;
Ok::<(), Error>(())
}
.boxed()
}
}
pub struct NoExecutor<T: Send>
{
ghost: std::marker::PhantomData<T>,
}
impl<T: Send> Executor<T> for NoExecutor<T>
{
fn execute<'a, 'b>(&'a self, _executors: &'b impl Executors, _t: T) -> ExecutionResult<'b>
{
async move { Err::<(), Error>(Error::NoExecutor()) }.boxed()
}
}
pub trait Agent {}
pub trait CreatableFromAgent<TAgent, T>
{
fn from_agent(agent: &TAgent) -> T;
}
impl<TAgent> CreatableFromAgent<TAgent, SeqExecutor> for SeqExecutor
{
fn from_agent(_agent: &TAgent) -> SeqExecutor
{
SeqExecutor {}
}
}
impl<TAgent> CreatableFromAgent<TAgent, ConcExecutor> for ConcExecutor
{
fn from_agent(_agent: &TAgent) -> ConcExecutor
{
ConcExecutor {}
}
}
impl<TAgent, T: Send> CreatableFromAgent<TAgent, NoExecutor<T>> for NoExecutor<T>
{
fn from_agent(_agent: &TAgent) -> NoExecutor<T>
{
NoExecutor {
ghost: Default::default(),
}
}
}
pub trait AgentExecutorTrait
{
type SeqExecutor: Executor<definitions_tst::Seq>;
type ConcExecutor: Executor<definitions_tst::Conc>;
type MoveToExecutor: Executor<definitions_tst::MoveTo>;
type SearchAreaExecutor: Executor<definitions_tst::SearchArea>;
fn from_agent<TAgent>(agent: &TAgent) -> Self
where
Self::SeqExecutor: CreatableFromAgent<TAgent, Self::SeqExecutor>,
Self::ConcExecutor: CreatableFromAgent<TAgent, Self::ConcExecutor>,
Self::MoveToExecutor: CreatableFromAgent<TAgent, Self::MoveToExecutor>,
Self::SearchAreaExecutor: CreatableFromAgent<TAgent, Self::SearchAreaExecutor>;
fn execute(&self, t: definitions_tst::Node) -> ExecutionResult;
}
pub struct AgentExecutor<
TSeqExecutor: Executor<definitions_tst::Seq>,
TConcExecutor: Executor<definitions_tst::Conc>,
TMoveToExecutor: Executor<definitions_tst::MoveTo>,
TSearchAreaExecutor: Executor<definitions_tst::SearchArea>,
> {
seq_executor: utils::ArcMutex<TSeqExecutor>,
conc_executor: utils::ArcMutex<TConcExecutor>,
move_to_executor: utils::ArcMutex<TMoveToExecutor>,
search_area_executor: utils::ArcMutex<TSearchAreaExecutor>,
}
impl<
TSeqExecutor: Executor<definitions_tst::Seq>,
TConcExecutor: Executor<definitions_tst::Conc>,
TMoveToExecutor: Executor<definitions_tst::MoveTo>,
TSearchAreaExecutor: Executor<definitions_tst::SearchArea>,
> AgentExecutorTrait
for AgentExecutor<TSeqExecutor, TConcExecutor, TMoveToExecutor, TSearchAreaExecutor>
{
type SeqExecutor = TSeqExecutor;
type ConcExecutor = TConcExecutor;
type MoveToExecutor = TMoveToExecutor;
type SearchAreaExecutor = TSearchAreaExecutor;
fn from_agent<TAgent>(agent: &TAgent) -> Self
where
TSeqExecutor: CreatableFromAgent<TAgent, TSeqExecutor>,
TConcExecutor: CreatableFromAgent<TAgent, TConcExecutor>,
TMoveToExecutor: CreatableFromAgent<TAgent, TMoveToExecutor>,
TSearchAreaExecutor: CreatableFromAgent<TAgent, TSearchAreaExecutor>,
{
Self {
seq_executor: utils::arc_mutex_new(TSeqExecutor::from_agent(agent)),
conc_executor: utils::arc_mutex_new(TConcExecutor::from_agent(agent)),
move_to_executor: utils::arc_mutex_new(TMoveToExecutor::from_agent(agent)),
search_area_executor: utils::arc_mutex_new(TSearchAreaExecutor::from_agent(agent)),
}
}
fn execute(&self, t: definitions_tst::Node) -> ExecutionResult
{
dispatch_execution(self, t)
}
}
impl<
TSeqExecutor: Executor<definitions_tst::Seq>,
TConcExecutor: Executor<definitions_tst::Conc>,
TMoveToExecutor: Executor<definitions_tst::MoveTo>,
TSearchAreaExecutor: Executor<definitions_tst::SearchArea>,
> Executors for AgentExecutor<TSeqExecutor, TConcExecutor, TMoveToExecutor, TSearchAreaExecutor>
{
fn execute_seq(&self, tst_node: definitions_tst::Seq) -> ExecutionResult
{
self.seq_executor.lock().unwrap().execute(self, tst_node)
}
fn execute_conc(&self, tst_node: definitions_tst::Conc) -> ExecutionResult
{
self.conc_executor.lock().unwrap().execute(self, tst_node)
}
fn execute_move_to(&self, tst_node: definitions_tst::MoveTo) -> ExecutionResult
{
self
.move_to_executor
.lock()
.unwrap()
.execute(self, tst_node)
}
fn execute_search_area(&self, tst_node: definitions_tst::SearchArea) -> ExecutionResult
{
self
.search_area_executor
.lock()
.unwrap()
.execute(self, tst_node)
}
}
pub type DefaultAgentExecutor<TMoveToExecutor, TSearchAreaExecutor> =
AgentExecutor<SeqExecutor, ConcExecutor, TMoveToExecutor, TSearchAreaExecutor>;
#[cfg(test)]
mod tests
{
struct FakeAgentPosition
{
longitude: f32,
latitude: f32,
altitude: f32,
}
struct FakeAgent
{
position: utils::ArcMutex<FakeAgentPosition>,
}
impl Agent for FakeAgent {}
struct FakeAgentMoveToExecutor
{
position: utils::ArcMutex<FakeAgentPosition>,
}
impl CreatableFromAgent<FakeAgent, FakeAgentMoveToExecutor> for FakeAgentMoveToExecutor
{
fn from_agent(_agent: &FakeAgent) -> FakeAgentMoveToExecutor
{
FakeAgentMoveToExecutor {
position: _agent.position.clone(),
}
}
}
impl Executor<definitions_tst::MoveTo> for FakeAgentMoveToExecutor
{
fn execute<'a, 'b>(
&'a self,
_executors: &'b impl Executors,
t: definitions_tst::MoveTo,
) -> ExecutionResult<'b>
{
let pos = self.position.clone();
async move {
let mut p = pos.lock().unwrap();
p.longitude = t.params.waypoint.longitude;
p.latitude = t.params.waypoint.latitude;
p.altitude = t.params.waypoint.altitude;
Ok::<(), Error>(())
}
.boxed()
}
}
use super::*;
#[test]
fn execute()
{
let node: definitions_tst::Node = definitions_tst::Seq::build(None)
.add(
definitions_tst::MoveToParameters {
waypoint: definitions_tst::GeoPoint {
longitude: 16.4,
latitude: 59.3,
altitude: 110.8,
},
..Default::default()
},
None,
)
.add(
definitions_tst::MoveToParameters {
waypoint: definitions_tst::GeoPoint {
longitude: 16.5,
latitude: 59.5,
altitude: 110.7,
},
..Default::default()
},
None,
)
.into();
let agent = FakeAgent {
position: utils::arc_mutex_new(FakeAgentPosition {
longitude: 0.0,
latitude: 0.0,
altitude: 0.0,
}),
};
let executor = AgentExecutor::<
SeqExecutor,
ConcExecutor,
FakeAgentMoveToExecutor,
NoExecutor<definitions_tst::SearchArea>,
>::from_agent(&agent);
let r = executor.execute(node);
let res = futures::executor::block_on(r);
assert!(res.is_ok());
let p = agent.position.lock().unwrap();
assert_eq!(p.longitude, 16.5);
assert_eq!(p.latitude, 59.5);
assert_eq!(p.altitude, 110.7);
}
}