Files
storyteller-bevy/studio/src/wasm/mod.rs
T
2023-11-16 12:55:16 -05:00

104 lines
2.8 KiB
Rust

use std::{cell::RefCell, sync::OnceLock};
use anyhow::anyhow;
use bevy::window::Window;
use parking_lot::ReentrantMutex;
use web_sys::{CustomEvent, CustomEventInit, Element};
mod conv;
pub use conv::*;
pub(crate) type WasmMessageBuffer<T> = OnceLock<ReentrantMutex<RefCell<Option<T>>>>;
pub(crate) fn dispatch_to_js(
window: &Window,
event_type: &str,
// NOTE: We use dynamic dispatch here to keep the wasm binary small(-ish)
value: &dyn AsJsValue,
) -> anyhow::Result<()> {
let canvas = try_get_canvas(window)?;
let detail = value.as_js()?;
let event = CustomEvent::new_with_event_init_dict(
event_type,
CustomEventInit::new()
.bubbles(true)
.cancelable(true)
.detail(&detail),
)
.map_err(|err| anyhow!("{err:?}"))?;
canvas
.dispatch_event(&event)
.map_err(|err| anyhow!("{err:?}"))?;
Ok(())
}
fn try_get_canvas(window: &Window) -> anyhow::Result<Element> {
let canvas_selector = window
.canvas
.as_ref()
.ok_or(anyhow!("Canvas selector not set on Bevy Window"))?;
let window = web_sys::window().ok_or(anyhow!("web_sys::window() returned None"))?;
let document = window
.document()
.ok_or(anyhow!("window.document() returned None"))?;
match document.query_selector(canvas_selector) {
Ok(Some(canvas)) => Ok(canvas),
Ok(None) => Err(anyhow!(
"Failed to find element with selector '{canvas_selector}'"
)),
Err(err) => Err(anyhow!("JavaScript threw an Error: {err:?}")),
}
}
macro_rules! get_buffer {
($buffer:ident) => {
$buffer.get_or_init(|| {
::parking_lot::ReentrantMutex::new(::std::cell::RefCell::new(
::core::option::Option::None,
))
})
};
}
macro_rules! write_message {
($buffer:ident, $expr:expr) => {{
let buffer = crate::wasm::get_buffer!($buffer);
if let Some(lock) = buffer.try_lock() {
*lock.borrow_mut() = Some($expr);
}
}};
}
macro_rules! read_buffer {
($buffer:ident, |$msg:ident| $stmt:stmt) => {{
let buffer = crate::wasm::get_buffer!($buffer);
if let Some(lock) = buffer.try_lock() {
if let Some($msg) = lock.borrow_mut().take() {
$stmt
}
}
}};
($buffer:ident, |_| $stmt:stmt) => {{
let buffer = crate::wasm::get_buffer!($buffer);
if let Some(lock) = buffer.try_lock() {
if lock.borrow_mut().take().is_some() {
$stmt
}
}
}};
($buffer:ident) => {{
let buffer = crate::wasm::get_buffer!($buffer);
buffer.try_lock().and_then(|lock| lock.borrow_mut().take())
}};
}
pub(crate) use get_buffer;
pub(crate) use read_buffer;
pub(crate) use write_message;