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")
}
}