Skip to main content

crux_core/middleware/
effect_conversion.rs

1use std::marker::PhantomData;
2
3use crate::{Resolvable, ResolveError};
4
5use super::Layer;
6
7/// Middleware for converting the effect type to another type.
8///
9/// Typically, this is used to eliminate some of the effect variants which are processed
10/// by the layers below, so that code using this stack is not forced to have extraneous
11/// match arms which are never called.
12pub struct MapEffectLayer<Next, Effect>
13where
14    Next: Layer,
15    Effect: 'static,
16{
17    next: Next,
18    effect: PhantomData<fn() -> Effect>, // to avoid losing Sync
19}
20
21impl<Next, Effect> MapEffectLayer<Next, Effect>
22where
23    Next: Layer,
24{
25    pub fn new(next: Next) -> Self {
26        Self {
27            next,
28            effect: PhantomData,
29        }
30    }
31
32    fn map_effects(effects: Vec<Next::Effect>) -> Vec<Effect>
33    where
34        Effect: From<Next::Effect> + Send + 'static,
35    {
36        effects.into_iter().map(From::from).collect()
37    }
38}
39
40impl<Next, Effect> Layer for MapEffectLayer<Next, Effect>
41where
42    Next: Layer,
43    Effect: From<Next::Effect> + Send + 'static,
44{
45    type Event = Next::Event;
46    type Effect = Effect;
47
48    type ViewModel = Next::ViewModel;
49
50    fn update<F>(&self, event: Self::Event, effect_callback: F) -> Vec<Self::Effect>
51    where
52        F: Fn(Vec<Self::Effect>) + Sync + Send + 'static,
53    {
54        Self::map_effects(self.next.update(event, move |effects: Vec<Next::Effect>| {
55            effect_callback(Self::map_effects(effects));
56        }))
57    }
58
59    fn resolve<Output, F>(
60        &self,
61        request: &mut impl Resolvable<Output>,
62        output: Output,
63        effect_callback: F,
64    ) -> Result<Vec<Self::Effect>, ResolveError>
65    where
66        F: Fn(Vec<Self::Effect>) + Sync + Send + 'static,
67    {
68        Ok(Self::map_effects(self.next.resolve(
69            request,
70            output,
71            move |effects| effect_callback(Self::map_effects(effects)),
72        )?))
73    }
74
75    fn view(&self) -> Self::ViewModel {
76        self.next.view()
77    }
78
79    fn process_tasks<F>(&self, effect_callback: F) -> Vec<Self::Effect>
80    where
81        F: Fn(Vec<Self::Effect>) + Sync + Send + 'static,
82    {
83        Self::map_effects(
84            self.next
85                .process_tasks(move |effects| effect_callback(Self::map_effects(effects))),
86        )
87    }
88}