Skip to main content

crux_core/bridge/
request_serde.rs

1use crate::{
2    Request,
3    capability::Operation,
4    core::{RequestHandle, ResolveError},
5};
6
7use super::{BridgeError, FfiFormat};
8
9// used in docs/internals/bridge.md
10// ANCHOR: resolve_serialized
11type ResolveOnceSerialized<T> = Box<dyn FnOnce(&[u8]) -> Result<(), BridgeError<T>> + Send>;
12type ResolveManySerialized<T> = Box<dyn FnMut(&[u8]) -> Result<(), BridgeError<T>> + Send>;
13
14/// A deserializing version of Resolve
15///
16/// `ResolveSerialized` is a separate type because lifetime elision doesn't work
17/// through generic type arguments. We can't create a `ResolveRegistry` of
18/// Resolve<&[u8]> without specifying an explicit lifetime.
19/// If you see a better way around this, please open a PR.
20pub enum ResolveSerialized<T: FfiFormat> {
21    Never,
22    Once(ResolveOnceSerialized<T>),
23    Many(ResolveManySerialized<T>),
24}
25// ANCHOR_END: resolve_serialized
26
27impl<T: FfiFormat> ResolveSerialized<T> {
28    pub(crate) fn resolve(&mut self, response: &[u8]) -> Result<(), BridgeError<T>> {
29        match self {
30            Self::Never => Err(BridgeError::ProcessResponse(ResolveError::Never)),
31            Self::Many(f) => f(response),
32            Self::Once(_) => {
33                // The resolve has been used, turn it into a Never
34                let Self::Once(f) = std::mem::replace(self, Self::Never) else {
35                    unreachable!("already resolved");
36                };
37
38                f(response)
39            }
40        }
41    }
42}
43
44impl<Op> Request<Op>
45where
46    Op: Operation,
47    Op::Output: for<'de> serde::de::Deserialize<'de>,
48{
49    /// Serialize this effect request using `effect` as a constructor
50    /// for a serializable Effect `Eff`
51    ///
52    /// You should never need to call this method yourself, it will be called
53    /// by the generated implementation of [`EffectFFI::serialize`](crate::EffectFFI::serialize),
54    /// which is used by the Bridge implementation.
55    pub fn serialize<F, Eff, T>(self, effect: F) -> (Eff, ResolveSerialized<T>)
56    where
57        F: FnOnce(Op) -> Eff,
58        T: FfiFormat,
59    {
60        // FIXME should Eff be bound as `Serializable`?
61        let handle = self.handle.deserializing(move |response| {
62            T::deserialize(response).map_err(BridgeError::DeserializeOutput)
63        });
64
65        (effect(self.operation), handle)
66    }
67}
68
69impl<Out> RequestHandle<Out> {
70    /// Convert this Resolve into a version which deserializes from bytes, consuming it.
71    /// The `func` argument is a 'deserializer' converting from bytes into the `Out` type.
72    fn deserializing<F, T>(self, mut func: F) -> ResolveSerialized<T>
73    where
74        F: (FnMut(&[u8]) -> Result<Out, BridgeError<T>>) + Send + Sync + 'static,
75        T: FfiFormat,
76        Out: 'static,
77    {
78        match self {
79            Self::Never => ResolveSerialized::Never,
80            Self::Once(resolve) => ResolveSerialized::Once(Box::new(move |response| {
81                let out = func(response)?;
82                resolve(out);
83                Ok(())
84            })),
85            Self::Many(resolve) => ResolveSerialized::Many(Box::new(move |response| {
86                let out = func(response)?;
87                resolve(out).map_err(|()| BridgeError::ProcessResponse(ResolveError::FinishedMany))
88            })),
89        }
90    }
91}