1use futures::FutureExt;
3use std::{marker::PhantomData, sync::RwLock};
4
5use crate::{definitions, Error, Result};
6
7pub trait Mappers: Sync
16{
17 type Output;
19 fn map_noop<'a>(
21 &'a self,
22 tst_node: definitions::tst::Noop,
23 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
24 fn map_seq<'a>(
26 &'a self,
27 tst_node: definitions::tst::Seq,
28 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
29 fn map_conc<'a>(
31 &'a self,
32 tst_node: definitions::tst::Conc,
33 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
34 fn map_move_to<'a>(
36 &'a self,
37 tst_node: definitions::tst::MoveTo,
38 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
39 fn map_search_area<'a>(
41 &'a self,
42 tst_node: definitions::tst::SearchArea,
43 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>;
44}
45
46pub trait Mapper<TInput, TOutput>: Send + Sync
55{
56 fn map<'a, 'b, M>(
58 &'a self,
59 mappers: &'b M,
60 t: TInput,
61 ) -> futures::future::BoxFuture<'b, Result<TOutput>>
62 where
63 M: Mappers<Output = TOutput> + Send,
64 TInput: 'b;
65}
66
67fn dispatch_mapping<'a, M>(
70 mappers: &'a M,
71 tst_node: definitions::tst::Node,
72) -> futures::future::BoxFuture<'a, Result<M::Output>>
73where
74 M: Mappers,
75{
76 match tst_node
77 {
78 definitions::tst::Node::Noop(noop) => mappers.map_noop(noop),
79 definitions::tst::Node::Seq(seq) => mappers.map_seq(seq),
80 definitions::tst::Node::Conc(conc) => mappers.map_conc(conc),
81 definitions::tst::Node::MoveTo(move_to) => mappers.map_move_to(move_to),
82 definitions::tst::Node::SearchArea(search_area) => mappers.map_search_area(search_area),
83 }
84}
85
86pub trait Accumulator<T>
94{
95 fn new() -> Self;
97 fn next(&mut self, t: T) -> Result<()>;
99 fn finalise(self) -> Result<T>;
101}
102
103#[derive(Default)]
112pub struct CompositeNodeMapper<TOutput, TAccumulator: Accumulator<TOutput>>
113{
114 _out: PhantomData<fn() -> TOutput>,
115 _acc: PhantomData<fn() -> TAccumulator>,
116}
117
118impl<TNode, TOutput, TAccumulator> Mapper<TNode, TOutput>
119 for CompositeNodeMapper<TOutput, TAccumulator>
120where
121 TNode: definitions::tst::CompositeNode
122 + Send
123 + IntoIterator<Item = definitions::tst::Node, IntoIter: Send>,
124 TAccumulator: Accumulator<TOutput> + Send,
125{
126 fn map<'a, 'b, M>(
127 &'a self,
128 mappers: &'b M,
129 t: TNode,
130 ) -> futures::future::BoxFuture<'b, Result<M::Output>>
131 where
132 M: Mappers<Output = TOutput>,
133 TNode: 'b,
134 {
135 async move {
136 let mut acc = TAccumulator::new();
137 for sub_task in t.into_iter()
138 {
139 acc.next(dispatch_mapping(mappers, sub_task).await?)?;
140 }
141 acc.finalise()
142 }
143 .boxed()
144 }
145}
146
147#[derive(Default)]
156pub struct IdentityMapper {}
157
158impl<TNode> Mapper<TNode, definitions::tst::Node> for IdentityMapper
159where
160 TNode: definitions::tst::NodeTrait + Send,
161{
162 fn map<'a, 'b, M>(
163 &'a self,
164 _mappers: &'b M,
165 t: TNode,
166 ) -> futures::future::BoxFuture<'b, Result<definitions::tst::Node>>
167 where
168 M: Mappers<Output = definitions::tst::Node>,
169 TNode: 'b,
170 {
171 std::future::ready(Ok(t.into())).boxed()
172 }
173}
174
175pub trait TreeMapperTrait<TOutput>
184{
185 type SeqMapper: Mapper<definitions::tst::Seq, TOutput>;
187 type ConcMapper: Mapper<definitions::tst::Conc, TOutput>;
189 type MoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>;
191 type SearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>;
193
194 fn map<'a>(
196 &'a self,
197 t: definitions::tst::Node,
198 ) -> futures::future::BoxFuture<'a, Result<TOutput>>;
199
200 fn map_direct(&self, t: definitions::tst::Node) -> Result<TOutput>
202 {
203 futures::executor::block_on(self.map(t))
204 }
205}
206
207pub struct TreeMapper<
216 TOutput,
217 TNoopMapper: Mapper<definitions::tst::Noop, TOutput>,
218 TSeqMapper: Mapper<definitions::tst::Seq, TOutput>,
219 TConcMapper: Mapper<definitions::tst::Conc, TOutput>,
220 TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>,
221 TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>,
222> {
223 noop_mapper: TNoopMapper,
224 seq_mapper: TSeqMapper,
225 conc_mapper: TConcMapper,
226 move_to_mapper: TMoveToMapper,
227 search_area_mapper: TSearchAreaMapper,
228 _out: PhantomData<fn() -> TOutput>,
229}
230
231impl<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper> Mappers
232 for TreeMapper<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
233where
234 TNoopMapper: Mapper<definitions::tst::Noop, TOutput>,
235 TSeqMapper: Mapper<definitions::tst::Seq, TOutput>,
236 TConcMapper: Mapper<definitions::tst::Conc, TOutput>,
237 TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>,
238 TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>,
239{
240 type Output = TOutput;
241 fn map_noop<'a>(
242 &'a self,
243 tst_node: definitions::tst::Noop,
244 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>
245 {
246 self.noop_mapper.map(self, tst_node)
247 }
248 fn map_seq<'a>(
249 &'a self,
250 tst_node: definitions::tst::Seq,
251 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>
252 {
253 self.seq_mapper.map(self, tst_node)
254 }
255 fn map_conc<'a>(
256 &'a self,
257 tst_node: definitions::tst::Conc,
258 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>
259 {
260 self.conc_mapper.map(self, tst_node)
261 }
262 fn map_move_to<'a>(
263 &'a self,
264 tst_node: definitions::tst::MoveTo,
265 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>
266 {
267 self.move_to_mapper.map(self, tst_node)
268 }
269 fn map_search_area<'a>(
270 &'a self,
271 tst_node: definitions::tst::SearchArea,
272 ) -> futures::future::BoxFuture<'a, Result<Self::Output>>
273 {
274 self.search_area_mapper.map(self, tst_node)
275 }
276}
277
278impl<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
279 TreeMapperTrait<TOutput>
280 for TreeMapper<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
281where
282 TNoopMapper: Mapper<definitions::tst::Noop, TOutput>,
283 TSeqMapper: Mapper<definitions::tst::Seq, TOutput>,
284 TConcMapper: Mapper<definitions::tst::Conc, TOutput>,
285 TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput>,
286 TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput>,
287{
288 type SeqMapper = TSeqMapper;
289 type ConcMapper = TConcMapper;
290 type MoveToMapper = TMoveToMapper;
291 type SearchAreaMapper = TSearchAreaMapper;
292 fn map<'a>(&'a self, t: definitions::tst::Node)
294 -> futures::future::BoxFuture<'a, Result<TOutput>>
295 {
296 dispatch_mapping(self, t)
297 }
298}
299
300impl<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper> Default
301 for TreeMapper<TOutput, TNoopMapper, TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper>
302where
303 TNoopMapper: Mapper<definitions::tst::Noop, TOutput> + Default + Send,
304 TSeqMapper: Mapper<definitions::tst::Seq, TOutput> + Default + Send,
305 TConcMapper: Mapper<definitions::tst::Conc, TOutput> + Default + Send,
306 TMoveToMapper: Mapper<definitions::tst::MoveTo, TOutput> + Default + Send,
307 TSearchAreaMapper: Mapper<definitions::tst::SearchArea, TOutput> + Default + Send,
308{
309 fn default() -> Self
310 {
311 Self {
312 noop_mapper: Default::default(),
313 seq_mapper: Default::default(),
314 conc_mapper: Default::default(),
315 move_to_mapper: Default::default(),
316 search_area_mapper: Default::default(),
317 _out: Default::default(),
318 }
319 }
320}
321
322pub struct TransformerAccumulator<TNode: definitions::tst::CompositeNode>
331{
332 children: RwLock<Option<Vec<definitions::tst::Node>>>,
333 tnode: PhantomData<fn() -> TNode>,
334}
335
336impl<TNode> Default for TransformerAccumulator<TNode>
337where
338 TNode: definitions::tst::CompositeNode,
339{
340 fn default() -> Self
341 {
342 Self::new()
343 }
344}
345
346impl<TNode> Accumulator<definitions::tst::Node> for TransformerAccumulator<TNode>
347where
348 TNode: definitions::tst::CompositeNode,
349{
350 fn new() -> Self
351 {
352 Self {
353 children: RwLock::new(Some(Default::default())),
354 tnode: Default::default(),
355 }
356 }
357 fn next(&mut self, t: definitions::tst::Node) -> Result<()>
358 {
359 let _: () = self
360 .children
361 .write()?
362 .as_mut()
363 .ok_or(Error::InternalError("Null vector should not happen."))?
364 .push(t);
365 Ok(())
366 }
367 fn finalise(self) -> Result<definitions::tst::Node>
368 {
369 let mut builder = TNode::build(Default::default());
370 for c in self
371 .children
372 .write()?
373 .take()
374 .ok_or(Error::InternalError("Null vector should not happen."))?
375 .into_iter()
376 {
377 builder = builder.add_node(c);
378 }
379 Ok(builder.into())
380 }
381}
382
383pub type TreeTransformer<TSeqMapper, TConcMapper, TMoveToMapper, TSearchAreaMapper> = TreeMapper<
392 definitions::tst::Node,
393 IdentityMapper,
394 TSeqMapper,
395 TConcMapper,
396 TMoveToMapper,
397 TSearchAreaMapper,
398>;
399
400pub type DefaultTreeTransformer<TMoveToMapper, TSearchAreaMapper> = TreeTransformer<
402 CompositeNodeMapper<definitions::tst::Node, TransformerAccumulator<definitions::tst::Seq>>,
403 CompositeNodeMapper<definitions::tst::Node, TransformerAccumulator<definitions::tst::Conc>>,
404 TMoveToMapper,
405 TSearchAreaMapper,
406>;
407
408impl<TMoveToMapper, TSearchAreaMapper> DefaultTreeTransformer<TMoveToMapper, TSearchAreaMapper>
409where
410 TMoveToMapper: Mapper<definitions::tst::MoveTo, definitions::tst::Node> + Send,
411 TSearchAreaMapper: Mapper<definitions::tst::SearchArea, definitions::tst::Node> + Send,
412{
413 pub fn new(move_to_mapper: TMoveToMapper, search_area_mapper: TSearchAreaMapper) -> Self
415 {
416 Self {
417 noop_mapper: IdentityMapper {},
418 seq_mapper: Default::default(),
419 conc_mapper: Default::default(),
420 move_to_mapper,
421 search_area_mapper,
422 _out: Default::default(),
423 }
424 }
425}
426
427#[cfg(test)]
428mod tests
429{
430 use super::*;
431 macro_rules! get_tst_node {
432 ($value:expr, $variant:path) => {
433 match $value
434 {
435 $variant(x) => x,
436 _ => panic!("Unexpected TST Node."),
437 }
438 };
439 }
440 #[derive(Default)]
441 struct FakeSearchAreaTransformer {}
442
443 impl Mapper<definitions::tst::SearchArea, definitions::tst::Node> for FakeSearchAreaTransformer
444 {
445 fn map<'a, 'b, M>(
446 &'a self,
447 _mappers: &'b M,
448 t: definitions::tst::SearchArea,
449 ) -> futures::future::BoxFuture<'b, Result<definitions::tst::Node>>
450 where
451 M: Mappers<Output = definitions::tst::Node> + Send,
452 definitions::tst::SearchArea: 'b,
453 {
454 let avg = t.params.area.iter().fold((0.0, 0.0), |acc, x| {
455 (acc.0 + x.longitude, acc.1 + x.latitude)
456 });
457 std::future::ready(Ok(
458 definitions::tst::MoveTo {
459 params: definitions::tst::MoveToParameters {
460 waypoint: definitions::tst::GeoPoint {
461 longitude: avg.0 / t.params.area.len() as f64,
462 latitude: avg.1 / t.params.area.len() as f64,
463 altitude: 0.0,
464 },
465 ..Default::default()
466 },
467 ..Default::default()
468 }
469 .into(),
470 ))
471 .boxed()
472 }
473 }
474
475 #[test]
476 fn expansion()
477 {
478 let node: definitions::tst::Node = definitions::tst::Seq::build(None)
479 .add(
480 definitions::tst::SearchAreaParameters {
481 area: vec![
482 definitions::tst::GeoPoint {
483 longitude: 10.0,
484 latitude: 50.0,
485 altitude: 0.0,
486 },
487 definitions::tst::GeoPoint {
488 longitude: 12.0,
489 latitude: 50.0,
490 altitude: 0.0,
491 },
492 definitions::tst::GeoPoint {
493 longitude: 12.0,
494 latitude: 52.0,
495 altitude: 0.0,
496 },
497 definitions::tst::GeoPoint {
498 longitude: 10.0,
499 latitude: 52.0,
500 altitude: 0.0,
501 },
502 ],
503 ..Default::default()
504 },
505 None,
506 )
507 .into();
508 let transformer: DefaultTreeTransformer<IdentityMapper, FakeSearchAreaTransformer> =
509 Default::default();
510 let transformed_node = transformer.map_direct(node).unwrap();
511 let node_seq = get_tst_node!(transformed_node, definitions::tst::Node::Seq);
512 let move_to = get_tst_node!(&node_seq.children[0], definitions::tst::Node::MoveTo);
513 assert_eq!(move_to.params.waypoint.longitude, 11.0);
514 assert_eq!(move_to.params.waypoint.latitude, 51.0);
515 }
516}