@thi.ng/wasm-api 0.10.0 → 0.12.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/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
+ }