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
94
95
96
97
98
99
100
101
102
103
mod registry;
mod request_serde;

use serde::{Deserialize, Serialize};

use crate::Effect;
use crate::{App, Core};
use registry::ResolveRegistry;
// ResolveByte is public to be accessible from crux_macros
#[doc(hidden)]
pub use request_serde::ResolveBytes;

/// Request for a side-effect passed from the Core to the Shell. The `uuid` links
/// the `Request` with the corresponding call to [`Core::resolve`] to pass the data back
/// to the [`App::update`] function (wrapped in the event provided to the capability originating the effect).
#[derive(Debug, Serialize, Deserialize)]
pub struct Request<Eff>
where
    Eff: Serialize,
{
    pub uuid: Vec<u8>,
    pub effect: Eff,
}

/// Bridge is a core wrapper presenting the same interface as the [`Core`] but in a
/// serialized form
pub struct Bridge<Eff, A>
where
    Eff: Effect,
    A: App,
{
    core: Core<Eff, A>,
    registry: ResolveRegistry,
}

impl<Eff, A> Bridge<Eff, A>
where
    Eff: Effect + Send + 'static,
    A: App,
{
    /// Create a new Bridge using the provided `core`.
    pub fn new(core: Core<Eff, A>) -> Self {
        Self {
            core,
            registry: Default::default(),
        }
    }

    /// Receive an event from the shell.
    ///
    /// The `event` is serialized and will be deserialized by the core before it's passed
    /// to your app.
    pub fn process_event<'de>(&self, event: &'de [u8]) -> Vec<u8>
    where
        A::Event: Deserialize<'de>,
    {
        self.process(None, event)
    }

    /// Receive a response to a capability request from the shell.
    ///
    /// The `output` is serialized capability output. It will be deserialized by the core.
    /// The `uuid` MUST match the `uuid` of the effect that triggered it, else the core will panic.
    pub fn handle_response<'de>(&self, uuid: &[u8], output: &'de [u8]) -> Vec<u8>
    where
        A::Event: Deserialize<'de>,
    {
        self.process(Some(uuid), output)
    }

    fn process<'de>(&self, uuid: Option<&[u8]>, data: &'de [u8]) -> Vec<u8>
    where
        A::Event: Deserialize<'de>,
    {
        let effects = match uuid {
            None => {
                let shell_event =
                    bincode::deserialize(data).expect("Message deserialization failed.");

                self.core.process_event(shell_event)
            }
            Some(uuid) => {
                self.registry.resume(uuid, data).expect(
                    "Response could not be handled. The request did not expect a response.",
                );

                self.core.process()
            }
        };

        let requests: Vec<_> = effects
            .into_iter()
            .map(|eff| self.registry.register(eff))
            .collect();

        bincode::serialize(&requests).expect("Request serialization failed.")
    }

    /// Get the current state of the app's view model (serialized).
    pub fn view(&self) -> Vec<u8> {
        bincode::serialize(&self.core.view()).expect("View should serialize")
    }
}