Skip to main content

crux_core/middleware/
bridge.rs

1use std::{marker::PhantomData, sync::Arc};
2
3use serde::{Deserialize, Serialize};
4
5use super::Layer;
6use crate::{
7    EffectFFI,
8    bridge::{BridgeError, EffectId, FfiFormat, ResolveRegistry},
9};
10
11#[doc(hidden)]
12pub type EffectCallback<Format> =
13    dyn Fn(Result<Vec<u8>, BridgeError<Format>>) + Send + Sync + 'static;
14
15/// FFI Bridge with support for wrapping a middleware stack
16pub struct Bridge<Next, Format>
17where
18    Next: Layer,
19    Format: FfiFormat,
20{
21    next: Next,
22    effect_callback: Arc<EffectCallback<Format>>,
23    registry: Arc<ResolveRegistry<Format>>,
24    format: PhantomData<Format>,
25}
26
27impl<Next, Format> Bridge<Next, Format>
28where
29    Next: Layer,
30    Next::Event: for<'a> Deserialize<'a>,
31    Next::Effect: EffectFFI,
32    Format: FfiFormat,
33{
34    /// Typically, you would would use [`Layer::bridge`] to construct a `Bridge` instance
35    pub fn new<F>(next: Next, effect_callback: F) -> Self
36    where
37        F: Fn(Result<Vec<u8>, BridgeError<Format>>) + Send + Sync + 'static,
38    {
39        Self {
40            next,
41            effect_callback: Arc::new(effect_callback),
42            registry: Arc::new(ResolveRegistry::default()),
43            format: PhantomData,
44        }
45    }
46
47    /// Send a serialized event to the core
48    ///
49    /// # Errors
50    ///
51    /// Returns an [`BridgeError`] when any of the (de)serialization fails
52    pub fn update(
53        &self,
54        event_bytes: &[u8],
55        requests_out: &mut Vec<u8>,
56    ) -> Result<(), BridgeError<Format>> {
57        self.process(None, event_bytes, requests_out)
58    }
59
60    /// Resolve a requested effect, providing the output to the core
61    ///
62    /// # Errors
63    ///
64    /// Returns a [`BridgeError`] when the effect fails to resolve, or any of the (de)serialization fails.
65    pub fn resolve(
66        &self,
67        id: EffectId,
68        output: &[u8],
69        requests_out: &mut Vec<u8>,
70    ) -> Result<(), BridgeError<Format>> {
71        self.process(Some(id), output, requests_out)
72    }
73
74    fn process(
75        &self,
76        id: Option<EffectId>,
77        event_or_output: &[u8],
78        requests_out: &mut Vec<u8>,
79    ) -> Result<(), BridgeError<Format>> {
80        let effect_callback = {
81            let shell_callback = self.effect_callback.clone();
82            let registry = self.registry.clone();
83
84            move |effects: Vec<Next::Effect>| {
85                let requests: Vec<_> = effects
86                    .into_iter()
87                    .map(|eff| registry.register(eff))
88                    .collect();
89                let mut requests_bytes = vec![];
90
91                let result = {
92                    Format::serialize(&mut requests_bytes, &requests)
93                        .map_err(BridgeError::SerializeRequests)
94                };
95
96                shell_callback(result.map(|()| requests_bytes));
97            }
98        };
99
100        let effects = match id {
101            None => {
102                let shell_event =
103                    Format::deserialize(event_or_output).map_err(BridgeError::DeserializeEvent)?;
104
105                self.next.update(shell_event, effect_callback)
106            }
107            Some(id) => {
108                self.registry.resume(id, event_or_output)?;
109
110                self.next.process_tasks(effect_callback)
111            }
112        };
113
114        let requests: Vec<_> = effects
115            .into_iter()
116            .map(|eff| self.registry.register(eff))
117            .collect();
118
119        Format::serialize(requests_out, &requests).map_err(BridgeError::SerializeRequests)?;
120
121        Ok(())
122    }
123
124    /// Get the latest view model
125    ///
126    /// # Errors
127    ///
128    /// Returns an [`BridgeError`] when any of the (de)serialization fails
129    pub fn view(&self, view_out: &mut Vec<u8>) -> Result<(), BridgeError<Format>>
130    where
131        Next::ViewModel: Serialize,
132    {
133        Format::serialize(view_out, &self.next.view()).map_err(BridgeError::SerializeView)
134    }
135}