use futures::FutureExt;
use std::{marker::PhantomData, sync::RwLock};
use crate::{definitions, Error, Result};
pub trait Mappers: Sync
{
type Output;
fn map_noop<'a>(
&'a self,
tst_node: definitions::tst::Noop,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
fn map_seq<'a>(
&'a self,
tst_node: definitions::tst::Seq,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
fn map_conc<'a>(
&'a self,
tst_node: definitions::tst::Conc,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
fn map_move_to<'a>(
&'a self,
tst_node: definitions::tst::MoveTo,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
fn map_search_area<'a>(
&'a self,
tst_node: definitions::tst::SearchArea,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
}
pub trait Mapper<TInput, TOutput>: Send + Sync
{
fn map<'a, 'b, M>(
&'a self,
mappers: &'b M,
t: TInput,
) -> futures::future::BoxFuture<'b, Result<TOutput>>
where
M: Mappers<Output = TOutput> + Send,
TInput: 'b;
}
fn dispatch_mapping<'a, M>(
mappers: &'a M,
tst_node: definitions::tst::Node,
) -> futures::future::BoxFuture<'a, Result<M::Output>>
where
M: Mappers,
{
match tst_node
{
definitions::tst::Node::Noop(noop) => mappers.map_noop(noop),
definitions::tst::Node::Seq(seq) => mappers.map_seq(seq),
definitions::tst::Node::Conc(conc) => mappers.map_conc(conc),
definitions::tst::Node::MoveTo(move_to) => mappers.map_move_to(move_to),
definitions::tst::Node::SearchArea(search_area) => mappers.map_search_area(search_area),
}
}
pub trait Accumulator<T>
{
fn new() -> Self;
fn next(&mut self, t: T) -> Result<()>;
fn finalise(self) -> Result<T>;
}
#[derive(Default)]
pub struct CompositeNodeMapper<TOutput, TAccumulator: Accumulator<TOutput>>
{
_out: PhantomData<fn() -> TOutput>,
_acc: PhantomData<fn() -> TAccumulator>,
}
impl<TNode, TOutput, TAccumulator> Mapper<TNode, TOutput>
for CompositeNodeMapper<TOutput, TAccumulator>
where
TNode: definitions::tst::CompositeNode
+ Send
+ IntoIterator<Item = definitions::tst::Node, IntoIter: Send>,
TAccumulator: Accumulator<TOutput> + Send,
{
fn map<'a, 'b, M>(
&'a self,
mappers: &'b M,
t: TNode,
) -> futures::future::BoxFuture<'b, Result<M::Output>>
where
M: Mappers<Output = TOutput>,
TNode: 'b,
{
async move {
let mut acc = TAccumulator::new();
for sub_task in t.into_iter()
{
acc.next(dispatch_mapping(mappers, sub_task).await?)?;
}
acc.finalise()
}
.boxed()
}
}
#[derive(Default)]
pub struct IdentityMapper {}
impl<TNode> Mapper<TNode, definitions::tst::Node> for IdentityMapper
where
TNode: definitions::tst::NodeTrait + Send,
{
fn map<'a, 'b, M>(
&'a self,
_mappers: &'b M,
t: TNode,
) -> futures::future::BoxFuture<'b, Result<definitions::tst::Node>>
where
M: Mappers<Output = definitions::tst::Node>,
TNode: 'b,
{
std::future::ready(Ok(t.into())).boxed()
}
}
pub trait TreeMapperTrait<TOutput>
{
type SeqMapper: Mapper<definitions::tst::Seq, TOutput>;
type ConcMapper: Mapper<definitions::tst::Conc, TOutput>;
type MoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>;
type SearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>;
fn map<'a>(
&'a self,
t: definitions::tst::Node,
) -> futures::future::BoxFuture<'a, Result<TOutput>>;
fn map_direct(&self, t: definitions::tst::Node) -> Result<TOutput>
{
futures::executor::block_on(self.map(t))
}
}
pub struct TreeMapper<
TOutput,
TNoopMapper: Mapper<definitions::tst::Noop, TOutput>,
TSeqMapper: Mapper<definitions::tst::Seq, TOutput>,
TConcMapper: Mapper<definitions::tst::Conc, TOutput>,
TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>,
TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>,
> {
noop_mapper: TNoopMapper,
seq_mapper: TSeqMapper,
conc_mapper: TConcMapper,
move_to_mapper: TMoveToMapper,
search_area_mapper: TSearchAreaMapper,
_out: PhantomData<fn() -> TOutput>,
}
impl<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper> Mappers
for TreeMapper<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
where
TNoopMapper: Mapper<definitions::tst::Noop, TOutput>,
TSeqMapper: Mapper<definitions::tst::Seq, TOutput>,
TConcMapper: Mapper<definitions::tst::Conc, TOutput>,
TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>,
TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>,
{
type Output = TOutput;
fn map_noop<'a>(
&'a self,
tst_node: definitions::tst::Noop,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>
{
self.noop_mapper.map(self, tst_node)
}
fn map_seq<'a>(
&'a self,
tst_node: definitions::tst::Seq,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>
{
self.seq_mapper.map(self, tst_node)
}
fn map_conc<'a>(
&'a self,
tst_node: definitions::tst::Conc,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>
{
self.conc_mapper.map(self, tst_node)
}
fn map_move_to<'a>(
&'a self,
tst_node: definitions::tst::MoveTo,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>
{
self.move_to_mapper.map(self, tst_node)
}
fn map_search_area<'a>(
&'a self,
tst_node: definitions::tst::SearchArea,
) -> futures::future::BoxFuture<'a, Result<Self::Output>>
{
self.search_area_mapper.map(self, tst_node)
}
}
impl<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
TreeMapperTrait<TOutput>
for TreeMapper<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
where
TNoopMapper: Mapper<definitions::tst::Noop, TOutput>,
TSeqMapper: Mapper<definitions::tst::Seq, TOutput>,
TConcMapper: Mapper<definitions::tst::Conc, TOutput>,
TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>,
TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>,
{
type SeqMapper = TSeqMapper;
type ConcMapper = TConcMapper;
type MoveToMapper = TMoveToMapper;
type SearchAreaMapper = TSearchAreaMapper;
fn map<'a>(&'a self, t: definitions::tst::Node)
-> futures::future::BoxFuture<'a, Result<TOutput>>
{
dispatch_mapping(self, t)
}
}
impl<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper> Default
for TreeMapper<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
where
TNoopMapper: Mapper<definitions::tst::Noop, TOutput> + Default + Send,
TSeqMapper: Mapper<definitions::tst::Seq, TOutput> + Default + Send,
TConcMapper: Mapper<definitions::tst::Conc, TOutput> + Default + Send,
TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput> + Default + Send,
TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput> + Default + Send,
{
fn default() -> Self
{
Self {
noop_mapper: Default::default(),
seq_mapper: Default::default(),
conc_mapper: Default::default(),
move_to_mapper: Default::default(),
search_area_mapper: Default::default(),
_out: Default::default(),
}
}
}
pub struct TransformerAccumulator<TNode: definitions::tst::CompositeNode>
{
children: RwLock<Option<Vec<definitions::tst::Node>>>,
tnode: PhantomData<fn() -> TNode>,
}
impl<TNode> Default for TransformerAccumulator<TNode>
where
TNode: definitions::tst::CompositeNode,
{
fn default() -> Self
{
Self::new()
}
}
impl<TNode> Accumulator<definitions::tst::Node> for TransformerAccumulator<TNode>
where
TNode: definitions::tst::CompositeNode,
{
fn new() -> Self
{
Self {
children: RwLock::new(Some(Default::default())),
tnode: Default::default(),
}
}
fn next(&mut self, t: definitions::tst::Node) -> Result<()>
{
let _: () = self
.children
.write()?
.as_mut()
.ok_or(Error::InternalError("Null vector should not happen."))?
.push(t);
Ok(())
}
fn finalise(self) -> Result<definitions::tst::Node>
{
let mut builder = TNode::build(Default::default());
for c in self
.children
.write()?
.take()
.ok_or(Error::InternalError("Null vector should not happen."))?
.into_iter()
{
builder = builder.add_node(c);
}
Ok(builder.into())
}
}
pub type TreeTransformer<TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper> = TreeMapper<
definitions::tst::Node,
IdentityMapper,
TSeqMapper,
TConcMapper,
TMoveToMapper,
TSearchAreaMapper,
>;
pub type DefaultTreeTransformer<TMoveToMapper, TSearchAreaMapper> = TreeTransformer<
CompositeNodeMapper<definitions::tst::Node, TransformerAccumulator<definitions::tst::Seq>>,
CompositeNodeMapper<definitions::tst::Node, TransformerAccumulator<definitions::tst::Conc>>,
TMoveToMapper,
TSearchAreaMapper,
>;
impl<TMoveToMapper, TSearchAreaMapper> DefaultTreeTransformer<TMoveToMapper, TSearchAreaMapper>
where
TMoveToMapper: Mapper<definitions::tst::MoveTo, definitions::tst::Node> + Send,
TSearchAreaMapper: Mapper<definitions::tst::SearchArea, definitions::tst::Node> + Send,
{
pub fn new(move_to_mapper: TMoveToMapper, search_area_mapper: TSearchAreaMapper) -> Self
{
Self {
noop_mapper: IdentityMapper {},
seq_mapper: Default::default(),
conc_mapper: Default::default(),
move_to_mapper,
search_area_mapper,
_out: Default::default(),
}
}
}
#[cfg(test)]
mod tests
{
use super::*;
macro_rules! get_tst_node {
($value:expr, $variant:path) => {
match $value
{
$variant(x) => x,
_ => panic!("Unexpected TST Node."),
}
};
}
#[derive(Default)]
struct FakeSearchAreaTransformer {}
impl Mapper<definitions::tst::SearchArea, definitions::tst::Node> for FakeSearchAreaTransformer
{
fn map<'a, 'b, M>(
&'a self,
_mappers: &'b M,
t: definitions::tst::SearchArea,
) -> futures::future::BoxFuture<'b, Result<definitions::tst::Node>>
where
M: Mappers<Output = definitions::tst::Node> + Send,
definitions::tst::SearchArea: 'b,
{
let avg = t.params.area.iter().fold((0.0, 0.0), |acc, x| {
(acc.0 + x.longitude, acc.1 + x.latitude)
});
std::future::ready(Ok(
definitions::tst::MoveTo {
params: definitions::tst::MoveToParameters {
waypoint: definitions::tst::GeoPoint {
longitude: avg.0 / t.params.area.len() as f64,
latitude: avg.1 / t.params.area.len() as f64,
altitude: 0.0,
},
..Default::default()
},
..Default::default()
}
.into(),
))
.boxed()
}
}
#[test]
fn expansion()
{
let node: definitions::tst::Node = definitions::tst::Seq::build(None)
.add(
definitions::tst::SearchAreaParameters {
area: vec![
definitions::tst::GeoPoint {
longitude: 10.0,
latitude: 50.0,
altitude: 0.0,
},
definitions::tst::GeoPoint {
longitude: 12.0,
latitude: 50.0,
altitude: 0.0,
},
definitions::tst::GeoPoint {
longitude: 12.0,
latitude: 52.0,
altitude: 0.0,
},
definitions::tst::GeoPoint {
longitude: 10.0,
latitude: 52.0,
altitude: 0.0,
},
],
..Default::default()
},
None,
)
.into();
let transformer: DefaultTreeTransformer<IdentityMapper, FakeSearchAreaTransformer> =
Default::default();
let transformed_node = transformer.map_direct(node).unwrap();
let node_seq = get_tst_node!(transformed_node, definitions::tst::Node::Seq);
let move_to = get_tst_node!(&node_seq.children[0], definitions::tst::Node::MoveTo);
assert_eq!(move_to.params.waypoint.longitude, 11.0);
assert_eq!(move_to.params.waypoint.latitude, 51.0);
}
}