use crate::boundary::{
MutationBatch, RendererApi, STATUS_OK, STATUS_PROTOCOL_ERROR, install_renderer_api,
};
use crate::schema::{
WEB_BATCH_BYTES, WEB_EVENT_BUFFER_BYTES, WEB_EVENT_BUFFER_OFFSET, WEB_RUST_REGION_BASE,
};
use crate::{LaunchBuilder, LoopMode, Runtime};
use std::ffi::c_int;
use std::mem::{offset_of, size_of};
#[link(wasm_import_module = "compose_rust_renderer")]
unsafe extern "C" {
fn compose_rust_renderer_request_frame();
}
const _: () = {
assert!(size_of::<MutationBatch>() == WEB_BATCH_BYTES as usize);
assert!(offset_of!(MutationBatch, ptr) == 0);
assert!(offset_of!(MutationBatch, len) == 4);
assert!(offset_of!(MutationBatch, result) == 8);
};
#[repr(C)]
struct BoundaryBlock {
out: MutationBatch,
event: [u8; WEB_EVENT_BUFFER_BYTES as usize],
}
static mut BLOCK: BoundaryBlock = BoundaryBlock {
out: MutationBatch {
ptr: std::ptr::null(),
len: 0,
result: 0,
},
event: [0; WEB_EVENT_BUFFER_BYTES as usize],
};
const _: () = assert!(offset_of!(BoundaryBlock, event) == WEB_EVENT_BUFFER_OFFSET as usize);
extern "C" fn platform_run() -> c_int {
STATUS_OK as c_int
}
extern "C" fn request_frame() {
unsafe { compose_rust_renderer_request_frame() };
}
fn lent(address: u32) -> bool {
address >= WEB_RUST_REGION_BASE
}
#[unsafe(no_mangle)]
pub extern "C" fn compose_rust_host_web_init(
handshake: u32,
handshake_length: u32,
out: u32,
) -> i32 {
if !((handshake_length == 0 || lent(handshake)) && lent(out)) {
return STATUS_PROTOCOL_ERROR;
}
unsafe {
crate::boundary::compose_rust_host_init(
handshake as *const u8,
handshake_length,
out as *mut MutationBatch,
)
}
}
#[unsafe(no_mangle)]
pub extern "C" fn compose_rust_host_web_dispatch_event(
event: u32,
event_length: u32,
out: u32,
) -> i32 {
if !((event_length == 0 || lent(event)) && lent(out)) {
return STATUS_PROTOCOL_ERROR;
}
unsafe {
crate::boundary::compose_rust_host_dispatch_event(
event as *const u8,
event_length,
out as *mut MutationBatch,
)
}
}
#[unsafe(no_mangle)]
pub extern "C" fn compose_rust_host_web_render_frame(
frame_time_nanos_low: u32,
frame_time_nanos_high: u32,
out: u32,
) -> i32 {
if !(lent(out)) {
return STATUS_PROTOCOL_ERROR;
}
let frame_time_nanos =
(u64::from(frame_time_nanos_high) << 32) | u64::from(frame_time_nanos_low);
unsafe {
crate::boundary::compose_rust_host_render_frame(frame_time_nanos, out as *mut MutationBatch)
}
}
#[unsafe(no_mangle)]
pub extern "C" fn compose_rust_host_web_release_batch(out: u32) -> i32 {
if !(lent(out)) {
return STATUS_PROTOCOL_ERROR;
}
unsafe { crate::boundary::compose_rust_host_release_batch(out as *mut MutationBatch) };
STATUS_OK
}
#[unsafe(no_mangle)]
pub extern "C" fn compose_rust_host_web_shutdown() -> i32 {
crate::boundary::compose_rust_host_shutdown();
STATUS_OK
}
pub fn web_start(
builder: LaunchBuilder,
runtime: impl Fn() -> Box<dyn Runtime> + Send + Sync + 'static,
) -> u32 {
let _ = install_renderer_api(RendererApi {
run: platform_run,
request_frame,
});
let status = builder
.with_mode(LoopMode::Platform)
.try_launch_runtime(runtime);
if status != STATUS_OK {
return 0;
}
let address = (&raw const BLOCK) as usize as u32;
if lent(address) { address } else { 0 }
}