@thi.ng/wasm-api 0.10.0 → 0.11.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.
@@ -3,9 +3,24 @@
3
3
  const std = @import("std");
4
4
  const root = @import("root");
5
5
 
6
+ /// JS external part of the custom panic handler
7
+ /// Prints message using configured JS logger and then throws JS error
8
+ pub extern "wasmapi" fn _panic(addr: [*]const u8, len: usize) noreturn;
9
+
10
+ /// Custom panic handler which prints given message using configured JS logger
11
+ /// To use this handler, add the following line to your **root** source file:
12
+ ///
13
+ /// ```
14
+ /// pub const panic = @import("wasmapi").panic;
15
+ /// ```
16
+ pub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace) noreturn {
17
+ _panic(msg.ptr, msg.len);
18
+ unreachable;
19
+ }
20
+
6
21
  /// Obtains the allocator to be exposed to the WASM host env
7
22
  /// (via `_wasm_allocate()` and `_wasm_free()`).
8
- /// If the user defines a public `WASM_ALLOCATOR` in their root file
23
+ /// If the user defines a public `WASM_ALLOCATOR` in their **root** file
9
24
  /// then this allocator will be used, otherwise the implementations
10
25
  /// of the two mentioned functions are no-ops.
11
26
  /// The `WASM_ALLOCATOR` can be changed and/or enabled/disabled dynamically
@@ -32,9 +47,9 @@ pub export fn _wasm_allocate(numBytes: usize) usize {
32
47
  /// Frees chunk of heap memory (previously allocated using `_wasm_allocate()`)
33
48
  /// starting at given address and of given byte length.
34
49
  /// Note: This is a no-op if no allocator is configured (see `allocator()`)
35
- pub export fn _wasm_free(addr: usize, numBytes: usize) void {
50
+ pub export fn _wasm_free(addr: [*]u8, numBytes: usize) void {
36
51
  if (allocator()) |alloc| {
37
- var mem = [2]usize{ addr, numBytes };
52
+ var mem = [2]usize{ @ptrToInt(addr), numBytes };
38
53
  alloc.free(@ptrCast(*[]u8, &mem).*);
39
54
  }
40
55
  }
@@ -60,26 +75,12 @@ pub extern "wasmapi" fn printU32(x: u32) void;
60
75
  /// Prints hex number using configured JS logger
61
76
  pub extern "wasmapi" fn printU32Hex(x: u32) void;
62
77
 
63
- /// Prints decomposed i64 number using configured JS logger
64
- pub extern "wasmapi" fn _printI64(hi: i32, lo: i32) void;
65
- /// Convenience wrapper for _printI64(), accepting an i64
66
- pub fn printI64(x: i64) void {
67
- _printI64(@truncate(i32, x >> 32), @truncate(i32, x));
68
- }
69
-
70
- /// Prints decomposed u64 number using configured JS logger
71
- pub extern "wasmapi" fn _printU64(hi: u32, lo: u32) void;
72
- /// Convenience wrapper for _printU64(), accepting an u64
73
- pub fn printU64(x: u64) void {
74
- _printU64(@truncate(u32, x >> 32), @truncate(u32, x));
75
- }
76
-
77
- /// Prints decomposed u64 hex number using configured JS logger
78
- pub extern "wasmapi" fn _printU64Hex(hi: u32, lo: u32) void;
79
- /// Convenience wrapper for _printU64Hex(), accepting an u64
80
- pub fn printU64Hex(x: u64) void {
81
- _printU64Hex(@truncate(u32, x >> 32), @truncate(u32, x));
82
- }
78
+ /// Prints i64 number using configured JS logger
79
+ pub extern "wasmapi" fn printI64(x: i64) void;
80
+ /// Prints u64 number using configured JS logger
81
+ pub extern "wasmapi" fn printU64(x: u64) void;
82
+ /// Prints u64 hex number using configured JS logger
83
+ pub extern "wasmapi" fn printU64Hex(x: u64) void;
83
84
 
84
85
  /// Prints number using configured JS logger
85
86
  pub extern "wasmapi" fn printF32(x: f32) void;
@@ -92,74 +93,74 @@ pub fn printPtr(ptr: *const anyopaque) void {
92
93
  }
93
94
 
94
95
  /// Prints number array using configured JS logger
95
- pub extern "wasmapi" fn _printI8Array(addr: usize, len: usize) void;
96
+ pub extern "wasmapi" fn _printI8Array(addr: [*]const i8, len: usize) void;
96
97
  /// Prints number array using configured JS logger
97
- pub extern "wasmapi" fn _printU8Array(addr: usize, len: usize) void;
98
+ pub extern "wasmapi" fn _printU8Array(addr: [*]const u8, len: usize) void;
98
99
  /// Prints number array using configured JS logger
99
- pub extern "wasmapi" fn _printI16Array(addr: usize, len: usize) void;
100
+ pub extern "wasmapi" fn _printI16Array(addr: [*]const i16, len: usize) void;
100
101
  /// Prints number array using configured JS logger
101
- pub extern "wasmapi" fn _printU16Array(addr: usize, len: usize) void;
102
+ pub extern "wasmapi" fn _printU16Array(addr: [*]const u16, len: usize) void;
102
103
  /// Prints number array using configured JS logger
103
- pub extern "wasmapi" fn _printI32Array(addr: usize, len: usize) void;
104
+ pub extern "wasmapi" fn _printI32Array(addr: [*]const i32, len: usize) void;
104
105
  /// Prints number array using configured JS logger
105
- pub extern "wasmapi" fn _printU32Array(addr: usize, len: usize) void;
106
+ pub extern "wasmapi" fn _printU32Array(addr: [*]const u32, len: usize) void;
106
107
  /// Prints number array using configured JS logger
107
- pub extern "wasmapi" fn _printI64Array(addr: usize, len: usize) void;
108
+ pub extern "wasmapi" fn _printI64Array(addr: [*]const i64, len: usize) void;
108
109
  /// Prints number array using configured JS logger
109
- pub extern "wasmapi" fn _printU64Array(addr: usize, len: usize) void;
110
+ pub extern "wasmapi" fn _printU64Array(addr: [*]const u64, len: usize) void;
110
111
  /// Prints number array using configured JS logger
111
- pub extern "wasmapi" fn _printF32Array(addr: usize, len: usize) void;
112
+ pub extern "wasmapi" fn _printF32Array(addr: [*]const f32, len: usize) void;
112
113
  /// Prints number array using configured JS logger
113
- pub extern "wasmapi" fn _printF64Array(addr: usize, len: usize) void;
114
+ pub extern "wasmapi" fn _printF64Array(addr: [*]const f64, len: usize) void;
114
115
 
115
116
  /// Prints number array using configured JS logger
116
117
  pub fn printI8Array(buf: []const i8) void {
117
- _printI8Array(@ptrToInt(buf.ptr), buf.len);
118
+ _printI8Array(buf.ptr, buf.len);
118
119
  }
119
120
  /// Prints number array using configured JS logger
120
121
  pub fn printU8Array(buf: []const u8) void {
121
- _printU8Array(@ptrToInt(buf.ptr), buf.len);
122
+ _printU8Array(buf.ptr, buf.len);
122
123
  }
123
124
  /// Prints number array using configured JS logger
124
125
  pub fn printI16Array(buf: []const i16) void {
125
- _printI16Array(@ptrToInt(buf.ptr), buf.len);
126
+ _printI16Array(buf.ptr, buf.len);
126
127
  }
127
128
  /// Prints number array using configured JS logger
128
129
  pub fn printU16Array(buf: []const u16) void {
129
- _printU16Array(@ptrToInt(buf.ptr), buf.len);
130
+ _printU16Array(buf.ptr, buf.len);
130
131
  }
131
132
  /// Prints number array using configured JS logger
132
133
  pub fn printI32Array(buf: []const i32) void {
133
- _printI32Array(@ptrToInt(buf.ptr), buf.len);
134
+ _printI32Array(buf.ptr, buf.len);
134
135
  }
135
136
  /// Prints number array using configured JS logger
136
137
  pub fn printU32Array(buf: []const u32) void {
137
- _printU32Array(@ptrToInt(buf.ptr), buf.len);
138
+ _printU32Array(buf.ptr, buf.len);
138
139
  }
139
140
  /// Prints number array using configured JS logger
140
141
  pub fn printI64Array(buf: []const i64) void {
141
- _printI64Array(@ptrToInt(buf.ptr), buf.len);
142
+ _printI64Array(buf.ptr, buf.len);
142
143
  }
143
144
  /// Prints number array using configured JS logger
144
145
  pub fn printU64Array(buf: []const u64) void {
145
- _printU64Array(@ptrToInt(buf.ptr), buf.len);
146
+ _printU64Array(buf.ptr, buf.len);
146
147
  }
147
148
  /// Prints number array using configured JS logger
148
149
  pub fn printF32Array(buf: []const f32) void {
149
- _printF32Array(@ptrToInt(buf.ptr), buf.len);
150
+ _printF32Array(buf.ptr, buf.len);
150
151
  }
151
152
  /// Prints number array using configured JS logger
152
153
  pub fn printF64Array(buf: []const f64) void {
153
- _printF64Array(@ptrToInt(buf.ptr), buf.len);
154
+ _printF64Array(buf.ptr, buf.len);
154
155
  }
155
156
 
156
157
  /// Prints a zero-terminated string using configured JS logger
157
- pub extern "wasmapi" fn _printStr0(addr: usize) void;
158
+ pub extern "wasmapi" fn _printStr0(addr: [*]const u8) void;
158
159
  /// Prints a string of given length using configured JS logger
159
- pub extern "wasmapi" fn _printStr(addr: usize, len: usize) void;
160
+ pub extern "wasmapi" fn _printStr(addr: [*]const u8, len: usize) void;
160
161
  /// Convenience wrapper for _printStr, accepting a slice as arg
161
162
  pub fn printStr(msg: []const u8) void {
162
- _printStr(@ptrToInt(msg.ptr), msg.len);
163
+ _printStr(msg.ptr, msg.len);
163
164
  }
164
165
 
165
166
  /// Calls std.fmt.allocPrint to format given string, then calls `printStr()`
@@ -175,3 +176,9 @@ pub fn printFmt(comptime fmt: []const u8, args: anytype) void {
175
176
 
176
177
  /// Triggers the JS/browser debugger
177
178
  pub extern "wasmapi" fn debug() void;
179
+
180
+ /// Returns a JS/browser highres timer value (via `performance.now()`)
181
+ pub extern "wasmapi" fn timer() f64;
182
+
183
+ /// Returns a JS/browser Unix epoch (via `Date.now()`)
184
+ pub extern "wasmapi" fn epoch() u64;
package/index.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  export * from "./api.js";
2
2
  export * from "./bridge.js";
3
3
  export * from "./codegen.js";
4
+ export * from "./codegen/c11.js";
4
5
  export * from "./codegen/typescript.js";
5
6
  export * from "./codegen/utils.js";
6
7
  export * from "./codegen/zig.js";
7
8
  export * from "./object-index.js";
9
+ export * from "./pointer.js";
10
+ export * from "./string.js";
8
11
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  export * from "./api.js";
2
2
  export * from "./bridge.js";
3
3
  export * from "./codegen.js";
4
+ export * from "./codegen/c11.js";
4
5
  export * from "./codegen/typescript.js";
5
6
  export * from "./codegen/utils.js";
6
7
  export * from "./codegen/zig.js";
7
8
  export * from "./object-index.js";
9
+ export * from "./pointer.js";
10
+ export * from "./string.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@thi.ng/wasm-api",
3
- "version": "0.10.0",
4
- "description": "Generic, modular, extensible API bridge, glue code and bindings code generator for hybrid JS & WebAssembly projects",
3
+ "version": "0.11.0",
4
+ "description": "Generic, modular, extensible API bridge, polyglot glue code and bindings code generators for hybrid JS & WebAssembly projects",
5
5
  "type": "module",
6
6
  "module": "./index.js",
7
7
  "typings": "./index.d.ts",
@@ -36,25 +36,26 @@
36
36
  "test:build-zig": "zig build-lib -O ReleaseSmall -target wasm32-freestanding -dynamic --strip --pkg-begin wasmapi include/wasmapi.zig --pkg-end test/custom.zig && wasm-dis -o custom.wast custom.wasm && cp custom.wasm test"
37
37
  },
38
38
  "dependencies": {
39
- "@thi.ng/api": "^8.4.1",
40
- "@thi.ng/args": "^2.2.1",
41
- "@thi.ng/binary": "^3.3.4",
42
- "@thi.ng/checks": "^3.2.4",
43
- "@thi.ng/compare": "^2.1.11",
44
- "@thi.ng/defmulti": "^2.1.13",
45
- "@thi.ng/errors": "^2.1.10",
46
- "@thi.ng/file-io": "^0.3.10",
47
- "@thi.ng/hex": "^2.1.9",
48
- "@thi.ng/idgen": "^2.1.12",
49
- "@thi.ng/logger": "^1.2.1"
39
+ "@thi.ng/api": "^8.4.2",
40
+ "@thi.ng/args": "^2.2.2",
41
+ "@thi.ng/binary": "^3.3.5",
42
+ "@thi.ng/checks": "^3.2.5",
43
+ "@thi.ng/compare": "^2.1.12",
44
+ "@thi.ng/defmulti": "^2.1.14",
45
+ "@thi.ng/errors": "^2.2.0",
46
+ "@thi.ng/file-io": "^0.3.11",
47
+ "@thi.ng/hex": "^2.2.0",
48
+ "@thi.ng/idgen": "^2.1.13",
49
+ "@thi.ng/logger": "^1.3.0",
50
+ "@thi.ng/paths": "^5.1.15"
50
51
  },
51
52
  "devDependencies": {
52
- "@microsoft/api-extractor": "^7.25.0",
53
- "@thi.ng/testament": "^0.2.12",
53
+ "@microsoft/api-extractor": "^7.31.1",
54
+ "@thi.ng/testament": "^0.3.0",
54
55
  "rimraf": "^3.0.2",
55
56
  "tools": "^0.0.1",
56
57
  "typedoc": "^0.22.17",
57
- "typescript": "^4.7.4"
58
+ "typescript": "^4.8.3"
58
59
  },
59
60
  "keywords": [
60
61
  "allocator",
@@ -62,10 +63,12 @@
62
63
  "bindings",
63
64
  "c",
64
65
  "codegen",
66
+ "enum",
65
67
  "event",
66
68
  "id",
67
69
  "logger",
68
70
  "memory",
71
+ "polyglot",
69
72
  "string",
70
73
  "struct",
71
74
  "typedarray",
@@ -103,8 +106,8 @@
103
106
  "./bridge": {
104
107
  "default": "./bridge.js"
105
108
  },
106
- "./codegen": {
107
- "default": "./codegen.js"
109
+ "./codegen/c11": {
110
+ "default": "./codegen/c11.js"
108
111
  },
109
112
  "./codegen/typescript": {
110
113
  "default": "./codegen/typescript.js"
@@ -115,13 +118,22 @@
115
118
  "./codegen/zig": {
116
119
  "default": "./codegen/zig.js"
117
120
  },
121
+ "./codegen": {
122
+ "default": "./codegen.js"
123
+ },
118
124
  "./object-index": {
119
125
  "default": "./object-index.js"
126
+ },
127
+ "./pointer": {
128
+ "default": "./pointer.js"
129
+ },
130
+ "./string": {
131
+ "default": "./string.js"
120
132
  }
121
133
  },
122
134
  "thi.ng": {
123
135
  "status": "alpha",
124
136
  "year": 2022
125
137
  },
126
- "gitHead": "4264b91052b8c1f74db9fd51dc48c830dc0d5829\n"
138
+ "gitHead": "973139c5aa3b50081020f4cc726a7cc330f77fc7\n"
127
139
  }
package/pointer.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { Fn, IDeref } from "@thi.ng/api";
2
+ import type { IWasmMemoryAccess } from "./api.js";
3
+ /**
4
+ * Generic pointer facility which on {@link Pointer.deref()} calls wrapper
5
+ * function (provided as ctor arg) to realise the pointer's target value. The
6
+ * pointer's target address can be accessed via {@link Pointer.addr}
7
+ * (read/write).
8
+ *
9
+ * @remarks
10
+ * The pointer always behaves like `volatile`, i.e. memoization of target values
11
+ * is purposfully avoided and the wrapper function is executed anew _each_ time
12
+ * the pointer is deref'd.
13
+ */
14
+ export declare class Pointer<T> implements IDeref<T> {
15
+ readonly mem: IWasmMemoryAccess;
16
+ readonly base: number;
17
+ readonly fn: Fn<number, T>;
18
+ constructor(mem: IWasmMemoryAccess, base: number, fn: Fn<number, T>);
19
+ get addr(): number;
20
+ set addr(addr: number);
21
+ deref(): T;
22
+ }
23
+ //# sourceMappingURL=pointer.d.ts.map
package/pointer.js ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Generic pointer facility which on {@link Pointer.deref()} calls wrapper
3
+ * function (provided as ctor arg) to realise the pointer's target value. The
4
+ * pointer's target address can be accessed via {@link Pointer.addr}
5
+ * (read/write).
6
+ *
7
+ * @remarks
8
+ * The pointer always behaves like `volatile`, i.e. memoization of target values
9
+ * is purposfully avoided and the wrapper function is executed anew _each_ time
10
+ * the pointer is deref'd.
11
+ */
12
+ export class Pointer {
13
+ constructor(mem, base, fn) {
14
+ this.mem = mem;
15
+ this.base = base;
16
+ this.fn = fn;
17
+ }
18
+ get addr() {
19
+ return this.mem.u32[this.base >>> 2];
20
+ }
21
+ set addr(addr) {
22
+ this.mem.u32[this.base >>> 2] = addr;
23
+ }
24
+ deref() {
25
+ return this.fn(this.addr);
26
+ }
27
+ }
package/string.d.ts ADDED
@@ -0,0 +1,97 @@
1
+ import type { IDeref } from "@thi.ng/api";
2
+ import type { IWasmMemoryAccess } from "./api.js";
3
+ /**
4
+ * Memory mapped string wrapper for Zig-style UTF-8 encoded byte slices (aka
5
+ * pointer & length pair). The actual JS string can be obtained via
6
+ * {@link WasmStringSlice.deref} and mutated via {@link WasmStringSlice.set}.
7
+ */
8
+ export declare class WasmStringSlice implements IDeref<string> {
9
+ readonly mem: IWasmMemoryAccess;
10
+ readonly base: number;
11
+ readonly isConst: boolean;
12
+ readonly max: number;
13
+ constructor(mem: IWasmMemoryAccess, base: number, isConst?: boolean);
14
+ /**
15
+ * Returns string start address (deref'd pointer).
16
+ */
17
+ get addr(): number;
18
+ /**
19
+ * Returns string length (read from memory)
20
+ */
21
+ get length(): number;
22
+ /**
23
+ * Returns memory as JS string (aka wrapper for
24
+ * {@link WasmBridge.getString}).
25
+ */
26
+ deref(): string;
27
+ /**
28
+ * If given a JS string as arg (and if **not** a const slice), attempts to
29
+ * overwrite this wrapped string's memory with bytes from given string. If
30
+ * given another {@link WasmStringSlice} as arg, only the slice pointer &
31
+ * new length will be updated (always succeeds).
32
+ *
33
+ * @remarks
34
+ * When copying bytes from a JS string, an error will be thrown if the new
35
+ * string is longer than the _original_ length of the slice (i.e. from when
36
+ * this `WasmStringSlice` wrapper instance was created). Also updates the
37
+ * slice's length field to new string length.
38
+ *
39
+ * Passing a `WasmString` instance as arg is faster than JS string since
40
+ * only the slice definition itself will be updated.
41
+ *
42
+ * @param str
43
+ */
44
+ set(str: string | WasmStringSlice): void;
45
+ toJSON(): string;
46
+ toString(): string;
47
+ valueOf(): string;
48
+ }
49
+ /**
50
+ * Memory mapped string wrapper for C-style UTF-8 encoded and zero-terminated
51
+ * char pointers. The actual JS string can be obtained via
52
+ * {@link WasmStringSlice.deref} and mutated via {@link WasmStringSlice.set}.
53
+ */
54
+ export declare class WasmStringPtr implements IDeref<string> {
55
+ readonly mem: IWasmMemoryAccess;
56
+ readonly base: number;
57
+ readonly isConst: boolean;
58
+ constructor(mem: IWasmMemoryAccess, base: number, isConst?: boolean);
59
+ /**
60
+ * Returns string start address (deref'd pointer).
61
+ */
62
+ get addr(): number;
63
+ set addr(addr: number);
64
+ /**
65
+ * Returns computed string length (scanning memory for zero sentinel)
66
+ */
67
+ get length(): number;
68
+ /**
69
+ * Returns memory as JS string (aka wrapper for
70
+ * {@link WasmBridge.getString}).
71
+ */
72
+ deref(): string;
73
+ /**
74
+ * If given a JS string as arg (and if not a const pointer), attempts to
75
+ * overwrite this wrapped string's memory with bytes from given string. If
76
+ * given another {@link WasmStringPtr}, it merely overrides the pointer to
77
+ * the new one (always succeeds).
78
+ *
79
+ * @remarks
80
+ * Unlike with {@link WasmStringSlice.set} this implementation which
81
+ * performs bounds checking when copying bytes from a JS string, this method
82
+ * only throws an error if the new string is longer than the available
83
+ * memory (from the start address until the end of the WASM memory).
84
+ * **Therefore, this is as (un)safe as a C pointer and should be used with
85
+ * caution!**
86
+ *
87
+ * Passing a `WasmStringPtr` instance as arg is faster than JS string since
88
+ * only the pointer itself will be updated.
89
+ *
90
+ * @param str
91
+ */
92
+ set(str: string | WasmStringPtr): void;
93
+ toJSON(): string;
94
+ toString(): string;
95
+ valueOf(): string;
96
+ }
97
+ //# sourceMappingURL=string.d.ts.map
package/string.js ADDED
@@ -0,0 +1,145 @@
1
+ import { unsupported } from "@thi.ng/errors/unsupported";
2
+ /**
3
+ * Memory mapped string wrapper for Zig-style UTF-8 encoded byte slices (aka
4
+ * pointer & length pair). The actual JS string can be obtained via
5
+ * {@link WasmStringSlice.deref} and mutated via {@link WasmStringSlice.set}.
6
+ */
7
+ export class WasmStringSlice {
8
+ constructor(mem, base, isConst = true) {
9
+ this.mem = mem;
10
+ this.base = base;
11
+ this.isConst = isConst;
12
+ this.max = this.length;
13
+ }
14
+ /**
15
+ * Returns string start address (deref'd pointer).
16
+ */
17
+ get addr() {
18
+ return this.mem.u32[this.base >>> 2];
19
+ }
20
+ /**
21
+ * Returns string length (read from memory)
22
+ */
23
+ get length() {
24
+ return this.mem.u32[(this.base + 4) >>> 2];
25
+ }
26
+ /**
27
+ * Returns memory as JS string (aka wrapper for
28
+ * {@link WasmBridge.getString}).
29
+ */
30
+ deref() {
31
+ return this.mem.getString(this.addr, this.length);
32
+ }
33
+ /**
34
+ * If given a JS string as arg (and if **not** a const slice), attempts to
35
+ * overwrite this wrapped string's memory with bytes from given string. If
36
+ * given another {@link WasmStringSlice} as arg, only the slice pointer &
37
+ * new length will be updated (always succeeds).
38
+ *
39
+ * @remarks
40
+ * When copying bytes from a JS string, an error will be thrown if the new
41
+ * string is longer than the _original_ length of the slice (i.e. from when
42
+ * this `WasmStringSlice` wrapper instance was created). Also updates the
43
+ * slice's length field to new string length.
44
+ *
45
+ * Passing a `WasmString` instance as arg is faster than JS string since
46
+ * only the slice definition itself will be updated.
47
+ *
48
+ * @param str
49
+ */
50
+ set(str) {
51
+ if (typeof str === "string") {
52
+ if (this.isConst)
53
+ unsupported("can't mutate const string");
54
+ this.mem.u32[(this.base + 4) >>> 2] = this.mem.setString(str, this.addr, this.max + 1, true);
55
+ }
56
+ else {
57
+ this.mem.u32[this.base >>> 2] = str.addr;
58
+ this.mem.u32[(this.base + 4) >>> 2] = str.length;
59
+ }
60
+ }
61
+ toJSON() {
62
+ return this.deref();
63
+ }
64
+ toString() {
65
+ return this.deref();
66
+ }
67
+ valueOf() {
68
+ return this.deref();
69
+ }
70
+ }
71
+ /**
72
+ * Memory mapped string wrapper for C-style UTF-8 encoded and zero-terminated
73
+ * char pointers. The actual JS string can be obtained via
74
+ * {@link WasmStringSlice.deref} and mutated via {@link WasmStringSlice.set}.
75
+ */
76
+ export class WasmStringPtr {
77
+ constructor(mem, base, isConst = true) {
78
+ this.mem = mem;
79
+ this.base = base;
80
+ this.isConst = isConst;
81
+ }
82
+ /**
83
+ * Returns string start address (deref'd pointer).
84
+ */
85
+ get addr() {
86
+ return this.mem.u32[this.base >>> 2];
87
+ }
88
+ set addr(addr) {
89
+ this.mem.u32[this.base >>> 2] = addr;
90
+ }
91
+ /**
92
+ * Returns computed string length (scanning memory for zero sentinel)
93
+ */
94
+ get length() {
95
+ const addr = this.addr;
96
+ const idx = this.mem.u8.indexOf(0, addr);
97
+ return idx >= 0 ? idx - addr : 0;
98
+ }
99
+ /**
100
+ * Returns memory as JS string (aka wrapper for
101
+ * {@link WasmBridge.getString}).
102
+ */
103
+ deref() {
104
+ return this.mem.getString(this.addr, this.length);
105
+ }
106
+ /**
107
+ * If given a JS string as arg (and if not a const pointer), attempts to
108
+ * overwrite this wrapped string's memory with bytes from given string. If
109
+ * given another {@link WasmStringPtr}, it merely overrides the pointer to
110
+ * the new one (always succeeds).
111
+ *
112
+ * @remarks
113
+ * Unlike with {@link WasmStringSlice.set} this implementation which
114
+ * performs bounds checking when copying bytes from a JS string, this method
115
+ * only throws an error if the new string is longer than the available
116
+ * memory (from the start address until the end of the WASM memory).
117
+ * **Therefore, this is as (un)safe as a C pointer and should be used with
118
+ * caution!**
119
+ *
120
+ * Passing a `WasmStringPtr` instance as arg is faster than JS string since
121
+ * only the pointer itself will be updated.
122
+ *
123
+ * @param str
124
+ */
125
+ set(str) {
126
+ const addr = this.addr;
127
+ if (typeof str === "string") {
128
+ if (this.isConst)
129
+ unsupported("can't mutate const string");
130
+ this.mem.setString(str, addr, this.mem.u8.byteLength - addr, true);
131
+ }
132
+ else {
133
+ this.addr = str.addr;
134
+ }
135
+ }
136
+ toJSON() {
137
+ return this.deref();
138
+ }
139
+ toString() {
140
+ return this.deref();
141
+ }
142
+ valueOf() {
143
+ return this.deref();
144
+ }
145
+ }