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}