@thi.ng/wasm-api
Advanced tools
Comparing version 1.6.7 to 2.0.0
54
api.d.ts
@@ -1,2 +0,2 @@ | ||
import type { EVENT_ALL, Fn, IDeref, ILength } from "@thi.ng/api"; | ||
import type { BigTypedArray, EVENT_ALL, Fn, IDeref, ILength, TypedArray, Values } from "@thi.ng/api"; | ||
import type { WasmBridge } from "./bridge.js"; | ||
@@ -56,14 +56,2 @@ export declare const EVENT_MEMORY_CHANGED = "memory-changed"; | ||
/** | ||
* The unique ID for grouping the WASM imports of this module. MUST be the | ||
* same as used by the native side of the module. | ||
*/ | ||
readonly id: string; | ||
/** | ||
* IDs of other WASM API modules which this module depends on. Used to infer | ||
* correct initialization order. The core module (w/ unique ID: `wasmapi`) | ||
* is always considered an implicit dependency, will be initialized first | ||
* and MUST NOT be stated here. | ||
*/ | ||
readonly dependencies?: string[]; | ||
/** | ||
* Called by {@link WasmBridge.init} to initialize all child APIs (async) | ||
@@ -83,2 +71,27 @@ * after the WASM module has been instantiated. If the method returns false | ||
} | ||
export interface WasmModuleSpec<T extends WasmExports = WasmExports> { | ||
/** | ||
* The unique ID for grouping the WASM imports of this module. MUST be the | ||
* same as used by the native side of the module. | ||
*/ | ||
id: string; | ||
/** | ||
* Optional array of other {@link WasmModuleSpec}s which this module depends | ||
* on (element order is irrelevant). Used to construct a module dependency | ||
* graph and the correct initialization order of modules. The core module | ||
* (defined via {@link WasmBridge} w/ unique ID: `wasmapi`) is always | ||
* considered an implicit dependency, will be initialized first and MUST NOT | ||
* be stated here. | ||
*/ | ||
deps?: WasmModuleSpec<T>[]; | ||
/** | ||
* Factory function to pre-instantiate the API module. | ||
* | ||
* @remarks | ||
* Note: All modules will only be fully initialized at a later point via | ||
* {@link WasmBridge.instantiate} or {@link WasmBridge.init} and each | ||
* modules own {@link IWasmAPI.init} method. | ||
*/ | ||
factory: Fn<WasmBridge<T>, IWasmAPI<T>>; | ||
} | ||
/** | ||
@@ -138,2 +151,17 @@ * Base interface of exports declared by the WASM module. At the very least, a | ||
export type MemorySlice = [addr: number, len: number]; | ||
export type MemoryViewType = "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "f32" | "f64"; | ||
export interface MemoryViewTypeMap extends Record<MemoryViewType, TypedArray | BigTypedArray> { | ||
u8: Uint8Array; | ||
u8c: Uint8ClampedArray; | ||
i8: Int8Array; | ||
u16: Uint16Array; | ||
i16: Int16Array; | ||
u32: Uint32Array; | ||
i32: Int32Array; | ||
i64: BigInt64Array; | ||
u64: BigUint64Array; | ||
f32: Float32Array; | ||
f64: Float64Array; | ||
} | ||
export type MemoryView = Values<MemoryViewTypeMap>; | ||
export interface IWasmMemoryAccess { | ||
@@ -140,0 +168,0 @@ i8: Int8Array; |
import type { Event, INotify, IObjectOf, Listener, NumericArray } from "@thi.ng/api"; | ||
import type { ILogger } from "@thi.ng/logger"; | ||
import { type BigIntArray, type BridgeEventType, type CoreAPI, type IWasmAPI, type IWasmMemoryAccess, type MemorySlice, type WasmExports } from "./api.js"; | ||
import { type BigIntArray, type BridgeEventType, type CoreAPI, type IWasmAPI, type IWasmMemoryAccess, type MemorySlice, type WasmExports, type WasmModuleSpec } from "./api.js"; | ||
export declare const Panic: { | ||
@@ -63,4 +63,18 @@ new (msg?: string | undefined): { | ||
modules: IObjectOf<IWasmAPI<T>>; | ||
constructor(modules?: IWasmAPI<T>[], logger?: ILogger); | ||
order: string[]; | ||
constructor(modules?: WasmModuleSpec<T>[], logger?: ILogger); | ||
/** | ||
* Takes array of root module specs, extracts all transitive dependencies, | ||
* pre-computes their topological order, then calls | ||
* {@link WasmModuleSpec.factory} for each module and stores all modules for | ||
* future reference. | ||
* | ||
* @remarks | ||
* Note: The pre-instantiated modules will only be fully initialized later | ||
* via {@link WasmBridge.instantiate} or {@link WasmBridge.init}. | ||
* | ||
* @param specs | ||
*/ | ||
protected _buildModuleGraph(specs: WasmModuleSpec<T>[]): void; | ||
/** | ||
* Instantiates WASM module from given `src` (and optional provided extra | ||
@@ -67,0 +81,0 @@ * imports), then automatically calls {@link WasmBridge.init} with the |
@@ -73,10 +73,3 @@ var __defProp = Object.defineProperty; | ||
}; | ||
this.modules = modules.reduce((acc, x) => { | ||
assert( | ||
acc[x.id] === void 0 && x.id !== this.id, | ||
`duplicate API module ID: ${x.id}` | ||
); | ||
acc[x.id] = x; | ||
return acc; | ||
}, {}); | ||
this._buildModuleGraph(modules); | ||
} | ||
@@ -100,3 +93,41 @@ id = "wasmapi"; | ||
modules; | ||
order; | ||
/** | ||
* Takes array of root module specs, extracts all transitive dependencies, | ||
* pre-computes their topological order, then calls | ||
* {@link WasmModuleSpec.factory} for each module and stores all modules for | ||
* future reference. | ||
* | ||
* @remarks | ||
* Note: The pre-instantiated modules will only be fully initialized later | ||
* via {@link WasmBridge.instantiate} or {@link WasmBridge.init}. | ||
* | ||
* @param specs | ||
*/ | ||
_buildModuleGraph(specs) { | ||
const unique = /* @__PURE__ */ new Set(); | ||
const queue = [...specs]; | ||
while (queue.length) { | ||
const mod = queue.shift(); | ||
unique.add(mod); | ||
if (!mod.deps) continue; | ||
for (let d of mod.deps) { | ||
if (!unique.has(d)) queue.push(d); | ||
} | ||
} | ||
const graph = [...unique].reduce((acc, mod) => { | ||
assert( | ||
(acc[mod.id] === void 0 || acc[mod.id] === mod) && mod.id !== this.id, | ||
`duplicate API module ID: ${mod.id}` | ||
); | ||
acc[mod.id] = mod; | ||
return acc; | ||
}, {}); | ||
this.order = topoSort(graph, (mod) => mod.deps?.map((x) => x.id)); | ||
this.modules = this.order.reduce((acc, id) => { | ||
acc[id] = graph[id].factory(this); | ||
return acc; | ||
}, {}); | ||
} | ||
/** | ||
* Instantiates WASM module from given `src` (and optional provided extra | ||
@@ -135,7 +166,3 @@ * imports), then automatically calls {@link WasmBridge.init} with the | ||
this.ensureMemory(false); | ||
for (let id of topoSort( | ||
this.modules, | ||
(module) => module.dependencies | ||
)) { | ||
assert(!!this.modules[id], `missing API module: ${id}`); | ||
for (let id of this.order) { | ||
this.logger.debug(`initializing API module: ${id}`); | ||
@@ -142,0 +169,0 @@ const status = await this.modules[id].init(this); |
# Change Log | ||
- **Last updated**: 2024-08-10T15:03:07Z | ||
- **Last updated**: 2024-08-18T14:11:34Z | ||
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub) | ||
@@ -12,2 +12,28 @@ | ||
# [2.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@2.0.0) (2024-08-18) | ||
#### 🛑 Breaking changes | ||
- update WASM module dependency handling ([31f0358](https://github.com/thi-ng/umbrella/commit/31f0358)) | ||
- BREAKING CHANGE: update WASM module dependency handling | ||
- add `WasmModuleSpec` interface to declare WASM modules with their deps | ||
- update `WasmBridge` ctor to accept array of module specs | ||
- add buildModuleGraph() to process dependencies & init modules from specs | ||
- add/update docstrings | ||
- update tests | ||
#### 🚀 Features | ||
- add ObjectIndex.addUnique() ([e79275d](https://github.com/thi-ng/umbrella/commit/e79275d)) | ||
- add MemoryView types ([b621adc](https://github.com/thi-ng/umbrella/commit/b621adc)) | ||
- add internal memory view accessors ([6830337](https://github.com/thi-ng/umbrella/commit/6830337)) | ||
- these accessors are shared by various types generated via [@thi.ng/wasm-api-bindgen](https://github.com/thi-ng/umbrella/tree/main/packages/wasm-api-bindgen) | ||
and help to drastically cut down filesize of generated code | ||
- update pkg exports | ||
- update ObjectIndex ctor, make opts fully optional ([564e0f3](https://github.com/thi-ng/umbrella/commit/564e0f3)) | ||
#### ♻️ Refactoring | ||
- update internal array mem accessors ([b442d92](https://github.com/thi-ng/umbrella/commit/b442d92)) | ||
## [1.6.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@1.6.0) (2024-06-21) | ||
@@ -14,0 +40,0 @@ |
export * from "./api.js"; | ||
export * from "./bridge.js"; | ||
export * from "./memory.js"; | ||
export * from "./object-index.js"; | ||
@@ -4,0 +5,0 @@ export * from "./pointer.js"; |
export * from "./api.js"; | ||
export * from "./bridge.js"; | ||
export * from "./memory.js"; | ||
export * from "./object-index.js"; | ||
export * from "./pointer.js"; | ||
export * from "./string.js"; |
@@ -12,3 +12,3 @@ import type { Maybe, Predicate, Range1_32 } from "@thi.ng/api"; | ||
*/ | ||
logger?: ILogger; | ||
logger: ILogger; | ||
/** | ||
@@ -19,4 +19,10 @@ * Number of bits for IDs, [1..32] range. | ||
*/ | ||
bits?: Range1_32; | ||
bits: Range1_32; | ||
} | ||
/** | ||
* Object cache with numeric ID handle management. | ||
* | ||
* @remarks | ||
* [Further reference](https://docs.thi.ng/umbrella/wasm-api/#md:object-indices--handles) | ||
*/ | ||
export declare class ObjectIndex<T> { | ||
@@ -27,3 +33,3 @@ readonly name: string; | ||
protected items: T[]; | ||
constructor(opts: ObjectIndexOpts); | ||
constructor(opts?: Partial<ObjectIndexOpts>); | ||
keys(): Generator<number, void, unknown>; | ||
@@ -39,2 +45,15 @@ values(): Generator<T, void, unknown>; | ||
/** | ||
* Similar to {@link ObjectIndex.add}, but first checks if `item` has | ||
* already been indexed and if so returns the ID of already indexed item | ||
* without adding `item` to the index again. Uses `equiv` for checking item | ||
* equality (by default: `===`). | ||
* | ||
* @remarks | ||
* Currently an O(n) implementation. | ||
* | ||
* @param item | ||
* @param equiv | ||
*/ | ||
addUnique(item: T, equiv?: Predicate<T>): number; | ||
/** | ||
* Returns true if the given `id` is valid/active. | ||
@@ -41,0 +60,0 @@ * |
import { assert } from "@thi.ng/errors/assert"; | ||
import { IDGen } from "@thi.ng/idgen"; | ||
let __nextID = 0; | ||
class ObjectIndex { | ||
@@ -9,5 +10,5 @@ name; | ||
constructor(opts) { | ||
this.name = opts.name; | ||
this.logger = opts.logger; | ||
this.idgen = new IDGen(opts.bits || 32, 0); | ||
this.name = opts?.name ?? `idx-${__nextID++}`; | ||
this.logger = opts?.logger; | ||
this.idgen = new IDGen(opts?.bits ?? 32, 0); | ||
} | ||
@@ -35,2 +36,18 @@ keys() { | ||
/** | ||
* Similar to {@link ObjectIndex.add}, but first checks if `item` has | ||
* already been indexed and if so returns the ID of already indexed item | ||
* without adding `item` to the index again. Uses `equiv` for checking item | ||
* equality (by default: `===`). | ||
* | ||
* @remarks | ||
* Currently an O(n) implementation. | ||
* | ||
* @param item | ||
* @param equiv | ||
*/ | ||
addUnique(item, equiv = (x) => x === item) { | ||
const id = this.find(equiv, false); | ||
return id === void 0 ? this.add(item) : id; | ||
} | ||
/** | ||
* Returns true if the given `id` is valid/active. | ||
@@ -37,0 +54,0 @@ * |
{ | ||
"name": "@thi.ng/wasm-api", | ||
"version": "1.6.7", | ||
"version": "2.0.0", | ||
"description": "Generic, modular, extensible API bridge and infrastructure for hybrid JS & WebAssembly projects", | ||
@@ -40,9 +40,9 @@ "type": "module", | ||
"dependencies": { | ||
"@thi.ng/api": "^8.11.8", | ||
"@thi.ng/arrays": "^2.9.14", | ||
"@thi.ng/checks": "^3.6.10", | ||
"@thi.ng/errors": "^2.5.14", | ||
"@thi.ng/hex": "^2.3.52", | ||
"@thi.ng/idgen": "^2.2.48", | ||
"@thi.ng/logger": "^3.0.18" | ||
"@thi.ng/api": "^8.11.9", | ||
"@thi.ng/arrays": "^2.10.0", | ||
"@thi.ng/checks": "^3.6.11", | ||
"@thi.ng/errors": "^2.5.15", | ||
"@thi.ng/hex": "^2.3.53", | ||
"@thi.ng/idgen": "^2.2.49", | ||
"@thi.ng/logger": "^3.0.19" | ||
}, | ||
@@ -106,2 +106,5 @@ "devDependencies": { | ||
}, | ||
"./memory": { | ||
"default": "./memory.js" | ||
}, | ||
"./object-index": { | ||
@@ -121,3 +124,3 @@ "default": "./object-index.js" | ||
}, | ||
"gitHead": "ec78f98d015e4d214a0b840e72e497407807daf3\n" | ||
"gitHead": "f6e26ea1142525171de5d36b9c3119f2782bb437\n" | ||
} |
178
README.md
@@ -10,3 +10,3 @@ <!-- This file is generated - DO NOT EDIT! --> | ||
> [!NOTE] | ||
> This is one of 198 standalone projects, maintained as part | ||
> This is one of 199 standalone projects, maintained as part | ||
> of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo | ||
@@ -19,2 +19,3 @@ > and anti-framework. | ||
- [About](#about) | ||
- [Polyglot bindings generator](#polyglot-bindings-generator) | ||
- [Custom API modules](#custom-api-modules) | ||
@@ -51,9 +52,12 @@ - [String handling](#string-handling) | ||
This package provides the following: | ||
This package form the core of a larger WASM toolkit which includes a polyglot | ||
bindings generator and a growing number of API modules to interop with different | ||
browser APIs. This core package provides the following: | ||
1. A small | ||
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html) | ||
class as generic interop basis and much reduced boilerplate for hybrid JS/WebAssembly | ||
applications. | ||
2. A minimal core API for debug output, string/pointer/typedarray accessors for | ||
class as generic interop basis and much reduced boilerplate for hybrid | ||
JS/WebAssembly applications. | ||
2. Child WASM API modules with dependency graph resolution & initialization | ||
3. A minimal core API for debug output, string/pointer/typedarray accessors for | ||
8/16/32/64 bit (u)ints and 32/64 bit floats. Additionally, a number of support | ||
@@ -65,5 +69,4 @@ modules for [DOM | ||
WebGL, WebGPU, WebAudio etc. is being actively worked on. | ||
3. Different types of memory-mapped (UTF-8) string abstractions (slice or pointer based) | ||
4. Different types of memory-mapped (UTF-8) string abstractions (slice or pointer based) | ||
5. Shared (opt-in) memory allocation mechanism, also accessible from JS/TS side | ||
4. Simple registration & dependency-order initialization for child WASM API modules | ||
6. Include files for | ||
@@ -78,12 +81,14 @@ [Zig](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api/zig), | ||
TS/Zig packages with the built-in build system | ||
8. Extensible shared [datatype code generator | ||
infrastructure](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-bindgen/) | ||
for (currently) Zig & TypeScript and C11. For TS fully type checked and | ||
memory-mapped (zero-copy) accessors of WASM-side data are generated. In | ||
principle, all languages with a WASM target are supported, however currently | ||
only bindings for these mentioned langs are included. | ||
9. [CLI | ||
frontend/utility](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen/README.md#cli-generator) | ||
for the code generator(s) | ||
## Polyglot bindings generator | ||
The toolkit includes an extensible [code | ||
generator](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-bindgen/) | ||
for shared datatypes and (currently) supports Zig & TypeScript and C11. For TS | ||
fully type checked and memory-mapped (mostly zero-copy) accessors of WASM-side | ||
data are generated. In principle, all languages with a WASM target are | ||
supported, however currently only bindings for the languages mentioned are | ||
included. The codegen also includes a [CLI | ||
frontend/utility](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen/README.md#cli-generator). | ||
## Custom API modules | ||
@@ -93,28 +98,67 @@ | ||
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html) | ||
can be extented via custom defined API modules. Such API extensions will consist | ||
can be extented via custom defined API modules. Such child modules will consist | ||
of a collection of JS/TS functions & variables, their related counterparts | ||
(import definitions) for the WASM target and (optionally) some shared data types | ||
([bindings for which _can_ be generated by this package | ||
too](#data-bindings--code-generators)). | ||
([bindings for which can be generated via | ||
thi.ng/wasm-api-bindgen](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen)). | ||
On the JS side, custom API modules can be easily integrated via the [`IWasmAPI` | ||
interface](https://docs.thi.ng/umbrella/wasm-api/interfaces/IWasmAPI.html). The | ||
following example provides a brief overview: | ||
On the JS side, custom API extensions can be easily integrated and exposed via | ||
the [`IWasmAPI` | ||
interface](https://docs.thi.ng/umbrella/wasm-api/interfaces/IWasmAPI.html) and | ||
their module descriptors via | ||
[`WasmModuleSpec`](https://docs.thi.ng/umbrella/wasm-api/interfaces/WasmModuleSpec.html). | ||
The following example provides a brief overview: | ||
```ts | ||
import { IWasmAPI, WasmBridge } from "@thi.ng/wasm-api"; | ||
import { WasmBridge, type IWasmAPI, type WasmModuleSpec } from "@thi.ng/wasm-api"; | ||
import { WasmDomModule, type WasmDom, type WasmDomExports } from "@thi.ng/wasm-api-dom"; | ||
export class CustomAPI implements IWasmAPI { | ||
// Unique API module identifier to group WASM imports, | ||
// must match ID used by native code (see further below). | ||
readonly id = "custom"; | ||
// optionally list IDs of other API modules this module depends on | ||
// these are used to infer the correct initialization order | ||
readonly dependencies = []; | ||
export const CustomModule: WasmModuleSpec = { | ||
// Unique API module identifier to group WASM imports, must match ID used | ||
// by the native code (see further below). | ||
id: "custom", | ||
// Optional array of API modules this module depends on. This is used to | ||
// infer the full dependency graph and correct initialization order. | ||
// Note: Each of the wasm-api support packages includes a module spec... | ||
depes: [WasmDomModule], | ||
// Factory function to pre-instantiate the API module. Full initialization | ||
// only happens at a later point via WasmBridge.instantiate() or | ||
// WasmBridge.init() and each module's own init() method... | ||
factory: () => new CustomAPI(), | ||
}; | ||
// Optional declarations for JS-side functions which can be used from the WASM side. | ||
// Using an interface for this is useful to establish a contract. | ||
export interface CustomImports extends WebAssembly.ModuleImports { | ||
/** | ||
* Writes `num` random float32 numbers from given address | ||
*/ | ||
fillRandom(addr: number, num: number): void; | ||
} | ||
// Optional (but likely used) interface declarations of functions exposed | ||
// by the WASM binary and callable from the JS side (i.e. the opposite of the above) | ||
// | ||
// Note: If your module has dependencies on other modules you should declare | ||
// your exports as extension of these other module's exports for better | ||
// downstream developer experience | ||
export interface CustomWasmExports extends WasmDomExports { | ||
// ... | ||
} | ||
// Actual custom API extension implentation | ||
export class CustomAPI implements IWasmAPI<CustomWasmExports> { | ||
parent!: WasmBridge; | ||
dom!: WasmDom; | ||
/** | ||
* Actual module initialization, called from the main WasmBridge which | ||
* initializes all modules in dependency order... | ||
*/ | ||
async init(parent: WasmBridge) { | ||
this.parent = parent; | ||
this.parent.logger.debug("initializing custom API"); | ||
// Store a direct reference to the DOM module for future ref | ||
// (just shown as example, we're not actually using this module here...) | ||
this.dom = <WasmDom>this.parent.modules[WasmDomModule.id]; | ||
@@ -127,11 +171,11 @@ // any other tasks you might need to do... | ||
/** | ||
* Returns object of functions to import as externals into the | ||
* WASM module during instantiation. These imports are merged | ||
* into a larger imports object alongside the bridge's core API... | ||
* Returns object of functions/constants to import as externals into the | ||
* WASM module during instantiation. These imports are merged into a | ||
* larger imports object alongside the bridge's core API... | ||
* | ||
* Each module's imports will be grouped by its declared module ID, which | ||
* also needs to be used to declare extern functions on the WASM side. | ||
*/ | ||
getImports(): WebAssembly.Imports { | ||
getImports(): CustomImports { | ||
return { | ||
/** | ||
* Writes `num` random float32 numbers from given address | ||
*/ | ||
fillRandom: (addr: number, num: number) => { | ||
@@ -146,9 +190,8 @@ addr >>>= 2; | ||
// now we can supply this custom API when creating the main WASM bridge: | ||
export const bridge = new WasmBridge([new CustomAPI()]); | ||
export const bridge = new WasmBridge([CustomModule]); | ||
``` | ||
In Zig (or any other language of your choice) we can then utilize this custom | ||
API like so (Please also see [example | ||
projects](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-canvas/) | ||
& other example snippets in this readme): | ||
API like so (Please also see [example projects](#usage-examples) & other code | ||
snippets in this readme): | ||
@@ -166,2 +209,7 @@ Bindings file / lib: | ||
extern "custom" fn fillRandom(addr: [*]f32, num: usize) void; | ||
/// Syntax sugar for `fillRandom()` | ||
pub fn fillRandomSlice(slice: []f32) void { | ||
fillRandom(slice.ptr, slice.len); | ||
} | ||
``` | ||
@@ -173,3 +221,3 @@ | ||
// Import JS core API | ||
const js = @import("wasm-api"); | ||
const wasm = @import("wasm-api"); | ||
const custom = @import("custom.zig"); | ||
@@ -181,9 +229,9 @@ | ||
// print original | ||
js.printF32Array(foo[0..]); | ||
wasm.printF32Array(foo[0..]); | ||
// populate foo with random numbers | ||
custom.fillRandom(&foo, foo.len); | ||
custom.fillRandomSlice(foo[0..]); | ||
// print result | ||
js.printF32Array(foo[0..]); | ||
wasm.printF32Array(foo[0..]); | ||
} | ||
@@ -271,22 +319,25 @@ ``` | ||
allocator is defined and/or a custom allocator should be used, then these API | ||
modules will be have to be initialized manually. | ||
modules will have to be initialized manually. | ||
## Object indices & handles | ||
Since only numeric values can be exchanged between the WASM module and the JS | ||
host, any JS native objects the WASM side might want to be working with must be | ||
managed manually in JS. For this purpose the [`ObjectIndex` | ||
Since only numeric values can be directly passed between the WASM module and the | ||
JS host, any JS native objects the WASM side might want to be working with must | ||
be managed manually in JS. For this purpose the [`ObjectIndex` | ||
class](https://docs.thi.ng/umbrella/wasm-api/classes/ObjectIndex.html) can be | ||
used by API modules to handle ID generation (incl. recycling, using | ||
[@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen)) | ||
and the indexing of different types of JS objects/values. Only the numeric IDs | ||
(handles) will then need to be exchanged with the WASM module... | ||
used by API modules to handle the indexing of different types of JS | ||
objects/values and their ID generation (incl. recycling of IDs, using | ||
[@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen)). | ||
Using this approach, only the numeric IDs (handles) will then need to be | ||
exchanged with the WASM module... | ||
```ts | ||
import { ObjectIndex } from "@thi.ng/wasm-api"; | ||
import { ConsoleLogger } from "@thi.ng/logger"; | ||
// create index (see API docs for options) | ||
const canvases = new ObjectIndex<HTMLCanvasElement>({ name: "canvas" }); | ||
// index item and assign new ID | ||
canvases.add(document.createElement("canvas")); | ||
canvases.add(<HTMLCanvasElement>document.createElement("canvas")); | ||
// 0 | ||
@@ -298,2 +349,8 @@ | ||
// by default, items to be indexed are not checked for equality | ||
// but we can use the below to ensure double indexing is avoided... | ||
// (supports custom predicates to check for equality) | ||
canvases.addUnique(canvases.get(0)); | ||
// 0 (returned already known ID) | ||
// work w/ retrieved item | ||
@@ -342,4 +399,4 @@ canvases.get(0).id = "foo"; | ||
[v0.13.0](https://ziglang.org/download/0.13.0/release-notes.html), older Zig | ||
versions are not actively supported (however, [build files for older versions | ||
are still | ||
versions are not actively supported anymore (however, [build files for older | ||
versions are still | ||
included](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/zig)) | ||
@@ -376,4 +433,3 @@ | ||
All bundled example projects (see [list below](#usage-examples)) are being built | ||
via this script. **Please find more details/options in the commented source | ||
code:** | ||
via this script. **More details/options in the commented source code:** | ||
@@ -400,2 +456,3 @@ - [`/zig/build.zig`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/zig/build.zig) | ||
- [@thi.ng/wasm-api-schedule](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-schedule) - Delayed & scheduled function execution (via setTimeout() etc.) for hybrid WASM apps | ||
- [@thi.ng/wasm-api-webgl](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-webgl) - WebGL bridge API for hybrid TypeScript & WASM (Zig) applications | ||
@@ -422,3 +479,3 @@ ## Installation | ||
Package sizes (brotli'd, pre-treeshake): ESM: 2.69 KB | ||
Package sizes (brotli'd, pre-treeshake): ESM: 3.00 KB | ||
@@ -439,3 +496,3 @@ ## Dependencies | ||
Four projects in this repo's | ||
Five projects in this repo's | ||
[/examples](https://github.com/thi-ng/umbrella/tree/develop/examples) | ||
@@ -450,2 +507,3 @@ directory are using this package: | ||
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-todo-list.png" width="240"/> | Zig-based To-Do list, DOM creation, local storage task persistence | [Demo](https://demo.thi.ng/umbrella/zig-todo-list/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-todo-list) | | ||
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-webgl.avif" width="240"/> | Basic Zig/WebAssembly WebGL demo | [Demo](https://demo.thi.ng/umbrella/zig-webgl/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-webgl) | | ||
@@ -452,0 +510,0 @@ ## API |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
176048
1632
616
1
56
31
1
Updated@thi.ng/api@^8.11.9
Updated@thi.ng/arrays@^2.10.0
Updated@thi.ng/checks@^3.6.11
Updated@thi.ng/errors@^2.5.15
Updated@thi.ng/hex@^2.3.53
Updated@thi.ng/idgen@^2.2.49
Updated@thi.ng/logger@^3.0.19