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            ResolveSerialized::Never => Err(BridgeError::ProcessResponse(ResolveError::Never)),
31            ResolveSerialized::Many(f) => f(response),
32            ResolveSerialized::Once(_) => {
33                // The resolve has been used, turn it into a Never
34                let ResolveSerialized::Once(f) = std::mem::replace(self, ResolveSerialized::Never)
35                else {
36                    unreachable!("already resolved");
37                };
38
39                f(response)
40            }
41        }
42    }
43}
44
45impl<Op> Request<Op>
46where
47    Op: Operation,
48    Op::Output: for<'de> serde::de::Deserialize<'de>,
49{
50    /// Serialize this effect request using `effect` as a constructor
51    /// for a serializable Effect `Eff`
52    ///
53    /// You should never need to call this method yourself, it will be called
54    /// by the generated implementation of [`Effect::serialize`](crate::Effect::serialize),
55    /// which is used by the Bridge implementation.
56    pub fn serialize<F, Eff, T>(self, effect: F) -> (Eff, ResolveSerialized<T>)
57    where
58        F: FnOnce(Op) -> Eff,
59        T: FfiFormat,
60    {
61        // FIXME should Eff be bound as `Serializable`?
62        let handle = self.handle.deserializing(move |response| {
63            T::deserialize(response).map_err(BridgeError::DeserializeOutput)
64        });
65
66        (effect(self.operation), handle)
67    }
68}
69
70impl<Out> RequestHandle<Out> {
71    /// Convert this Resolve into a version which deserializes from bytes, consuming it.
72    /// The `func` argument is a 'deserializer' converting from bytes into the `Out` type.
73    fn deserializing<F, T>(self, mut func: F) -> ResolveSerialized<T>
74    where
75        F: (FnMut(&[u8]) -> Result<Out, BridgeError<T>>) + Send + Sync + 'static,
76        T: FfiFormat,
77        Out: 'static,
78    {
79        match self {
80            RequestHandle::Never => ResolveSerialized::Never,
81            RequestHandle::Once(resolve) => ResolveSerialized::Once(Box::new(move |response| {
82                let out = func(response)?;
83                resolve(out);
84                Ok(())
85            })),
86            RequestHandle::Many(resolve) => ResolveSerialized::Many(Box::new(move |response| {
87                let out = func(response)?;
88                resolve(out).map_err(|()| BridgeError::ProcessResponse(ResolveError::FinishedMany))
89            })),
90        }
91    }
92}