1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
4
5use smallvec::SmallVec;
6
7use crate::pipeline::{ForwardingAction, NackReason};
8use ndn_packet::Name;
9use ndn_strategy::{StrategyContext, StrategyFilter};
10
11use crate::stages::ErasedStrategy;
12
13pub struct ComposedStrategy {
20 name: Name,
21 inner: Arc<dyn ErasedStrategy>,
22 filters: Vec<Arc<dyn StrategyFilter>>,
23}
24
25impl ComposedStrategy {
26 pub fn new(
28 name: Name,
29 inner: Arc<dyn ErasedStrategy>,
30 filters: Vec<Arc<dyn StrategyFilter>>,
31 ) -> Self {
32 Self {
33 name,
34 inner,
35 filters,
36 }
37 }
38
39 fn apply_filters(
40 &self,
41 ctx: &StrategyContext,
42 mut actions: SmallVec<[ForwardingAction; 2]>,
43 ) -> SmallVec<[ForwardingAction; 2]> {
44 for filter in &self.filters {
45 actions = filter.filter(ctx, actions);
46 }
47 actions
48 }
49}
50
51impl ErasedStrategy for ComposedStrategy {
52 fn name(&self) -> &Name {
53 &self.name
54 }
55
56 fn decide_sync(&self, ctx: &StrategyContext<'_>) -> Option<SmallVec<[ForwardingAction; 2]>> {
57 let actions = self.inner.decide_sync(ctx)?;
58 Some(self.apply_filters(ctx, actions))
59 }
60
61 fn after_receive_interest_erased<'a>(
62 &'a self,
63 ctx: &'a StrategyContext<'a>,
64 ) -> Pin<Box<dyn Future<Output = SmallVec<[ForwardingAction; 2]>> + Send + 'a>> {
65 Box::pin(async move {
66 let actions = self.inner.after_receive_interest_erased(ctx).await;
67 self.apply_filters(ctx, actions)
68 })
69 }
70
71 fn on_nack_erased<'a>(
72 &'a self,
73 ctx: &'a StrategyContext<'a>,
74 reason: NackReason,
75 ) -> Pin<Box<dyn Future<Output = ForwardingAction> + Send + 'a>> {
76 Box::pin(async move {
79 let action = self.inner.on_nack_erased(ctx, reason).await;
80 let mut actions = SmallVec::new();
81 actions.push(action);
82 let filtered = self.apply_filters(ctx, actions);
83 filtered
84 .into_iter()
85 .next()
86 .unwrap_or(ForwardingAction::Suppress)
87 })
88 }
89}