crux_core/bridge/
request_serde.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use crate::{
    capability::Operation,
    core::{Resolve, ResolveError},
    Request,
};

// used in docs/internals/bridge.md
// ANCHOR: resolve_serialized
type ResolveOnceSerialized = Box<dyn FnOnce(&mut dyn erased_serde::Deserializer) + Send>;
type ResolveManySerialized =
    Box<dyn FnMut(&mut dyn erased_serde::Deserializer) -> Result<(), ()> + Send>;

/// A deserializing version of Resolve
///
/// ResolveSerialized is a separate type because lifetime elision doesn't work
/// through generic type arguments. We can't create a ResolveRegistry of
/// Resolve<&[u8]> without specifying an explicit lifetime.
/// If you see a better way around this, please open a PR.
pub enum ResolveSerialized {
    Never,
    Once(ResolveOnceSerialized),
    Many(ResolveManySerialized),
}
// ANCHOR_END: resolve_serialized

impl ResolveSerialized {
    pub(crate) fn resolve(
        &mut self,
        bytes: &mut dyn erased_serde::Deserializer,
    ) -> Result<(), ResolveError> {
        match self {
            ResolveSerialized::Never => Err(ResolveError::Never),
            ResolveSerialized::Many(f) => f(bytes).map_err(|_| ResolveError::FinishedMany),
            ResolveSerialized::Once(_) => {
                // The resolve has been used, turn it into a Never
                if let ResolveSerialized::Once(f) =
                    std::mem::replace(self, ResolveSerialized::Never)
                {
                    f(bytes);
                }

                Ok(())
            }
        }
    }
}

impl<Op> Request<Op>
where
    Op: Operation,
{
    /// Serialize this effect request using `effect` as a constructor
    /// for a serializable Effect `Eff`
    ///
    /// You should never need to call this method yourself, it will be called
    /// by the generated implementation of [`Effect::serialize`](crate::Effect::serialize),
    /// which is used by the Bridge implementation.
    pub fn serialize<F, Eff>(self, effect: F) -> (Eff, ResolveSerialized)
    where
        F: FnOnce(Op) -> Eff,
    {
        // FIXME should Eff be bound as `Serializable`?
        let (operation, resolve) = (self.operation, self.resolve);

        let resolve = resolve.deserializing(move |deserializer| {
            erased_serde::deserialize(deserializer).expect("Deserialization failed")
        });

        (effect(operation), resolve)
    }
}

impl<Out> Resolve<Out> {
    /// Convert this Resolve into a version which deserializes from bytes, consuming it.
    /// The `func` argument is a 'deserializer' converting from bytes into the `Out` type.
    fn deserializing<F>(self, mut func: F) -> ResolveSerialized
    where
        F: (FnMut(&mut dyn erased_serde::Deserializer) -> Out) + Send + Sync + 'static,
        Out: 'static,
    {
        match self {
            Resolve::Never => ResolveSerialized::Never,
            Resolve::Once(resolve) => ResolveSerialized::Once(Box::new(move |deser| {
                let out = func(deser);
                resolve(out)
            })),
            Resolve::Many(resolve) => ResolveSerialized::Many(Box::new(move |deser| {
                let out = func(deser);
                resolve(out)
            })),
        }
    }
}