#[macro_export]
macro_rules! wasm_worker {
(
$( init = $init:path, )?
$( first_serve = $first_serve:path, )?
build = $build:path
$(,)?
) => {
#[cfg(target_arch = "wasm32")]
extern "C" {
fn vgi_sab_worker_read(slot: i32, dst: *mut u8, n: i32) -> i32;
fn vgi_sab_worker_write(slot: i32, src: *const u8, n: i32) -> i32;
fn vgi_sab_worker_close(slot: i32);
fn vgi_worker_await_slot(slot: i32);
fn vgi_worker_await_release(slot: i32);
}
#[cfg(target_arch = "wasm32")]
struct __VgiSabReader {
slot: i32,
}
#[cfg(target_arch = "wasm32")]
impl ::std::io::Read for __VgiSabReader {
fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
let n = unsafe { vgi_sab_worker_read(self.slot, buf.as_mut_ptr(), buf.len() as i32) };
if n < 0 {
return Err(::std::io::Error::other("vgi sab ring read failed"));
}
Ok(n as usize)
}
}
#[cfg(target_arch = "wasm32")]
struct __VgiSabWriter {
slot: i32,
}
#[cfg(target_arch = "wasm32")]
impl ::std::io::Write for __VgiSabWriter {
fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
let n = unsafe { vgi_sab_worker_write(self.slot, buf.as_ptr(), buf.len() as i32) };
if n < 0 {
return Err(::std::io::Error::other("vgi sab ring write failed"));
}
Ok(n as usize)
}
fn flush(&mut self) -> ::std::io::Result<()> {
Ok(())
}
}
#[cfg(target_arch = "wasm32")]
fn __vgi_first_serve_once() {
$(
static ONCE: ::std::sync::Once = ::std::sync::Once::new();
ONCE.call_once(|| { $first_serve(); });
)?
}
#[cfg(target_arch = "wasm32")]
fn __vgi_serve_slot(slot: i32) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
__vgi_first_serve_once();
let worker: $crate::Worker = $build();
worker.serve_reader_writer(__VgiSabReader { slot }, __VgiSabWriter { slot });
}));
if let Err(payload) = result {
let msg = payload
.downcast_ref::<&str>()
.map(|s| (*s).to_string())
.or_else(|| payload.downcast_ref::<String>().cloned())
.unwrap_or_else(|| "<non-string panic payload>".to_string());
::std::eprintln!("[vgi] worker panic on slot {slot}: {msg}");
}
unsafe { vgi_sab_worker_close(slot) };
}
#[cfg(target_arch = "wasm32")]
#[no_mangle]
pub extern "C" fn vgi_worker_init() {
$( $init(); )?
}
#[cfg(target_arch = "wasm32")]
#[no_mangle]
pub extern "C" fn vgi_worker_serve_sab_slot(slot: i32) {
__vgi_serve_slot(slot);
}
#[cfg(target_arch = "wasm32")]
#[no_mangle]
pub extern "C" fn vgi_worker_serve_pool(n_slots: i32) {
for slot in 0..n_slots {
::std::thread::spawn(move || loop {
unsafe { vgi_worker_await_slot(slot) };
__vgi_serve_slot(slot);
unsafe { vgi_worker_await_release(slot) };
});
}
}
};
}