Add panel_send_message and PanelAbi

This commit is contained in:
mars 2022-11-16 21:08:17 -07:00
parent a84f11ec4a
commit 14540db59c
3 changed files with 54 additions and 10 deletions

View File

@ -8,6 +8,8 @@
//! implemented, but in the future, [wasm3](https://github.com/wasm3/wasm3) //! implemented, but in the future, [wasm3](https://github.com/wasm3/wasm3)
//! will also be provided. //! will also be provided.
use std::collections::VecDeque;
use super::*; use super::*;
pub mod wasmtime; pub mod wasmtime;
@ -22,7 +24,7 @@ pub fn make_default_backend() -> anyhow::Result<Box<dyn Backend>> {
/// A WebAssembly runtime backend. /// A WebAssembly runtime backend.
pub trait Backend { pub trait Backend {
fn load_module(&self, abi: ScriptAbi, module: &[u8]) -> anyhow::Result<Arc<dyn Instance>>; fn load_module(&self, abi: Arc<ScriptAbi>, module: &[u8]) -> anyhow::Result<Arc<dyn Instance>>;
} }
/// An instance of a WebAssembly module. /// An instance of a WebAssembly module.
@ -69,6 +71,7 @@ pub struct ScriptAbi {
loaded_fonts: RwLock<Vec<Arc<text::Font>>>, loaded_fonts: RwLock<Vec<Arc<text::Font>>>,
text_layouts: RwLock<Slab<text::TextLayout>>, text_layouts: RwLock<Slab<text::TextLayout>>,
message_store: RwLock<Slab<Vec<u8>>>, message_store: RwLock<Slab<Vec<u8>>>,
panels: RwLock<Slab<PanelAbi>>,
} }
impl ScriptAbi { impl ScriptAbi {
@ -79,6 +82,13 @@ impl ScriptAbi {
} }
} }
/// Allocates a new ID and host-side storage for a panel.
pub fn create_panel(&self) -> PanelId {
let abi = PanelAbi::default();
let id = self.panels.write().insert(abi);
PanelId(id)
}
pub fn start_draw(&self) { pub fn start_draw(&self) {
let mut lock = self.draw_cmds.lock(); let mut lock = self.draw_cmds.lock();
lock.clear(); lock.clear();
@ -157,4 +167,23 @@ impl ScriptAbi {
let src = store.get(id as usize).unwrap(); let src = store.get(id as usize).unwrap();
dst.copy_from_slice(src); dst.copy_from_slice(src);
} }
pub fn panel_send_message(&self, id: u32, message: Vec<u8>) {
if let Some(panel) = self.panels.read().get(id as usize) {
panel.outgoing_messages.write().push_back(message);
}
}
pub fn recv_panel_messages(&self, id: PanelId) -> Vec<Vec<u8>> {
if let Some(panel) = self.panels.read().get(id.0) {
panel.outgoing_messages.write().drain(..).collect()
} else {
Vec::new()
}
}
}
#[derive(Default)]
pub struct PanelAbi {
outgoing_messages: RwLock<VecDeque<Vec<u8>>>,
} }

View File

@ -9,9 +9,9 @@ use crate::DrawCommand;
use canary_script::{Color, CursorEventKind, Rect, Vec2}; use canary_script::{Color, CursorEventKind, Rect, Vec2};
use parking_lot::Mutex; use parking_lot::Mutex;
type Caller<'a> = wasmtime::Caller<'a, ScriptAbi>; type Caller<'a> = wasmtime::Caller<'a, Arc<ScriptAbi>>;
type Store = wasmtime::Store<ScriptAbi>; type Store = wasmtime::Store<Arc<ScriptAbi>>;
type Linker = wasmtime::Linker<ScriptAbi>; type Linker = wasmtime::Linker<Arc<ScriptAbi>>;
pub struct WasmtimeBackend { pub struct WasmtimeBackend {
engine: wasmtime::Engine, engine: wasmtime::Engine,
@ -30,7 +30,7 @@ impl WasmtimeBackend {
} }
impl Backend for WasmtimeBackend { impl Backend for WasmtimeBackend {
fn load_module(&self, abi: ScriptAbi, module: &[u8]) -> anyhow::Result<Arc<dyn Instance>> { fn load_module(&self, abi: Arc<ScriptAbi>, module: &[u8]) -> anyhow::Result<Arc<dyn Instance>> {
let module = wasmtime::Module::new(&self.engine, module)?; let module = wasmtime::Module::new(&self.engine, module)?;
let mut store = wasmtime::Store::new(&self.engine, abi); let mut store = wasmtime::Store::new(&self.engine, abi);
let mut linker = Linker::new(&self.engine); let mut linker = Linker::new(&self.engine);
@ -147,6 +147,15 @@ impl WasmtimeInstance {
}, },
)?; )?;
linker.func_wrap(
module,
"panel_send_message",
|mut caller: Caller<'_>, id: u32, ptr: u32, len: u32| {
let message = Self::get_memory_slice_bytes(&mut caller, ptr as usize, len as usize);
caller.data().panel_send_message(id, message.to_vec())
},
)?;
Ok(()) Ok(())
} }

View File

@ -29,11 +29,12 @@ impl Runtime {
pub fn load_module(&self, module: &[u8]) -> anyhow::Result<Script> { pub fn load_module(&self, module: &[u8]) -> anyhow::Result<Script> {
let abi = ScriptAbi::new(self.font_store.to_owned()); let abi = ScriptAbi::new(self.font_store.to_owned());
let instance = self.backend.load_module(abi, module)?; let abi = Arc::new(abi);
let instance = self.backend.load_module(abi.to_owned(), module)?;
Ok(Script { Ok(Script {
instance, instance,
next_panel: 0, abi,
}) })
} }
} }
@ -41,16 +42,16 @@ impl Runtime {
/// A loaded instance of a Canary script. /// A loaded instance of a Canary script.
pub struct Script { pub struct Script {
instance: Arc<dyn Instance>, instance: Arc<dyn Instance>,
next_panel: usize, abi: Arc<ScriptAbi>,
} }
impl Script { impl Script {
pub fn create_panel(&mut self, protocol: &str, msg: Vec<u8>) -> anyhow::Result<Panel> { pub fn create_panel(&mut self, protocol: &str, msg: Vec<u8>) -> anyhow::Result<Panel> {
let id = PanelId(self.next_panel); let id = self.abi.create_panel();
self.next_panel += 1;
let userdata = self.instance.bind_panel(id, protocol, msg); let userdata = self.instance.bind_panel(id, protocol, msg);
Ok(Panel { Ok(Panel {
instance: self.instance.clone(), instance: self.instance.clone(),
abi: self.abi.clone(),
id, id,
userdata, userdata,
}) })
@ -60,6 +61,7 @@ impl Script {
/// A Canary panel. /// A Canary panel.
pub struct Panel { pub struct Panel {
instance: Arc<dyn Instance>, instance: Arc<dyn Instance>,
abi: Arc<ScriptAbi>,
id: PanelId, id: PanelId,
userdata: u32, userdata: u32,
} }
@ -84,6 +86,10 @@ impl Panel {
pub fn on_message(&self, msg: Vec<u8>) { pub fn on_message(&self, msg: Vec<u8>) {
self.instance.on_message(self.userdata, msg); self.instance.on_message(self.userdata, msg);
} }
pub fn recv_messages(&self) -> Vec<Vec<u8>> {
self.abi.recv_panel_messages(self.id)
}
} }
/// Proportion constant between pixels (at 96dpi) to millimeters (Canary's unit measurement). /// Proportion constant between pixels (at 96dpi) to millimeters (Canary's unit measurement).