@polyengine/runtime 0.5.1 → 0.6.1
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/esm/cabi/async_values.js +6 -5
- package/esm/cabi/bulk_lists.js +0 -5
- package/esm/cabi/context.js +13 -3
- package/esm/cabi/flatten.js +41 -9
- package/esm/cabi/handles.js +57 -54
- package/esm/cabi/layout.js +113 -52
- package/esm/cabi/load.js +31 -23
- package/esm/cabi/store.js +33 -26
- package/esm/cabi/trap.js +2 -2
- package/esm/cabi/types.js +138 -25
- package/esm/cabi/values.js +25 -7
- package/esm/cache/core.js +2 -11
- package/esm/digest/digest.js +10 -8
- package/esm/digest/mod.js +1 -1
- package/esm/digest/verify.js +6 -86
- package/esm/embedder/casing.js +24 -9
- package/esm/embedder/copy.js +6 -6
- package/esm/embedder/errors.js +2 -2
- package/esm/embedder/imports.js +3 -3
- package/esm/embedder/instantiate.js +132 -37
- package/esm/embedder/mod.js +9 -8
- package/esm/embedder/resources.js +39 -16
- package/esm/embedder/streams.js +36 -37
- package/esm/embedder/sync.js +242 -0
- package/esm/embedder/values.js +84 -22
- package/esm/embedder/version.js +9 -9
- package/esm/exec/boundary.js +123 -161
- package/esm/exec/executor.js +37 -25
- package/esm/exec/host_streams.js +31 -31
- package/esm/intrinsics/async_builtins.js +15 -7
- package/esm/intrinsics/context.js +1 -1
- package/esm/intrinsics/errors.js +9 -9
- package/esm/intrinsics/fact_calls.js +37 -49
- package/esm/intrinsics/mod.js +54 -117
- package/esm/intrinsics/stream_builtins.js +2 -2
- package/esm/intrinsics/transcode.js +1 -1
- package/esm/jspi/bridge.js +4 -3
- package/esm/jspi/suspending.js +5 -5
- package/esm/plan/loader.js +5 -5
- package/esm/shim/translator.js +2 -2
- package/esm/task/mod.js +45 -182
- package/esm/task/scheduler.js +154 -185
- package/esm/task/streams.js +39 -54
- package/esm/task/subtask.js +2 -2
- package/esm/task/thread.js +20 -41
- package/esm/task/waitable.js +0 -1
- package/package.json +2 -2
- package/types/cabi/async_values.d.ts +3 -2
- package/types/cabi/bulk_lists.d.ts +0 -2
- package/types/cabi/context.d.ts +15 -5
- package/types/cabi/flatten.d.ts +2 -2
- package/types/cabi/handles.d.ts +15 -26
- package/types/cabi/layout.d.ts +22 -1
- package/types/cabi/load.d.ts +10 -2
- package/types/cabi/store.d.ts +4 -2
- package/types/cabi/types.d.ts +22 -3
- package/types/digest/mod.d.ts +1 -1
- package/types/digest/verify.d.ts +3 -19
- package/types/embedder/casing.d.ts +9 -1
- package/types/embedder/copy.d.ts +4 -4
- package/types/embedder/instantiate.d.ts +4 -4
- package/types/embedder/mod.d.ts +3 -2
- package/types/embedder/resources.d.ts +20 -7
- package/types/embedder/streams.d.ts +5 -6
- package/types/embedder/sync.d.ts +81 -0
- package/types/embedder/values.d.ts +2 -2
- package/types/exec/boundary.d.ts +55 -44
- package/types/exec/executor.d.ts +3 -2
- package/types/exec/host_streams.d.ts +8 -8
- package/types/intrinsics/errors.d.ts +3 -3
- package/types/intrinsics/mod.d.ts +1 -1
- package/types/intrinsics/stream_builtins.d.ts +2 -2
- package/types/jspi/bridge.d.ts +6 -5
- package/types/plan/format.d.ts +11 -10
- package/types/plan/loader.d.ts +2 -2
- package/types/shim/translator.d.ts +2 -2
- package/types/task/mod.d.ts +26 -97
- package/types/task/scheduler.d.ts +81 -62
- package/types/task/streams.d.ts +23 -38
- package/types/task/subtask.d.ts +2 -2
- package/types/task/waitable.d.ts +0 -1
package/esm/embedder/values.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Bidirectional value-shape adaptation (contracts/embedder-api.md
|
|
2
|
-
// §"Value mapping"
|
|
2
|
+
// §"Value mapping").
|
|
3
3
|
//
|
|
4
4
|
// FROM: the runtime's raw boundary, whose shapes are the definitions.py
|
|
5
5
|
// interpreter's — single-key variants (`{ "circle": 1.5 }`), `{some}` /
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
//
|
|
16
16
|
// The adapter is driven entirely by the plan's `ValType`s — no generated code
|
|
17
17
|
// participates, which is what lets the same facade serve an untyped embedder
|
|
18
|
-
// and a bindgen-typed one (the
|
|
18
|
+
// and a bindgen-typed one (the design ruling: runtime-driven facade,
|
|
19
19
|
// compile-time-only bindgen).
|
|
20
20
|
import { despecialize } from "../cabi/types.js";
|
|
21
21
|
import { ERROR_CONTEXT, hasBrand } from "@polyengine/protocol";
|
|
@@ -74,6 +74,66 @@ export function checkNoCollisions(key, labels, what) {
|
|
|
74
74
|
}
|
|
75
75
|
checkedLabels.add(key);
|
|
76
76
|
}
|
|
77
|
+
const recordTables = new WeakMap();
|
|
78
|
+
function recordTable(t) {
|
|
79
|
+
const hit = recordTables.get(t);
|
|
80
|
+
if (hit !== undefined)
|
|
81
|
+
return hit;
|
|
82
|
+
const table = {
|
|
83
|
+
labels: t.fields.map((f) => f.label),
|
|
84
|
+
fields: t.fields.map((f) => ({
|
|
85
|
+
label: f.label,
|
|
86
|
+
js: camelCase(f.label),
|
|
87
|
+
type: f.type,
|
|
88
|
+
isOption: f.type.kind === "option",
|
|
89
|
+
optionInner: f.type.kind === "option" ? f.type.type : null,
|
|
90
|
+
})),
|
|
91
|
+
};
|
|
92
|
+
recordTables.set(t, table);
|
|
93
|
+
return table;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Label -> case, memoized on the `cases` array. Replaces the linear
|
|
97
|
+
* `t.cases.find(...)` both directions ran per element.
|
|
98
|
+
*
|
|
99
|
+
* **First wins on a duplicated label** — deliberately NOT `caseIndexOf` from
|
|
100
|
+
* cabi/types.ts, which maps a duplicate to -1. The two sites replace scans
|
|
101
|
+
* with different pre-existing behavior (`find` takes the first match; the cabi
|
|
102
|
+
* scan asserted on exactly one), so each keeps its own; merging them would be
|
|
103
|
+
* a behavior change, not a deduplication.
|
|
104
|
+
*/
|
|
105
|
+
const variantTables = new WeakMap();
|
|
106
|
+
function variantTable(cases) {
|
|
107
|
+
const hit = variantTables.get(cases);
|
|
108
|
+
if (hit !== undefined)
|
|
109
|
+
return hit;
|
|
110
|
+
const m = new Map();
|
|
111
|
+
for (const c of cases)
|
|
112
|
+
if (!m.has(c.label))
|
|
113
|
+
m.set(c.label, c);
|
|
114
|
+
variantTables.set(cases, m);
|
|
115
|
+
return m;
|
|
116
|
+
}
|
|
117
|
+
/** The enum's labels as a set, replacing `t.labels.includes(v)`. */
|
|
118
|
+
const enumTables = new WeakMap();
|
|
119
|
+
function enumTable(t) {
|
|
120
|
+
const hit = enumTables.get(t);
|
|
121
|
+
if (hit !== undefined)
|
|
122
|
+
return hit;
|
|
123
|
+
const s = new Set(t.labels);
|
|
124
|
+
enumTables.set(t, s);
|
|
125
|
+
return s;
|
|
126
|
+
}
|
|
127
|
+
/** Flags labels paired with their JS names, in source order. */
|
|
128
|
+
const flagsTables = new WeakMap();
|
|
129
|
+
function flagsTable(t) {
|
|
130
|
+
const hit = flagsTables.get(t);
|
|
131
|
+
if (hit !== undefined)
|
|
132
|
+
return hit;
|
|
133
|
+
const table = t.labels.map((label) => ({ label, js: camelCase(label) }));
|
|
134
|
+
flagsTables.set(t, table);
|
|
135
|
+
return table;
|
|
136
|
+
}
|
|
77
137
|
// ---------------------------------------------------------------------------
|
|
78
138
|
// internal -> conventions
|
|
79
139
|
// ---------------------------------------------------------------------------
|
|
@@ -117,21 +177,22 @@ export function toHost(v, t, o, scope = NO_BORROWS, inOption = false) {
|
|
|
117
177
|
return v.map((e) => toHost(e, t.element, o, scope));
|
|
118
178
|
}
|
|
119
179
|
case "record": {
|
|
120
|
-
|
|
180
|
+
const table = recordTable(t);
|
|
181
|
+
checkNoCollisions(t, table.labels, `${o.where}: record`);
|
|
121
182
|
const src = v;
|
|
122
183
|
const out = {};
|
|
123
|
-
for (const f of
|
|
184
|
+
for (const f of table.fields) {
|
|
124
185
|
// "fields of option type are optional properties (`field?: T`)": a
|
|
125
186
|
// `none` field is *absent*, not `undefined`-valued, so the object has
|
|
126
187
|
// one canonical shape rather than two indistinguishable ones.
|
|
127
|
-
if (f.
|
|
188
|
+
if (f.isOption) {
|
|
128
189
|
const inner = src[f.label];
|
|
129
190
|
if ("none" in inner)
|
|
130
191
|
continue;
|
|
131
|
-
out[
|
|
192
|
+
out[f.js] = toHost(inner["some"], f.optionInner, o, scope, true);
|
|
132
193
|
continue;
|
|
133
194
|
}
|
|
134
|
-
out[
|
|
195
|
+
out[f.js] = toHost(src[f.label], f.type, o, scope);
|
|
135
196
|
}
|
|
136
197
|
return out;
|
|
137
198
|
}
|
|
@@ -141,7 +202,7 @@ export function toHost(v, t, o, scope = NO_BORROWS, inOption = false) {
|
|
|
141
202
|
}
|
|
142
203
|
case "variant": {
|
|
143
204
|
const [label, payload] = single(v, o);
|
|
144
|
-
const c = t.cases.
|
|
205
|
+
const c = variantTable(t.cases).get(label);
|
|
145
206
|
if (c === undefined) {
|
|
146
207
|
throw new TypeError(`${o.where}: unknown variant case '${label}'`);
|
|
147
208
|
}
|
|
@@ -177,8 +238,8 @@ export function toHost(v, t, o, scope = NO_BORROWS, inOption = false) {
|
|
|
177
238
|
checkNoCollisions(t, t.labels, `${o.where}: flags`);
|
|
178
239
|
const src = v;
|
|
179
240
|
const out = {};
|
|
180
|
-
for (const
|
|
181
|
-
out[
|
|
241
|
+
for (const f of flagsTable(t))
|
|
242
|
+
out[f.js] = Boolean(src[f.label]);
|
|
182
243
|
return out;
|
|
183
244
|
}
|
|
184
245
|
case "map": {
|
|
@@ -263,7 +324,7 @@ export function fromHost(v, t, o, inOption = false) {
|
|
|
263
324
|
}
|
|
264
325
|
if (v instanceof InternalErrorContext)
|
|
265
326
|
return v;
|
|
266
|
-
//
|
|
327
|
+
// realm boundary (contracts/embedder-api.md §"Error-context is message-valued";
|
|
267
328
|
// issue #131; definitions.py — an error-context's state is exactly
|
|
268
329
|
// its debug message): a branded carrier of a string `message`, from
|
|
269
330
|
// any copy (or hand-rolled), is accepted by minting a FRESH local
|
|
@@ -272,7 +333,7 @@ export function fromHost(v, t, o, inOption = false) {
|
|
|
272
333
|
typeof v.message === "string") {
|
|
273
334
|
return new InternalErrorContext(v.message);
|
|
274
335
|
}
|
|
275
|
-
// Branded but no string `message` (
|
|
336
|
+
// Branded but no string `message` (§"Module identity and @polyengine/protocol", superseded above only
|
|
276
337
|
// for the message-valued case): a genuinely foreign stateful handle —
|
|
277
338
|
// it lives in another copy's handle table, so it can never be lowered
|
|
278
339
|
// here — but "recognized and named" beats the generic "expected an
|
|
@@ -300,18 +361,19 @@ export function fromHost(v, t, o, inOption = false) {
|
|
|
300
361
|
if (v === null || typeof v !== "object") {
|
|
301
362
|
throw new TypeError(`${o.where}: record expects an object`);
|
|
302
363
|
}
|
|
303
|
-
|
|
364
|
+
const table = recordTable(t);
|
|
365
|
+
checkNoCollisions(t, table.labels, `${o.where}: record`);
|
|
304
366
|
const src = v;
|
|
305
367
|
const out = {};
|
|
306
|
-
for (const f of
|
|
307
|
-
const key =
|
|
308
|
-
if (f.
|
|
368
|
+
for (const f of table.fields) {
|
|
369
|
+
const key = f.js;
|
|
370
|
+
if (f.isOption) {
|
|
309
371
|
// Absent and `undefined` both mean `none` — the two spellings of an
|
|
310
372
|
// optional property.
|
|
311
373
|
const inner = src[key];
|
|
312
374
|
out[f.label] = inner === undefined
|
|
313
375
|
? { none: null }
|
|
314
|
-
: { some: fromHost(inner, f.
|
|
376
|
+
: { some: fromHost(inner, f.optionInner, o, true) };
|
|
315
377
|
continue;
|
|
316
378
|
}
|
|
317
379
|
if (!(key in src)) {
|
|
@@ -333,7 +395,7 @@ export function fromHost(v, t, o, inOption = false) {
|
|
|
333
395
|
}
|
|
334
396
|
case "variant": {
|
|
335
397
|
const { kind, value, has } = tagged(v, o);
|
|
336
|
-
const c = t.cases.
|
|
398
|
+
const c = variantTable(t.cases).get(kind);
|
|
337
399
|
if (c === undefined) {
|
|
338
400
|
throw new TypeError(`${o.where}: unknown variant case '${kind}'`);
|
|
339
401
|
}
|
|
@@ -345,7 +407,7 @@ export function fromHost(v, t, o, inOption = false) {
|
|
|
345
407
|
return { [kind]: fromHost(value, c.type, o) };
|
|
346
408
|
}
|
|
347
409
|
case "enum": {
|
|
348
|
-
if (typeof v !== "string" || !t.
|
|
410
|
+
if (typeof v !== "string" || !enumTable(t).has(v)) {
|
|
349
411
|
throw new TypeError(`${o.where}: enum expects one of ${t.labels.join(" | ")}, got ` +
|
|
350
412
|
describe(v));
|
|
351
413
|
}
|
|
@@ -390,8 +452,8 @@ export function fromHost(v, t, o, inOption = false) {
|
|
|
390
452
|
const src = v;
|
|
391
453
|
const out = {};
|
|
392
454
|
// "lower: absent = false" — an omitted flag is not an error.
|
|
393
|
-
for (const
|
|
394
|
-
out[
|
|
455
|
+
for (const f of flagsTable(t))
|
|
456
|
+
out[f.label] = Boolean(src[f.js]);
|
|
395
457
|
return out;
|
|
396
458
|
}
|
|
397
459
|
case "map":
|
|
@@ -446,7 +508,7 @@ function elemCodec(element, o) {
|
|
|
446
508
|
where: o.where,
|
|
447
509
|
toHost: (v) => element === null ? undefined : toHost(v, element, o),
|
|
448
510
|
fromHost: (v) => element === null ? null : fromHost(v, element, o),
|
|
449
|
-
//
|
|
511
|
+
// resource stream: `own` elements a producer lowered but the reader never took
|
|
450
512
|
// must be destroyed, not leaked — an un-taken element may hold a live
|
|
451
513
|
// platform resource (the tcp `listen` shape: an accepted connection).
|
|
452
514
|
// Top-level `own` is the supported element shape; nested owns inside
|
package/esm/embedder/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Version-canonical import resolution (contracts/embedder-api.md
|
|
2
|
-
// §"Version canonicalization"
|
|
2
|
+
// §"Version canonicalization").
|
|
3
3
|
//
|
|
4
4
|
// Authorities, read before writing this:
|
|
5
5
|
// * Explainer.md §"canonical interface names" (`canonversion`) — the spec's
|
|
@@ -149,9 +149,9 @@ export class ImportResolver {
|
|
|
149
149
|
`to '@0' and this registration could never be resolved.`);
|
|
150
150
|
}
|
|
151
151
|
if (p.version === null) {
|
|
152
|
-
// Unversioned: matched exactly and never folded onto a track (
|
|
153
|
-
//
|
|
154
|
-
//
|
|
152
|
+
// Unversioned: matched exactly and never folded onto a track (the banned
|
|
153
|
+
// defect is version-agnostic keys merging distinct semver tracks).
|
|
154
|
+
// Recorded so resolution can *say so* instead of reporting a
|
|
155
155
|
// bare "not provided".
|
|
156
156
|
if (p.base.includes("/") || p.base.includes(":")) {
|
|
157
157
|
this.#unversioned.set(p.base, key);
|
|
@@ -212,9 +212,9 @@ export class ImportResolver {
|
|
|
212
212
|
return { key: claim.key, value: this.#exact.get(claim.key) };
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
|
-
// CONTRACT: contracts/embedder-api.md
|
|
216
|
-
//
|
|
217
|
-
//
|
|
215
|
+
// CONTRACT: contracts/embedder-api.md §"Version canonicalization" bans
|
|
216
|
+
// "unversioned folding": "unversioned keys -> error". Read
|
|
217
|
+
// conservatively: an unversioned key is still a legal
|
|
218
218
|
// *exact* match for an unversioned import (the ban is about folding
|
|
219
219
|
// distinct semver tracks together, and unversioned WIT interfaces
|
|
220
220
|
// exist), but it may never serve a *versioned* import. That attempt is
|
|
@@ -223,7 +223,7 @@ export class ImportResolver {
|
|
|
223
223
|
if (un !== undefined) {
|
|
224
224
|
throw new ImportResolutionError(`import '${id}' is versioned but the only registration for ` +
|
|
225
225
|
`'${p.base}' is the unversioned key '${un}'. Version-agnostic ` +
|
|
226
|
-
`folding is banned (contracts/embedder-api.md
|
|
226
|
+
`folding is banned (contracts/embedder-api.md §"Version canonicalization"): ` +
|
|
227
227
|
`register '${p.base}@${p.version}' or the compatibility-track ` +
|
|
228
228
|
`key '${trackKeyOf(p.base, p.semver) ?? p.base + "@" + p.version}'.`);
|
|
229
229
|
}
|
|
@@ -236,7 +236,7 @@ export class ImportResolver {
|
|
|
236
236
|
if (near.length > 0) {
|
|
237
237
|
throw new ImportResolutionError(`import '${id}' is unversioned but the registrations for it are ` +
|
|
238
238
|
`versioned (${near.join(", ")}). Version-agnostic folding is ` +
|
|
239
|
-
`banned (contracts/embedder-api.md
|
|
239
|
+
`banned (contracts/embedder-api.md §"Version canonicalization").`);
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
return undefined;
|