mod download;
mod dylib;
mod indexed_db;
mod legacy;
mod preload;
mod script;
mod timer;
mod worker;
pub use download::{Progress, Wget};
pub use dylib::{Library, dlopen};
pub use indexed_db::Idb;
#[allow(deprecated)] pub use preload::{preload, preload_data};
#[allow(deprecated)]
pub use script::load_script;
pub use timer::{
Ticks, animation_frame, animation_frames, immediate_loop, interval, main_loop_blocker, sleep,
timeout, timeout_loop, yield_now,
};
pub use worker::call_worker;
#[cfg(test)]
mod tests;
use crate::channel::mpsc;
use std::{
ffi::{CString, c_void},
io,
};
type Completion<T> = mpsc::Sender<io::Result<T>>;
fn c_string(value: &str) -> io::Result<CString> {
CString::new(value).map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))
}
fn completion<T>() -> (*mut c_void, mpsc::Receiver<io::Result<T>>) {
let (sender, receiver) = mpsc::bounded::<io::Result<T>>(1);
(Box::into_raw(Box::new(sender)).cast(), receiver)
}
unsafe fn complete<T>(arg: *mut c_void, result: io::Result<T>) {
let sender = unsafe { Box::from_raw(arg.cast::<Completion<T>>()) };
let _ = sender.send(result);
}
unsafe extern "C" fn failed<T>(arg: *mut c_void) {
unsafe { complete::<T>(arg, Err(io::Error::other("Emscripten operation failed"))) };
}
unsafe extern "C" fn succeeded(arg: *mut c_void) {
unsafe { complete(arg, Ok(())) };
}
async fn receive<T>(mut receiver: mpsc::Receiver<io::Result<T>>) -> io::Result<T> {
receiver
.recv()
.await
.ok_or_else(|| io::Error::other("operation canceled"))?
}
unsafe fn copy_bytes(data: *const c_void, len: usize) -> io::Result<Vec<u8>> {
if len == 0 {
return Ok(Vec::new());
}
if data.is_null() || len > isize::MAX as usize {
return Err(io::Error::other("invalid or oversized response buffer"));
}
Ok(unsafe { std::slice::from_raw_parts(data.cast::<u8>(), len) }.to_vec())
}
unsafe extern "C" fn loaded_bytes(arg: *mut c_void, data: *mut c_void, len: i32) {
let result = match usize::try_from(len) {
Ok(len) => unsafe { copy_bytes(data, len) },
Err(_) => Err(io::Error::other("response exceeds i32::MAX bytes")),
};
unsafe { complete(arg, result) };
}