Skip to content

Commit

Permalink
feat(wasm-api): use named import objects
Browse files Browse the repository at this point in the history
- switch to name import objects to avoid merging into flat namespace
- update externs in core.zig
- update docstrings
  • Loading branch information
postspectacular committed Aug 7, 2022
1 parent 67d26ef commit 4965f20
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 49 deletions.
2 changes: 1 addition & 1 deletion packages/wasm-api/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export interface WasmExports {
* functions are declared as bindings in `/zig/core.zig`. Also see this file for
* documentation of each function...
*/
export interface CoreAPI {
export interface CoreAPI extends WebAssembly.ModuleImports {
printI8: Fn<number, void>;
printU8: Fn<number, void>;
printU8Hex: Fn<number, void>;
Expand Down
62 changes: 40 additions & 22 deletions packages/wasm-api/src/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ export class WasmBridge<T extends WasmExports = WasmExports> {
f64!: Float64Array;
utf8Decoder: TextDecoder = new TextDecoder();
utf8Encoder: TextEncoder = new TextEncoder();
core: CoreAPI;
imports!: WebAssembly.Imports;
exports!: T;
core: CoreAPI;

constructor(
public modules: Record<string, IWasmAPI<T>> = {},
Expand Down Expand Up @@ -104,13 +105,10 @@ export class WasmBridge<T extends WasmExports = WasmExports> {
imports?: WebAssembly.Imports
) {
const $src = await src;
const $imports = { ...imports, ...this.getImports() };
let wasm: WebAssembly.WebAssemblyInstantiatedSource;
if ($src instanceof Response) {
wasm = await WebAssembly.instantiateStreaming($src, $imports);
} else {
wasm = await WebAssembly.instantiate($src, $imports);
}
const $imports = { ...this.getImports(), ...imports };
const wasm = await ($src instanceof Response
? WebAssembly.instantiateStreaming($src, $imports)
: WebAssembly.instantiate($src, $imports));
return this.init(<any>wasm.instance.exports);
}

Expand Down Expand Up @@ -148,25 +146,45 @@ export class WasmBridge<T extends WasmExports = WasmExports> {
* API and any provided bridge API modules.
*
* @remarks
* Since all declared imports will be merged into a single flat namespace,
* it's recommended to use per-module naming prefixes to avoid clashes. If
* there're any naming clashes, this function will throw an error.
* Since v0.4.0 each API module's imports will be in their own WASM import
* object, named using the same key which was assigned to the module when
* creating the WASM bridge. The bridge's core API will be named `core` and
* is reserved.
*
* @example
* The following creates a bridge with a fictional `custom` API module:
*
* ```ts
* const bridge = new WasmBridge({ custom: new CustomAPI() });
*
* // get combined imports object
* bridge.getImports();
* {
* // imports defined by the core API of the bridge itself
* core: { ... },
* // imports defined by the CustomAPI module
* custom: { ... }
* }
* ```
*
* Any related API bindings on the WASM (Zig) side then also need to refer
* to these custom import sections (also see `/zig/core.zig`):
*
* ```zig
* pub export "custom" fn foo(x: u32) void;
* ```
*/
getImports(): WebAssembly.Imports {
const env: WebAssembly.ModuleImports = { ...this.core };
for (let id in this.modules) {
const imports = this.modules[id].getImports();
// check for naming clashes
for (let k in imports) {
if (env[k] !== undefined) {
illegalArgs(
`attempt to redeclare import: ${k} by API module ${id}`
);
if (!this.imports) {
this.imports = { core: this.core };
for (let id in this.modules) {
if (this.imports[id] !== undefined) {
illegalArgs(`attempt to redeclare API module ${id}`);
}
this.imports[id] = this.modules[id].getImports();
}
Object.assign(env, imports);
}
return { env };
return this.imports;
}

getI8(addr: number) {
Expand Down
52 changes: 26 additions & 26 deletions packages/wasm-api/zig/core.zig
Original file line number Diff line number Diff line change
@@ -1,77 +1,77 @@
//! JavaScript externals for https://thi.ng/wasm-api

/// Prints number using configured JS logger
pub extern fn printI8(x: i8) void;
pub extern "core" fn printI8(x: i8) void;
/// Prints number using configured JS logger
pub extern fn printU8(x: u8) void;
pub extern "core" fn printU8(x: u8) void;
/// Prints hex number using configured JS logger
pub extern fn printU8Hex(x: u8) void;
pub extern "core" fn printU8Hex(x: u8) void;

/// Prints number using configured JS logger
pub extern fn printI16(x: i16) void;
pub extern "core" fn printI16(x: i16) void;
/// Prints number using configured JS logger
pub extern fn printU16(x: u16) void;
pub extern "core" fn printU16(x: u16) void;
/// Prints hex number using configured JS logger
pub extern fn printU16Hex(x: u16) void;
pub extern "core" fn printU16Hex(x: u16) void;

/// Prints number using configured JS logger
pub extern fn printI32(x: i32) void;
pub extern "core" fn printI32(x: i32) void;
/// Prints number using configured JS logger
pub extern fn printU32(x: u32) void;
pub extern "core" fn printU32(x: u32) void;
/// Prints hex number using configured JS logger
pub extern fn printU32Hex(x: u32) void;
pub extern "core" fn printU32Hex(x: u32) void;

/// Prints decomposed i64 number using configured JS logger
pub extern fn _printI64(hi: i32, lo: i32) void;
pub extern "core" fn _printI64(hi: i32, lo: i32) void;
/// Convenience wrapper for _printI64(), accepting an i64
pub fn printI64(x: i64) void {
_printI64(@truncate(i32, x >> 32), @truncate(i32, x));
}

/// Prints decomposed u64 number using configured JS logger
pub extern fn _printU64(hi: u32, lo: u32) void;
pub extern "core" fn _printU64(hi: u32, lo: u32) void;
/// Convenience wrapper for _printU64(), accepting an u64
pub fn printU64(x: u64) void {
_printU64(@truncate(u32, x >> 32), @truncate(u32, x));
}

/// Prints decomposed u64 hex number using configured JS logger
pub extern fn _printU64Hex(hi: u32, lo: u32) void;
pub extern "core" fn _printU64Hex(hi: u32, lo: u32) void;
/// Convenience wrapper for _printU64Hex(), accepting an u64
pub fn printU64Hex(x: u64) void {
_printU64Hex(@truncate(u32, x >> 32), @truncate(u32, x));
}

/// Prints number using configured JS logger
pub extern fn printF32(x: f32) void;
pub extern "core" fn printF32(x: f32) void;
/// Prints number using configured JS logger
pub extern fn printF64(x: f64) void;
pub extern "core" fn printF64(x: f64) void;

/// Prints pointer as hex number using configured JS logger
pub fn printPtr(ptr: *const anyopaque) void {
printU32Hex(@ptrToInt(ptr));
}

/// Prints number array using configured JS logger
pub extern fn _printI8Array(addr: usize, len: usize) void;
pub extern "core" fn _printI8Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printU8Array(addr: usize, len: usize) void;
pub extern "core" fn _printU8Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printI16Array(addr: usize, len: usize) void;
pub extern "core" fn _printI16Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printU16Array(addr: usize, len: usize) void;
pub extern "core" fn _printU16Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printI32Array(addr: usize, len: usize) void;
pub extern "core" fn _printI32Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printU32Array(addr: usize, len: usize) void;
pub extern "core" fn _printU32Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printI64Array(addr: usize, len: usize) void;
pub extern "core" fn _printI64Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printU64Array(addr: usize, len: usize) void;
pub extern "core" fn _printU64Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printF32Array(addr: usize, len: usize) void;
pub extern "core" fn _printF32Array(addr: usize, len: usize) void;
/// Prints number array using configured JS logger
pub extern fn _printF64Array(addr: usize, len: usize) void;
pub extern "core" fn _printF64Array(addr: usize, len: usize) void;

/// Prints number array using configured JS logger
pub fn printI8Array(buf: []const i8) void {
Expand Down Expand Up @@ -115,9 +115,9 @@ pub fn printF64Array(buf: []const f64) void {
}

/// Prints a zero-terminated string using configured JS logger
extern fn _printStr0(addr: usize) void;
pub extern "core" fn _printStr0(addr: usize) void;
/// Prints a string of given length using configured JS logger
extern fn _printStr(addr: usize, len: usize) void;
pub extern "core" fn _printStr(addr: usize, len: usize) void;
/// Convenience wrapper for _printStr, accepting a slice as arg
pub fn printStr(msg: []const u8) void {
_printStr(@ptrToInt(msg.ptr), msg.len);
Expand Down

0 comments on commit 4965f20

Please sign in to comment.