use localharness::rustlite;
fn function_export_names(wasm: &[u8]) -> Vec<String> {
fn leb_u32(wasm: &[u8], i: &mut usize) -> u32 {
let mut v = 0u32;
let mut shift = 0;
loop {
let b = wasm[*i];
*i += 1;
v |= ((b & 0x7f) as u32) << shift;
if b & 0x80 == 0 {
break;
}
shift += 7;
}
v
}
const SEC_EXPORT: u8 = 7;
let mut i = 8usize; let mut names = Vec::new();
while i < wasm.len() {
let id = wasm[i];
i += 1;
let size = leb_u32(wasm, &mut i) as usize;
let end = i + size;
if id == SEC_EXPORT {
let mut p = i;
let count = leb_u32(wasm, &mut p);
for _ in 0..count {
let nlen = leb_u32(wasm, &mut p) as usize;
let name = String::from_utf8_lossy(&wasm[p..p + nlen]).to_string();
p += nlen;
let kind = wasm[p];
p += 1;
let _ = leb_u32(wasm, &mut p); if kind == 0x00 {
names.push(name);
}
}
return names;
}
i = end;
}
names
}
#[test]
fn variable_resolution_cartridge_exports_dims() {
let src = r#"
fn dims() -> i32 {
(320 << 16) | 240
}
fn frame(t: i32) {
host::display::clear(0x101010);
host::display::fill_rect(0, 0, 320, 240, 0x3060ff);
host::display::present();
}
"#;
let wasm = rustlite::compile(src).expect("variable-resolution cartridge compiles");
assert_eq!(&wasm[0..4], b"\0asm", "valid wasm magic");
let exports = function_export_names(&wasm);
assert!(
exports.iter().any(|n| n == "dims"),
"dims() must be exported so the worker can read it (got: {exports:?})",
);
assert!(
exports.iter().any(|n| n == "frame"),
"frame must still be exported (got: {exports:?})",
);
}
#[test]
fn square_and_portrait_dims_pack_correctly() {
for src in [
"fn dims() -> i32 { (512 << 16) | 512 } fn frame(t: i32) { host::display::clear(0); }",
"fn dims() -> i32 { (144 << 16) | 256 } fn frame(t: i32) { host::display::clear(0); }",
"fn dims() -> i32 { (256 << 16) | 128 } fn frame(t: i32) { host::display::clear(0); }",
] {
let wasm = rustlite::compile(src).expect("dims cartridge compiles");
let exports = function_export_names(&wasm);
assert!(
exports.iter().any(|n| n == "dims"),
"dims export present for: {src}",
);
}
}