@thi.ng/wasm-api 1.6.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -1
- package/README.md +118 -60
- package/api.d.ts +41 -13
- package/bridge.d.ts +16 -2
- package/bridge.js +40 -13
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/memory.d.ts +14 -0
- package/memory.js +40 -0
- package/object-index.d.ts +22 -3
- package/object-index.js +20 -3
- package/package.json +12 -9
- package/zig/.zig-cache/z/53d8da468c12563c8ba398391b5e75e7 +0 -0
- package/zig/.zig-cache/tmp/0d9630e458f496b4/build +0 -0
- package/zig/.zig-cache/tmp/1d7d03c03ea37492/build +0 -0
- package/zig/.zig-cache/tmp/3946003e031e6f2d/build +0 -0
- package/zig/.zig-cache/tmp/44408331dcb9625f/build +0 -0
- package/zig/.zig-cache/tmp/5da4e501f0b1dec3/build +0 -0
- package/zig/.zig-cache/tmp/8204f942d1b78e57/build +0 -0
- package/zig/.zig-cache/tmp/8e6e9ee6f0c3a9ed/build +0 -0
- package/zig/.zig-cache/tmp/99f07abb0b44ff6e/build +0 -0
- package/zig/.zig-cache/tmp/9b11f06a25b08ec8/build +0 -0
- package/zig/.zig-cache/tmp/9e6b7db30c645e00/build +0 -0
- package/zig/.zig-cache/tmp/a38e6b0ab4712e40/build +0 -0
- package/zig/.zig-cache/tmp/b13ac822bd6aa967/build +0 -0
- package/zig/.zig-cache/tmp/e23560c26cbc775d/build +0 -0
- package/zig/.zig-cache/tmp/f908b8bbbbb51e24/build +0 -0
- package/zig/zig-cache/h/bc052b73addda9fe899d4556c8f21a5c.txt +0 -0
- package/zig/zig-cache/h/timestamp +0 -0
- package/zig/zig-cache/o/20f8f8362ac39302905d03992fa818bc/dependencies.zig +0 -2
- package/zig/zig-cache/tmp/0696373596682bd9/build +0 -0
- package/zig/zig-cache/tmp/06fd7da717810606/build +0 -0
- package/zig/zig-cache/tmp/0a39f7dbdddbea21/build +0 -0
- package/zig/zig-cache/tmp/0f72c6fd825322f3/build +0 -0
- package/zig/zig-cache/tmp/119286fc10b777f9/build +0 -0
- package/zig/zig-cache/tmp/1891fd08324fa403/build +0 -0
- package/zig/zig-cache/tmp/1eb500fac3d5ce62/build +0 -0
- package/zig/zig-cache/tmp/2043d7dd4743109c/build +0 -0
- package/zig/zig-cache/tmp/224ea1ba9258bfe3/build +0 -0
- package/zig/zig-cache/tmp/25343e986edbd1ad/build +0 -0
- package/zig/zig-cache/tmp/2d366ba992d14d5f/build +0 -0
- package/zig/zig-cache/tmp/2ddcd2b8d14b81eb/build +0 -0
- package/zig/zig-cache/tmp/2dfe9a721aef8bbd/build +0 -0
- package/zig/zig-cache/tmp/306b574d8ec701bf/build +0 -0
- package/zig/zig-cache/tmp/3411e025a5f335c7/build +0 -0
- package/zig/zig-cache/tmp/3b7519b048bc31f6/build +0 -0
- package/zig/zig-cache/tmp/4b5e6a399cb5aee9/build +0 -0
- package/zig/zig-cache/tmp/4fb96aef1e2a7ae7/build +0 -0
- package/zig/zig-cache/tmp/527925617da9c3dd/build +0 -0
- package/zig/zig-cache/tmp/56dbc6d60b6441e9/build +0 -0
- package/zig/zig-cache/tmp/57954e69e2d9522f/build +0 -0
- package/zig/zig-cache/tmp/57cb18f507029d64/build +0 -0
- package/zig/zig-cache/tmp/5d8fe28f3373c9ca/build +0 -0
- package/zig/zig-cache/tmp/65c1c50c9b1018bd/build +0 -0
- package/zig/zig-cache/tmp/6977aca430f59bc9/build +0 -0
- package/zig/zig-cache/tmp/6c0722b71c685402/build +0 -0
- package/zig/zig-cache/tmp/6c4ec579c09d1f80/build +0 -0
- package/zig/zig-cache/tmp/6eae82521f2631ac/build +0 -0
- package/zig/zig-cache/tmp/6f62ac363f21537f/build +0 -0
- package/zig/zig-cache/tmp/7556d654f70c4ae9/build +0 -0
- package/zig/zig-cache/tmp/7ae3fef48d8f3ada/build +0 -0
- package/zig/zig-cache/tmp/7fd336b7694ba54b/build +0 -0
- package/zig/zig-cache/tmp/899150dbae119836/build +0 -0
- package/zig/zig-cache/tmp/913281630cad1c0a/build +0 -0
- package/zig/zig-cache/tmp/927255f410775c17/build +0 -0
- package/zig/zig-cache/tmp/956b7aafe87eed23/build +0 -0
- package/zig/zig-cache/tmp/97e4f8c36515e21c/build +0 -0
- package/zig/zig-cache/tmp/9de1ed1e5e51add9/build +0 -0
- package/zig/zig-cache/tmp/a051bffb2bb19130/build +0 -0
- package/zig/zig-cache/tmp/a2d24144aa720ff5/build +0 -0
- package/zig/zig-cache/tmp/a6450c98790914aa/build +0 -0
- package/zig/zig-cache/tmp/a7851baacd09b97e/build +0 -0
- package/zig/zig-cache/tmp/a9620e90f7f21f27/build +0 -0
- package/zig/zig-cache/tmp/a9d0ae4a598bbae7/build +0 -0
- package/zig/zig-cache/tmp/adc434dfc8cff980/build +0 -0
- package/zig/zig-cache/tmp/b5906f3589d7a44e/build +0 -0
- package/zig/zig-cache/tmp/b92139a1c898f577/build +0 -0
- package/zig/zig-cache/tmp/bae01421ea15bdba/build +0 -0
- package/zig/zig-cache/tmp/bb366772a50163c4/build +0 -0
- package/zig/zig-cache/tmp/c2d91fef7812604a/build +0 -0
- package/zig/zig-cache/tmp/ca6f88cc7990ad70/build +0 -0
- package/zig/zig-cache/tmp/ce13ae17f06e2897/build +0 -0
- package/zig/zig-cache/tmp/d24e82056000cd3c/build +0 -0
- package/zig/zig-cache/tmp/d2d6630e2babce19/build +0 -0
- package/zig/zig-cache/tmp/d64ec8b30efbd39c/build +0 -0
- package/zig/zig-cache/tmp/db4af70a9676f22f/build +0 -0
- package/zig/zig-cache/tmp/dfc96c446ee3d83c/build +0 -0
- package/zig/zig-cache/tmp/e02fe3c9c8a1234f/build +0 -0
- package/zig/zig-cache/tmp/e1245d4f3790795e/build +0 -0
- package/zig/zig-cache/tmp/e680fd8b7b04a063/build +0 -0
- package/zig/zig-cache/tmp/ed7c14c98bd9f25f/build +0 -0
- package/zig/zig-cache/tmp/f26e509f102208e6/build +0 -0
- package/zig/zig-cache/tmp/f8720cafd74033d4/build +0 -0
- package/zig/zig-cache/tmp/fac1b43e1ee19272/build +0 -0
- package/zig/zig-cache/tmp/fb98957abd64e116/build +0 -0
- package/zig/zig-cache/tmp/fc4e6e1289006215/build +0 -0
- package/zig/zig-cache/tmp/fcb97051d8caa0cc/build +0 -0
- /package/zig/.zig-cache/h/{7cd9f9fd941f2892ab224c4945ba076c.txt → 34a475bf928ad516cafd7711e8a32f5d.txt} +0 -0
- /package/zig/.zig-cache/tmp/{0a4dffdc5a15f6d6 → 37deb3ceec94f9fa}/build +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-08-
|
|
3
|
+
- **Last updated**: 2024-08-18T14:11:34Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,32 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
# [2.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@2.0.0) (2024-08-18)
|
|
13
|
+
|
|
14
|
+
#### 🛑 Breaking changes
|
|
15
|
+
|
|
16
|
+
- update WASM module dependency handling ([31f0358](https://github.com/thi-ng/umbrella/commit/31f0358))
|
|
17
|
+
- BREAKING CHANGE: update WASM module dependency handling
|
|
18
|
+
- add `WasmModuleSpec` interface to declare WASM modules with their deps
|
|
19
|
+
- update `WasmBridge` ctor to accept array of module specs
|
|
20
|
+
- add buildModuleGraph() to process dependencies & init modules from specs
|
|
21
|
+
- add/update docstrings
|
|
22
|
+
- update tests
|
|
23
|
+
|
|
24
|
+
#### 🚀 Features
|
|
25
|
+
|
|
26
|
+
- add ObjectIndex.addUnique() ([e79275d](https://github.com/thi-ng/umbrella/commit/e79275d))
|
|
27
|
+
- add MemoryView types ([b621adc](https://github.com/thi-ng/umbrella/commit/b621adc))
|
|
28
|
+
- add internal memory view accessors ([6830337](https://github.com/thi-ng/umbrella/commit/6830337))
|
|
29
|
+
- 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)
|
|
30
|
+
and help to drastically cut down filesize of generated code
|
|
31
|
+
- update pkg exports
|
|
32
|
+
- update ObjectIndex ctor, make opts fully optional ([564e0f3](https://github.com/thi-ng/umbrella/commit/564e0f3))
|
|
33
|
+
|
|
34
|
+
#### ♻️ Refactoring
|
|
35
|
+
|
|
36
|
+
- update internal array mem accessors ([b442d92](https://github.com/thi-ng/umbrella/commit/b442d92))
|
|
37
|
+
|
|
12
38
|
## [1.6.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@1.6.0) (2024-06-21)
|
|
13
39
|
|
|
14
40
|
#### 🚀 Features
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://mastodon.thi.ng/@toxi)
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
|
-
> This is one of
|
|
10
|
+
> This is one of 199 standalone projects, maintained as part
|
|
11
11
|
> of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
|
|
12
12
|
> and anti-framework.
|
|
13
13
|
>
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
> GitHub](https://github.com/sponsors/postspectacular). Thank you! ❤️
|
|
16
16
|
|
|
17
17
|
- [About](#about)
|
|
18
|
+
- [Polyglot bindings generator](#polyglot-bindings-generator)
|
|
18
19
|
- [Custom API modules](#custom-api-modules)
|
|
19
20
|
- [String handling](#string-handling)
|
|
20
21
|
- [Memory allocations](#memory-allocations)
|
|
@@ -46,22 +47,24 @@ Generic, modular, extensible API bridge and infrastructure for hybrid JS & WebAs
|
|
|
46
47
|
|
|
47
48
|
(Screenshots of selected projects made with Zig & TypeScript using the interop features provided by this package. Images link to respective project info)
|
|
48
49
|
|
|
49
|
-
This package
|
|
50
|
+
This package form the core of a larger WASM toolkit which includes a polyglot
|
|
51
|
+
bindings generator and a growing number of API modules to interop with different
|
|
52
|
+
browser APIs. This core package provides the following:
|
|
50
53
|
|
|
51
54
|
1. A small
|
|
52
55
|
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html)
|
|
53
|
-
class as generic interop basis and much reduced boilerplate for hybrid
|
|
54
|
-
applications.
|
|
55
|
-
2.
|
|
56
|
+
class as generic interop basis and much reduced boilerplate for hybrid
|
|
57
|
+
JS/WebAssembly applications.
|
|
58
|
+
2. Child WASM API modules with dependency graph resolution & initialization
|
|
59
|
+
3. A minimal core API for debug output, string/pointer/typedarray accessors for
|
|
56
60
|
8/16/32/64 bit (u)ints and 32/64 bit floats. Additionally, a number of support
|
|
57
61
|
modules for [DOM
|
|
58
62
|
manipulation](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-dom/),
|
|
59
63
|
[scheduled function
|
|
60
64
|
execution](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-schedule/),
|
|
61
65
|
WebGL, WebGPU, WebAudio etc. is being actively worked on.
|
|
62
|
-
|
|
66
|
+
4. Different types of memory-mapped (UTF-8) string abstractions (slice or pointer based)
|
|
63
67
|
5. Shared (opt-in) memory allocation mechanism, also accessible from JS/TS side
|
|
64
|
-
4. Simple registration & dependency-order initialization for child WASM API modules
|
|
65
68
|
6. Include files for
|
|
66
69
|
[Zig](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api/zig),
|
|
67
70
|
and
|
|
@@ -71,46 +74,87 @@ WebGL, WebGPU, WebAudio etc. is being actively worked on.
|
|
|
71
74
|
by this package
|
|
72
75
|
7. [Zig build files](#using-the-zig-build-system) to simplify using hybrid
|
|
73
76
|
TS/Zig packages with the built-in build system
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
|
|
78
|
+
## Polyglot bindings generator
|
|
79
|
+
|
|
80
|
+
The toolkit includes an extensible [code
|
|
81
|
+
generator](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-bindgen/)
|
|
82
|
+
for shared datatypes and (currently) supports Zig & TypeScript and C11. For TS
|
|
83
|
+
fully type checked and memory-mapped (mostly zero-copy) accessors of WASM-side
|
|
84
|
+
data are generated. In principle, all languages with a WASM target are
|
|
85
|
+
supported, however currently only bindings for the languages mentioned are
|
|
86
|
+
included. The codegen also includes a [CLI
|
|
87
|
+
frontend/utility](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen/README.md#cli-generator).
|
|
83
88
|
|
|
84
89
|
## Custom API modules
|
|
85
90
|
|
|
86
91
|
The
|
|
87
92
|
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html)
|
|
88
|
-
can be extented via custom defined API modules. Such
|
|
93
|
+
can be extented via custom defined API modules. Such child modules will consist
|
|
89
94
|
of a collection of JS/TS functions & variables, their related counterparts
|
|
90
95
|
(import definitions) for the WASM target and (optionally) some shared data types
|
|
91
|
-
([bindings for which
|
|
92
|
-
|
|
96
|
+
([bindings for which can be generated via
|
|
97
|
+
thi.ng/wasm-api-bindgen](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen)).
|
|
93
98
|
|
|
94
|
-
On the JS side, custom API
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
On the JS side, custom API extensions can be easily integrated and exposed via
|
|
100
|
+
the [`IWasmAPI`
|
|
101
|
+
interface](https://docs.thi.ng/umbrella/wasm-api/interfaces/IWasmAPI.html) and
|
|
102
|
+
their module descriptors via
|
|
103
|
+
[`WasmModuleSpec`](https://docs.thi.ng/umbrella/wasm-api/interfaces/WasmModuleSpec.html).
|
|
104
|
+
The following example provides a brief overview:
|
|
97
105
|
|
|
98
106
|
```ts
|
|
99
|
-
import { IWasmAPI,
|
|
107
|
+
import { WasmBridge, type IWasmAPI, type WasmModuleSpec } from "@thi.ng/wasm-api";
|
|
108
|
+
import { WasmDomModule, type WasmDom, type WasmDomExports } from "@thi.ng/wasm-api-dom";
|
|
109
|
+
|
|
110
|
+
export const CustomModule: WasmModuleSpec = {
|
|
111
|
+
// Unique API module identifier to group WASM imports, must match ID used
|
|
112
|
+
// by the native code (see further below).
|
|
113
|
+
id: "custom",
|
|
114
|
+
// Optional array of API modules this module depends on. This is used to
|
|
115
|
+
// infer the full dependency graph and correct initialization order.
|
|
116
|
+
// Note: Each of the wasm-api support packages includes a module spec...
|
|
117
|
+
depes: [WasmDomModule],
|
|
118
|
+
// Factory function to pre-instantiate the API module. Full initialization
|
|
119
|
+
// only happens at a later point via WasmBridge.instantiate() or
|
|
120
|
+
// WasmBridge.init() and each module's own init() method...
|
|
121
|
+
factory: () => new CustomAPI(),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Optional declarations for JS-side functions which can be used from the WASM side.
|
|
125
|
+
// Using an interface for this is useful to establish a contract.
|
|
126
|
+
export interface CustomImports extends WebAssembly.ModuleImports {
|
|
127
|
+
/**
|
|
128
|
+
* Writes `num` random float32 numbers from given address
|
|
129
|
+
*/
|
|
130
|
+
fillRandom(addr: number, num: number): void;
|
|
131
|
+
}
|
|
100
132
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
133
|
+
// Optional (but likely used) interface declarations of functions exposed
|
|
134
|
+
// by the WASM binary and callable from the JS side (i.e. the opposite of the above)
|
|
135
|
+
//
|
|
136
|
+
// Note: If your module has dependencies on other modules you should declare
|
|
137
|
+
// your exports as extension of these other module's exports for better
|
|
138
|
+
// downstream developer experience
|
|
139
|
+
export interface CustomWasmExports extends WasmDomExports {
|
|
140
|
+
// ...
|
|
141
|
+
}
|
|
108
142
|
|
|
143
|
+
// Actual custom API extension implentation
|
|
144
|
+
export class CustomAPI implements IWasmAPI<CustomWasmExports> {
|
|
109
145
|
parent!: WasmBridge;
|
|
146
|
+
dom!: WasmDom;
|
|
110
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Actual module initialization, called from the main WasmBridge which
|
|
150
|
+
* initializes all modules in dependency order...
|
|
151
|
+
*/
|
|
111
152
|
async init(parent: WasmBridge) {
|
|
112
153
|
this.parent = parent;
|
|
113
154
|
this.parent.logger.debug("initializing custom API");
|
|
155
|
+
// Store a direct reference to the DOM module for future ref
|
|
156
|
+
// (just shown as example, we're not actually using this module here...)
|
|
157
|
+
this.dom = <WasmDom>this.parent.modules[WasmDomModule.id];
|
|
114
158
|
|
|
115
159
|
// any other tasks you might need to do...
|
|
116
160
|
|
|
@@ -118,15 +162,15 @@ export class CustomAPI implements IWasmAPI {
|
|
|
118
162
|
}
|
|
119
163
|
|
|
120
164
|
/**
|
|
121
|
-
* Returns object of functions to import as externals into the
|
|
122
|
-
* WASM module during instantiation. These imports are merged
|
|
123
|
-
*
|
|
165
|
+
* Returns object of functions/constants to import as externals into the
|
|
166
|
+
* WASM module during instantiation. These imports are merged into a
|
|
167
|
+
* larger imports object alongside the bridge's core API...
|
|
168
|
+
*
|
|
169
|
+
* Each module's imports will be grouped by its declared module ID, which
|
|
170
|
+
* also needs to be used to declare extern functions on the WASM side.
|
|
124
171
|
*/
|
|
125
|
-
getImports():
|
|
172
|
+
getImports(): CustomImports {
|
|
126
173
|
return {
|
|
127
|
-
/**
|
|
128
|
-
* Writes `num` random float32 numbers from given address
|
|
129
|
-
*/
|
|
130
174
|
fillRandom: (addr: number, num: number) => {
|
|
131
175
|
addr >>>= 2;
|
|
132
176
|
while(num-- > 0) this.parent.f32[addr++] = Math.random();
|
|
@@ -136,13 +180,12 @@ export class CustomAPI implements IWasmAPI {
|
|
|
136
180
|
}
|
|
137
181
|
|
|
138
182
|
// now we can supply this custom API when creating the main WASM bridge:
|
|
139
|
-
export const bridge = new WasmBridge([
|
|
183
|
+
export const bridge = new WasmBridge([CustomModule]);
|
|
140
184
|
```
|
|
141
185
|
|
|
142
186
|
In Zig (or any other language of your choice) we can then utilize this custom
|
|
143
|
-
API like so (Please also see [example
|
|
144
|
-
|
|
145
|
-
& other example snippets in this readme):
|
|
187
|
+
API like so (Please also see [example projects](#usage-examples) & other code
|
|
188
|
+
snippets in this readme):
|
|
146
189
|
|
|
147
190
|
Bindings file / lib:
|
|
148
191
|
|
|
@@ -155,26 +198,31 @@ Bindings file / lib:
|
|
|
155
198
|
///
|
|
156
199
|
/// The bridge core API uses "wasmapi" as reserved import group name
|
|
157
200
|
extern "custom" fn fillRandom(addr: [*]f32, num: usize) void;
|
|
201
|
+
|
|
202
|
+
/// Syntax sugar for `fillRandom()`
|
|
203
|
+
pub fn fillRandomSlice(slice: []f32) void {
|
|
204
|
+
fillRandom(slice.ptr, slice.len);
|
|
205
|
+
}
|
|
158
206
|
```
|
|
159
207
|
|
|
160
208
|
Main Zig file:
|
|
161
209
|
|
|
162
210
|
```zig
|
|
163
211
|
// Import JS core API
|
|
164
|
-
const
|
|
212
|
+
const wasm = @import("wasm-api");
|
|
165
213
|
const custom = @import("custom.zig");
|
|
166
214
|
|
|
167
215
|
export fn test_randomVec4() void {
|
|
168
216
|
var foo = [4]f32{ 1, 2, 3, 4 };
|
|
169
217
|
|
|
170
218
|
// print original
|
|
171
|
-
|
|
219
|
+
wasm.printF32Array(foo[0..]);
|
|
172
220
|
|
|
173
221
|
// populate foo with random numbers
|
|
174
|
-
custom.
|
|
222
|
+
custom.fillRandomSlice(foo[0..]);
|
|
175
223
|
|
|
176
224
|
// print result
|
|
177
|
-
|
|
225
|
+
wasm.printF32Array(foo[0..]);
|
|
178
226
|
}
|
|
179
227
|
```
|
|
180
228
|
|
|
@@ -257,32 +305,41 @@ etc.) use an auto-intialization hook related to the above `WASM_ALLOCATOR`
|
|
|
257
305
|
mechanism: If that allocator is available, the WASM side of these modules will
|
|
258
306
|
auto initialize and thus reduce boilerplate. However, if no such central
|
|
259
307
|
allocator is defined and/or a custom allocator should be used, then these API
|
|
260
|
-
modules will
|
|
308
|
+
modules will have to be initialized manually.
|
|
261
309
|
|
|
262
310
|
## Object indices & handles
|
|
263
311
|
|
|
264
|
-
Since only numeric values can be
|
|
265
|
-
host, any JS native objects the WASM side might want to be working with must
|
|
266
|
-
managed manually in JS. For this purpose the [`ObjectIndex`
|
|
312
|
+
Since only numeric values can be directly passed between the WASM module and the
|
|
313
|
+
JS host, any JS native objects the WASM side might want to be working with must
|
|
314
|
+
be managed manually in JS. For this purpose the [`ObjectIndex`
|
|
267
315
|
class](https://docs.thi.ng/umbrella/wasm-api/classes/ObjectIndex.html) can be
|
|
268
|
-
used by API modules to handle
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
(handles) will then need to be
|
|
316
|
+
used by API modules to handle the indexing of different types of JS
|
|
317
|
+
objects/values and their ID generation (incl. recycling of IDs, using
|
|
318
|
+
[@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen)).
|
|
319
|
+
Using this approach, only the numeric IDs (handles) will then need to be
|
|
320
|
+
exchanged with the WASM module...
|
|
272
321
|
|
|
273
322
|
```ts
|
|
274
323
|
import { ObjectIndex } from "@thi.ng/wasm-api";
|
|
324
|
+
import { ConsoleLogger } from "@thi.ng/logger";
|
|
275
325
|
|
|
326
|
+
// create index (see API docs for options)
|
|
276
327
|
const canvases = new ObjectIndex<HTMLCanvasElement>({ name: "canvas" });
|
|
277
328
|
|
|
278
329
|
// index item and assign new ID
|
|
279
|
-
canvases.add(document.createElement("canvas"));
|
|
330
|
+
canvases.add(<HTMLCanvasElement>document.createElement("canvas"));
|
|
280
331
|
// 0
|
|
281
332
|
|
|
282
333
|
// look up item by ID
|
|
283
334
|
canvases.get(0);
|
|
284
335
|
// <canvas ...>
|
|
285
336
|
|
|
337
|
+
// by default, items to be indexed are not checked for equality
|
|
338
|
+
// but we can use the below to ensure double indexing is avoided...
|
|
339
|
+
// (supports custom predicates to check for equality)
|
|
340
|
+
canvases.addUnique(canvases.get(0));
|
|
341
|
+
// 0 (returned already known ID)
|
|
342
|
+
|
|
286
343
|
// work w/ retrieved item
|
|
287
344
|
canvases.get(0).id = "foo";
|
|
288
345
|
|
|
@@ -326,8 +383,8 @@ built-in build system is as simple as:
|
|
|
326
383
|
**IMPORTANT:** Due to recent syntax & build system changes in Zig
|
|
327
384
|
[v0.12.0](https://ziglang.org/download/0.12.0/release-notes.html) &
|
|
328
385
|
[v0.13.0](https://ziglang.org/download/0.13.0/release-notes.html), older Zig
|
|
329
|
-
versions are not actively supported (however, [build files for older
|
|
330
|
-
are still
|
|
386
|
+
versions are not actively supported anymore (however, [build files for older
|
|
387
|
+
versions are still
|
|
331
388
|
included](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/zig))
|
|
332
389
|
|
|
333
390
|
```zig
|
|
@@ -359,8 +416,7 @@ pub fn build(b: *std.Build) void {
|
|
|
359
416
|
### Example projects
|
|
360
417
|
|
|
361
418
|
All bundled example projects (see [list below](#usage-examples)) are being built
|
|
362
|
-
via this script. **
|
|
363
|
-
code:**
|
|
419
|
+
via this script. **More details/options in the commented source code:**
|
|
364
420
|
|
|
365
421
|
- [`/zig/build.zig`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/zig/build.zig)
|
|
366
422
|
|
|
@@ -382,6 +438,7 @@ please also consult the information in
|
|
|
382
438
|
- [@thi.ng/wasm-api-canvas](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-canvas) - HTML Canvas2D bridge API for hybrid TypeScript & WASM (Zig) applications
|
|
383
439
|
- [@thi.ng/wasm-api-dom](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api-dom) - Browser DOM bridge API for hybrid TypeScript & WASM (Zig) applications
|
|
384
440
|
- [@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
|
|
441
|
+
- [@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
|
|
385
442
|
|
|
386
443
|
## Installation
|
|
387
444
|
|
|
@@ -403,7 +460,7 @@ Browser ESM import:
|
|
|
403
460
|
|
|
404
461
|
[JSDelivr documentation](https://www.jsdelivr.com/)
|
|
405
462
|
|
|
406
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
463
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 3.00 KB
|
|
407
464
|
|
|
408
465
|
## Dependencies
|
|
409
466
|
|
|
@@ -419,7 +476,7 @@ Note: @thi.ng/api is in _most_ cases a type-only import (not used at runtime)
|
|
|
419
476
|
|
|
420
477
|
## Usage examples
|
|
421
478
|
|
|
422
|
-
|
|
479
|
+
Five projects in this repo's
|
|
423
480
|
[/examples](https://github.com/thi-ng/umbrella/tree/develop/examples)
|
|
424
481
|
directory are using this package:
|
|
425
482
|
|
|
@@ -429,6 +486,7 @@ directory are using this package:
|
|
|
429
486
|
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-cellular.jpg" width="240"/> | Zig-based 2D multi-behavior cellular automata | [Demo](https://demo.thi.ng/umbrella/zig-cellular/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-cellular) |
|
|
430
487
|
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/zig-counter.png" width="240"/> | Simple Zig/WASM click counter DOM component | [Demo](https://demo.thi.ng/umbrella/zig-counter/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/zig-counter) |
|
|
431
488
|
| <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) |
|
|
489
|
+
| <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) |
|
|
432
490
|
|
|
433
491
|
## API
|
|
434
492
|
|
package/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EVENT_ALL, Fn, IDeref, ILength } from "@thi.ng/api";
|
|
1
|
+
import type { BigTypedArray, EVENT_ALL, Fn, IDeref, ILength, TypedArray, Values } from "@thi.ng/api";
|
|
2
2
|
import type { WasmBridge } from "./bridge.js";
|
|
3
3
|
export declare const EVENT_MEMORY_CHANGED = "memory-changed";
|
|
4
4
|
export declare const EVENT_PANIC = "panic";
|
|
@@ -52,18 +52,6 @@ export type WasmTypeConstructor<T> = Fn<IWasmMemoryAccess, WasmType<T>>;
|
|
|
52
52
|
* certain exports declared by WASM module.
|
|
53
53
|
*/
|
|
54
54
|
export interface IWasmAPI<T extends WasmExports = WasmExports> {
|
|
55
|
-
/**
|
|
56
|
-
* The unique ID for grouping the WASM imports of this module. MUST be the
|
|
57
|
-
* same as used by the native side of the module.
|
|
58
|
-
*/
|
|
59
|
-
readonly id: string;
|
|
60
|
-
/**
|
|
61
|
-
* IDs of other WASM API modules which this module depends on. Used to infer
|
|
62
|
-
* correct initialization order. The core module (w/ unique ID: `wasmapi`)
|
|
63
|
-
* is always considered an implicit dependency, will be initialized first
|
|
64
|
-
* and MUST NOT be stated here.
|
|
65
|
-
*/
|
|
66
|
-
readonly dependencies?: string[];
|
|
67
55
|
/**
|
|
68
56
|
* Called by {@link WasmBridge.init} to initialize all child APIs (async)
|
|
69
57
|
* after the WASM module has been instantiated. If the method returns false
|
|
@@ -79,6 +67,31 @@ export interface IWasmAPI<T extends WasmExports = WasmExports> {
|
|
|
79
67
|
*/
|
|
80
68
|
getImports(): WebAssembly.ModuleImports;
|
|
81
69
|
}
|
|
70
|
+
export interface WasmModuleSpec<T extends WasmExports = WasmExports> {
|
|
71
|
+
/**
|
|
72
|
+
* The unique ID for grouping the WASM imports of this module. MUST be the
|
|
73
|
+
* same as used by the native side of the module.
|
|
74
|
+
*/
|
|
75
|
+
id: string;
|
|
76
|
+
/**
|
|
77
|
+
* Optional array of other {@link WasmModuleSpec}s which this module depends
|
|
78
|
+
* on (element order is irrelevant). Used to construct a module dependency
|
|
79
|
+
* graph and the correct initialization order of modules. The core module
|
|
80
|
+
* (defined via {@link WasmBridge} w/ unique ID: `wasmapi`) is always
|
|
81
|
+
* considered an implicit dependency, will be initialized first and MUST NOT
|
|
82
|
+
* be stated here.
|
|
83
|
+
*/
|
|
84
|
+
deps?: WasmModuleSpec<T>[];
|
|
85
|
+
/**
|
|
86
|
+
* Factory function to pre-instantiate the API module.
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* Note: All modules will only be fully initialized at a later point via
|
|
90
|
+
* {@link WasmBridge.instantiate} or {@link WasmBridge.init} and each
|
|
91
|
+
* modules own {@link IWasmAPI.init} method.
|
|
92
|
+
*/
|
|
93
|
+
factory: Fn<WasmBridge<T>, IWasmAPI<T>>;
|
|
94
|
+
}
|
|
82
95
|
/**
|
|
83
96
|
* Base interface of exports declared by the WASM module. At the very least, a
|
|
84
97
|
* compatible module needs to export its memory and the functions defined in
|
|
@@ -133,6 +146,21 @@ export interface WasmExports {
|
|
|
133
146
|
_wasm_free(addr: number, numBytes: number): void;
|
|
134
147
|
}
|
|
135
148
|
export type MemorySlice = [addr: number, len: number];
|
|
149
|
+
export type MemoryViewType = "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "f32" | "f64";
|
|
150
|
+
export interface MemoryViewTypeMap extends Record<MemoryViewType, TypedArray | BigTypedArray> {
|
|
151
|
+
u8: Uint8Array;
|
|
152
|
+
u8c: Uint8ClampedArray;
|
|
153
|
+
i8: Int8Array;
|
|
154
|
+
u16: Uint16Array;
|
|
155
|
+
i16: Int16Array;
|
|
156
|
+
u32: Uint32Array;
|
|
157
|
+
i32: Int32Array;
|
|
158
|
+
i64: BigInt64Array;
|
|
159
|
+
u64: BigUint64Array;
|
|
160
|
+
f32: Float32Array;
|
|
161
|
+
f64: Float64Array;
|
|
162
|
+
}
|
|
163
|
+
export type MemoryView = Values<MemoryViewTypeMap>;
|
|
136
164
|
export interface IWasmMemoryAccess {
|
|
137
165
|
i8: Int8Array;
|
|
138
166
|
u8: Uint8Array;
|
package/bridge.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Event, INotify, IObjectOf, Listener, NumericArray } from "@thi.ng/api";
|
|
2
2
|
import type { ILogger } from "@thi.ng/logger";
|
|
3
|
-
import { type BigIntArray, type BridgeEventType, type CoreAPI, type IWasmAPI, type IWasmMemoryAccess, type MemorySlice, type WasmExports } from "./api.js";
|
|
3
|
+
import { type BigIntArray, type BridgeEventType, type CoreAPI, type IWasmAPI, type IWasmMemoryAccess, type MemorySlice, type WasmExports, type WasmModuleSpec } from "./api.js";
|
|
4
4
|
export declare const Panic: {
|
|
5
5
|
new (msg?: string | undefined): {
|
|
6
6
|
origMessage: string;
|
|
@@ -60,7 +60,21 @@ export declare class WasmBridge<T extends WasmExports = WasmExports> implements
|
|
|
60
60
|
exports: T;
|
|
61
61
|
api: CoreAPI;
|
|
62
62
|
modules: IObjectOf<IWasmAPI<T>>;
|
|
63
|
-
|
|
63
|
+
order: string[];
|
|
64
|
+
constructor(modules?: WasmModuleSpec<T>[], logger?: ILogger);
|
|
65
|
+
/**
|
|
66
|
+
* Takes array of root module specs, extracts all transitive dependencies,
|
|
67
|
+
* pre-computes their topological order, then calls
|
|
68
|
+
* {@link WasmModuleSpec.factory} for each module and stores all modules for
|
|
69
|
+
* future reference.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* Note: The pre-instantiated modules will only be fully initialized later
|
|
73
|
+
* via {@link WasmBridge.instantiate} or {@link WasmBridge.init}.
|
|
74
|
+
*
|
|
75
|
+
* @param specs
|
|
76
|
+
*/
|
|
77
|
+
protected _buildModuleGraph(specs: WasmModuleSpec<T>[]): void;
|
|
64
78
|
/**
|
|
65
79
|
* Instantiates WASM module from given `src` (and optional provided extra
|
|
66
80
|
* imports), then automatically calls {@link WasmBridge.init} with the
|
package/bridge.js
CHANGED
|
@@ -70,14 +70,7 @@ let WasmBridge = class {
|
|
|
70
70
|
timer: () => performance.now(),
|
|
71
71
|
epoch: () => BigInt(Date.now())
|
|
72
72
|
};
|
|
73
|
-
this.modules
|
|
74
|
-
assert(
|
|
75
|
-
acc[x.id] === void 0 && x.id !== this.id,
|
|
76
|
-
`duplicate API module ID: ${x.id}`
|
|
77
|
-
);
|
|
78
|
-
acc[x.id] = x;
|
|
79
|
-
return acc;
|
|
80
|
-
}, {});
|
|
73
|
+
this._buildModuleGraph(modules);
|
|
81
74
|
}
|
|
82
75
|
id = "wasmapi";
|
|
83
76
|
i8;
|
|
@@ -96,6 +89,44 @@ let WasmBridge = class {
|
|
|
96
89
|
exports;
|
|
97
90
|
api;
|
|
98
91
|
modules;
|
|
92
|
+
order;
|
|
93
|
+
/**
|
|
94
|
+
* Takes array of root module specs, extracts all transitive dependencies,
|
|
95
|
+
* pre-computes their topological order, then calls
|
|
96
|
+
* {@link WasmModuleSpec.factory} for each module and stores all modules for
|
|
97
|
+
* future reference.
|
|
98
|
+
*
|
|
99
|
+
* @remarks
|
|
100
|
+
* Note: The pre-instantiated modules will only be fully initialized later
|
|
101
|
+
* via {@link WasmBridge.instantiate} or {@link WasmBridge.init}.
|
|
102
|
+
*
|
|
103
|
+
* @param specs
|
|
104
|
+
*/
|
|
105
|
+
_buildModuleGraph(specs) {
|
|
106
|
+
const unique = /* @__PURE__ */ new Set();
|
|
107
|
+
const queue = [...specs];
|
|
108
|
+
while (queue.length) {
|
|
109
|
+
const mod = queue.shift();
|
|
110
|
+
unique.add(mod);
|
|
111
|
+
if (!mod.deps) continue;
|
|
112
|
+
for (let d of mod.deps) {
|
|
113
|
+
if (!unique.has(d)) queue.push(d);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const graph = [...unique].reduce((acc, mod) => {
|
|
117
|
+
assert(
|
|
118
|
+
(acc[mod.id] === void 0 || acc[mod.id] === mod) && mod.id !== this.id,
|
|
119
|
+
`duplicate API module ID: ${mod.id}`
|
|
120
|
+
);
|
|
121
|
+
acc[mod.id] = mod;
|
|
122
|
+
return acc;
|
|
123
|
+
}, {});
|
|
124
|
+
this.order = topoSort(graph, (mod) => mod.deps?.map((x) => x.id));
|
|
125
|
+
this.modules = this.order.reduce((acc, id) => {
|
|
126
|
+
acc[id] = graph[id].factory(this);
|
|
127
|
+
return acc;
|
|
128
|
+
}, {});
|
|
129
|
+
}
|
|
99
130
|
/**
|
|
100
131
|
* Instantiates WASM module from given `src` (and optional provided extra
|
|
101
132
|
* imports), then automatically calls {@link WasmBridge.init} with the
|
|
@@ -130,11 +161,7 @@ let WasmBridge = class {
|
|
|
130
161
|
async init(exports) {
|
|
131
162
|
this.exports = exports;
|
|
132
163
|
this.ensureMemory(false);
|
|
133
|
-
for (let id of
|
|
134
|
-
this.modules,
|
|
135
|
-
(module) => module.dependencies
|
|
136
|
-
)) {
|
|
137
|
-
assert(!!this.modules[id], `missing API module: ${id}`);
|
|
164
|
+
for (let id of this.order) {
|
|
138
165
|
this.logger.debug(`initializing API module: ${id}`);
|
|
139
166
|
const status = await this.modules[id].init(this);
|
|
140
167
|
if (!status) return false;
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
package/memory.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IWasmMemoryAccess, MemoryView, WasmType, WasmTypeConstructor } from "./api.js";
|
|
2
|
+
/** @internal */
|
|
3
|
+
export declare const __instanceArray: <T>(type: WasmType<T>, addr: number, num: number, size?: number) => T[];
|
|
4
|
+
/** @internal */
|
|
5
|
+
export declare const __array: <T>(mem: IWasmMemoryAccess, ctor: WasmTypeConstructor<T>, addr: number, len: number) => T[];
|
|
6
|
+
/** @internal */
|
|
7
|
+
export declare const __slice32: <T>(mem: IWasmMemoryAccess, ctor: WasmTypeConstructor<T>, offset: number) => T[];
|
|
8
|
+
/** @internal */
|
|
9
|
+
export declare const __slice64: <T>(mem: IWasmMemoryAccess, ctor: WasmTypeConstructor<T>, offset: number) => T[];
|
|
10
|
+
/** @internal */
|
|
11
|
+
export declare const __primslice32: <T extends MemoryView>(mem: IWasmMemoryAccess, view: T, offset: number, shift: number) => T;
|
|
12
|
+
/** @internal */
|
|
13
|
+
export declare const __primslice64: <T extends MemoryView>(mem: IWasmMemoryAccess, view: T, offset: number, shift: number) => T;
|
|
14
|
+
//# sourceMappingURL=memory.d.ts.map
|
package/memory.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const __instanceArray = (type, addr, num, size = type.size) => {
|
|
2
|
+
const items = [];
|
|
3
|
+
for (; num-- > 0; addr += size) items.push(type.instance(addr));
|
|
4
|
+
return items;
|
|
5
|
+
};
|
|
6
|
+
const __array = (mem, ctor, addr, len) => __instanceArray(ctor(mem), addr, len);
|
|
7
|
+
const __slice32 = (mem, ctor, offset) => {
|
|
8
|
+
return __array(
|
|
9
|
+
mem,
|
|
10
|
+
ctor,
|
|
11
|
+
mem.u32[offset >>> 2],
|
|
12
|
+
mem.u32[offset + 4 >>> 2]
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
const __slice64 = (mem, ctor, offset) => {
|
|
16
|
+
return __array(
|
|
17
|
+
mem,
|
|
18
|
+
ctor,
|
|
19
|
+
Number(mem.u64[offset >>> 3]),
|
|
20
|
+
Number(mem.u64[offset + 8 >>> 3])
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
const __primslice32 = (mem, view, offset, shift) => {
|
|
24
|
+
const addr = mem.u32[offset >>> 2] >>> shift;
|
|
25
|
+
const len = mem.u32[offset + 4 >>> 2];
|
|
26
|
+
return view.subarray(addr, addr + len);
|
|
27
|
+
};
|
|
28
|
+
const __primslice64 = (mem, view, offset, shift) => {
|
|
29
|
+
const addr = Number(mem.u64[offset >>> 3]) >>> shift;
|
|
30
|
+
const len = Number(mem.u64[offset + 8 >>> 3]);
|
|
31
|
+
return view.subarray(addr, addr + len);
|
|
32
|
+
};
|
|
33
|
+
export {
|
|
34
|
+
__array,
|
|
35
|
+
__instanceArray,
|
|
36
|
+
__primslice32,
|
|
37
|
+
__primslice64,
|
|
38
|
+
__slice32,
|
|
39
|
+
__slice64
|
|
40
|
+
};
|
package/object-index.d.ts
CHANGED
|
@@ -9,20 +9,26 @@ export interface ObjectIndexOpts {
|
|
|
9
9
|
/**
|
|
10
10
|
* Optional logger instance
|
|
11
11
|
*/
|
|
12
|
-
logger
|
|
12
|
+
logger: ILogger;
|
|
13
13
|
/**
|
|
14
14
|
* Number of bits for IDs, [1..32] range.
|
|
15
15
|
*
|
|
16
16
|
* @defaultValue 32
|
|
17
17
|
*/
|
|
18
|
-
bits
|
|
18
|
+
bits: Range1_32;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Object cache with numeric ID handle management.
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* [Further reference](https://docs.thi.ng/umbrella/wasm-api/#md:object-indices--handles)
|
|
25
|
+
*/
|
|
20
26
|
export declare class ObjectIndex<T> {
|
|
21
27
|
readonly name: string;
|
|
22
28
|
logger?: ILogger;
|
|
23
29
|
protected idgen: IDGen;
|
|
24
30
|
protected items: T[];
|
|
25
|
-
constructor(opts
|
|
31
|
+
constructor(opts?: Partial<ObjectIndexOpts>);
|
|
26
32
|
keys(): Generator<number, void, unknown>;
|
|
27
33
|
values(): Generator<T, void, unknown>;
|
|
28
34
|
/**
|
|
@@ -32,6 +38,19 @@ export declare class ObjectIndex<T> {
|
|
|
32
38
|
* @param item
|
|
33
39
|
*/
|
|
34
40
|
add(item: T): number;
|
|
41
|
+
/**
|
|
42
|
+
* Similar to {@link ObjectIndex.add}, but first checks if `item` has
|
|
43
|
+
* already been indexed and if so returns the ID of already indexed item
|
|
44
|
+
* without adding `item` to the index again. Uses `equiv` for checking item
|
|
45
|
+
* equality (by default: `===`).
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* Currently an O(n) implementation.
|
|
49
|
+
*
|
|
50
|
+
* @param item
|
|
51
|
+
* @param equiv
|
|
52
|
+
*/
|
|
53
|
+
addUnique(item: T, equiv?: Predicate<T>): number;
|
|
35
54
|
/**
|
|
36
55
|
* Returns true if the given `id` is valid/active.
|
|
37
56
|
*
|
package/object-index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { assert } from "@thi.ng/errors/assert";
|
|
2
2
|
import { IDGen } from "@thi.ng/idgen";
|
|
3
|
+
let __nextID = 0;
|
|
3
4
|
class ObjectIndex {
|
|
4
5
|
name;
|
|
5
6
|
logger;
|
|
6
7
|
idgen;
|
|
7
8
|
items = [];
|
|
8
9
|
constructor(opts) {
|
|
9
|
-
this.name = opts
|
|
10
|
-
this.logger = opts
|
|
11
|
-
this.idgen = new IDGen(opts
|
|
10
|
+
this.name = opts?.name ?? `idx-${__nextID++}`;
|
|
11
|
+
this.logger = opts?.logger;
|
|
12
|
+
this.idgen = new IDGen(opts?.bits ?? 32, 0);
|
|
12
13
|
}
|
|
13
14
|
keys() {
|
|
14
15
|
return this.idgen[Symbol.iterator]();
|
|
@@ -30,6 +31,22 @@ class ObjectIndex {
|
|
|
30
31
|
this.items[id] = item;
|
|
31
32
|
return id;
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Similar to {@link ObjectIndex.add}, but first checks if `item` has
|
|
36
|
+
* already been indexed and if so returns the ID of already indexed item
|
|
37
|
+
* without adding `item` to the index again. Uses `equiv` for checking item
|
|
38
|
+
* equality (by default: `===`).
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* Currently an O(n) implementation.
|
|
42
|
+
*
|
|
43
|
+
* @param item
|
|
44
|
+
* @param equiv
|
|
45
|
+
*/
|
|
46
|
+
addUnique(item, equiv = (x) => x === item) {
|
|
47
|
+
const id = this.find(equiv, false);
|
|
48
|
+
return id === void 0 ? this.add(item) : id;
|
|
49
|
+
}
|
|
33
50
|
/**
|
|
34
51
|
* Returns true if the given `id` is valid/active.
|
|
35
52
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/wasm-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Generic, modular, extensible API bridge and infrastructure for hybrid JS & WebAssembly projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@thi.ng/api": "^8.11.
|
|
41
|
-
"@thi.ng/arrays": "^2.
|
|
42
|
-
"@thi.ng/checks": "^3.6.
|
|
43
|
-
"@thi.ng/errors": "^2.5.
|
|
44
|
-
"@thi.ng/hex": "^2.3.
|
|
45
|
-
"@thi.ng/idgen": "^2.2.
|
|
46
|
-
"@thi.ng/logger": "^3.0.
|
|
40
|
+
"@thi.ng/api": "^8.11.9",
|
|
41
|
+
"@thi.ng/arrays": "^2.10.0",
|
|
42
|
+
"@thi.ng/checks": "^3.6.11",
|
|
43
|
+
"@thi.ng/errors": "^2.5.15",
|
|
44
|
+
"@thi.ng/hex": "^2.3.53",
|
|
45
|
+
"@thi.ng/idgen": "^2.2.49",
|
|
46
|
+
"@thi.ng/logger": "^3.0.19"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@microsoft/api-extractor": "^7.47.5",
|
|
@@ -102,6 +102,9 @@
|
|
|
102
102
|
"./bridge": {
|
|
103
103
|
"default": "./bridge.js"
|
|
104
104
|
},
|
|
105
|
+
"./memory": {
|
|
106
|
+
"default": "./memory.js"
|
|
107
|
+
},
|
|
105
108
|
"./object-index": {
|
|
106
109
|
"default": "./object-index.js"
|
|
107
110
|
},
|
|
@@ -116,5 +119,5 @@
|
|
|
116
119
|
"status": "alpha",
|
|
117
120
|
"year": 2022
|
|
118
121
|
},
|
|
119
|
-
"gitHead": "
|
|
122
|
+
"gitHead": "f6e26ea1142525171de5d36b9c3119f2782bb437\n"
|
|
120
123
|
}
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|