Skip to main content

crux_core/effects/routes/
serialized.rs

1use std::sync::{Arc, Weak};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    EffectFFI,
7    bridge::{BridgeError, EffectId, FfiFormat, Request as BridgeRequest, ResolveRegistry},
8    effects::{EffectRouter, Routes},
9};
10
11/// The default route, reproducing the standard [`Bridge`](crate::bridge::Bridge)
12/// behaviour on top of the [`EffectRouter`].
13///
14/// Effects on this lane are serialized to bytes using `Format`, registered under
15/// an [`EffectId`](crate::bridge::EffectId), and sent to the shell. The shell
16/// later calls [`Serialized::resolve`] with the id and the serialized response.
17/// Events and the view model are likewise exchanged as bytes via
18/// [`Serialized::update`] and [`Serialized::view`].
19///
20/// This is the primary onboarding path and typically acts as the fall-through
21/// arm of the routing closure, handling every effect that isn't claimed by a
22/// more specialised lane.
23///
24/// `Serialized` keeps a [`Weak`] reference to its [`EffectRouter`] so that
25/// resolving a request and processing an event can advance the runtime and
26/// route follow-up effects.
27pub struct Serialized<App, RouteSet, Format>
28where
29    App: crate::App,
30    RouteSet: Routes<App>,
31    Format: FfiFormat,
32{
33    router: Weak<EffectRouter<App, RouteSet>>,
34    registry: ResolveRegistry<Format>,
35}
36
37impl<App, RouteSet, Format> Serialized<App, RouteSet, Format>
38where
39    App: crate::App,
40    RouteSet: Routes<App> + Send + Sync + 'static,
41    Format: FfiFormat,
42{
43    /// Create a serialized route attached to `router`.
44    ///
45    /// Called from your [`Routes::new`] implementation with the [`Weak`] router
46    /// handle the trait provides.
47    #[must_use]
48    pub fn new(router: Weak<EffectRouter<App, RouteSet>>) -> Self {
49        Self {
50            router,
51            registry: ResolveRegistry::default(),
52        }
53    }
54
55    /// Process a serialized shell event and route any emitted effects.
56    ///
57    /// # Errors
58    ///
59    /// Returns an error if the event bytes could not be deserialized.
60    ///
61    /// # Panics
62    ///
63    /// Panics if the router has been dropped.
64    pub fn update<'a>(&self, event: &'a [u8]) -> Result<(), BridgeError<Format>>
65    where
66        App::Event: Deserialize<'a>,
67    {
68        let event = Format::deserialize(event).map_err(BridgeError::DeserializeEvent)?;
69
70        self.router().update(event);
71
72        Ok(())
73    }
74
75    /// Park a serialized effect and encode it as request bytes for the shell.
76    ///
77    /// # Errors
78    ///
79    /// Returns an error if the request could not be serialized.
80    ///
81    /// # Panics
82    ///
83    /// Panics if the internal registry lock has been poisoned.
84    pub fn serialize<Eff>(&self, effect: Eff) -> Result<Vec<u8>, BridgeError<Format>>
85    where
86        Eff: EffectFFI,
87    {
88        let request = self.registry.register(effect);
89        Self::encode_requests(&[request])
90    }
91
92    /// Resume a serialized request and route any follow-up effects.
93    ///
94    /// # Errors
95    ///
96    /// Returns an error if the request could not be resumed.
97    ///
98    /// # Panics
99    ///
100    /// Panics if the router has been dropped or the internal registry lock has
101    /// been poisoned.
102    pub fn resolve(&self, id: EffectId, response: &[u8]) -> Result<(), BridgeError<Format>> {
103        self.registry.resume(id, response)?;
104        self.router().process();
105
106        Ok(())
107    }
108
109    /// Serialize the current view model.
110    ///
111    /// # Errors
112    ///
113    /// Returns an error if the view model could not be serialized.
114    ///
115    /// # Panics
116    ///
117    /// Panics if the router has been dropped.
118    pub fn view(&self) -> Result<Vec<u8>, BridgeError<Format>>
119    where
120        App::ViewModel: Serialize,
121    {
122        let view = self.router().view();
123        let mut bytes = Vec::new();
124
125        Format::serialize(&mut bytes, &view).map_err(BridgeError::SerializeView)?;
126
127        Ok(bytes)
128    }
129
130    fn router(&self) -> Arc<EffectRouter<App, RouteSet>> {
131        self.router.upgrade().expect("effect router dropped")
132    }
133
134    fn encode_requests<Eff>(requests: &[BridgeRequest<Eff>]) -> Result<Vec<u8>, BridgeError<Format>>
135    where
136        Eff: Serialize,
137    {
138        let mut bytes = Vec::new();
139
140        Format::serialize(&mut bytes, &requests).map_err(BridgeError::SerializeRequests)?;
141
142        Ok(bytes)
143    }
144}