1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
(function() {
var elem = document.querySelector('#output');
window.mergedLibrary = {};
// Glue references wasm exports through the asmjs-mangled identifiers
// that emcc's `assignWasmExports` receiving code binds at the top level.
window.wasmExports = {};
window.___wbindgen_start = () => {};
window.__initialize = () => {};
window.___wbg_wasmbindgentestcontext_free = () => {};
window.___wbg_interval_free = () => {};
window.cachedTextEncoder = { encodeInto: () => {} };
window.cachedTextDecoder = { decode: () => {} };
window.Module = {};
window.addToLibrary = function(obj) {
Object.assign(window.mergedLibrary, obj);
};
// Symbol attribute (decorator) suffixes: `$name__deps`, `$name__postset`,
// `$name__export`, `$name__force` are attributes of `$name`, not library
// symbols in their own right.
var DECORATORS = ['__deps', '__postset', '__export', '__force'];
function isDecorator(key) {
return DECORATORS.some(function(d) { return key.endsWith(d); });
}
// Run once every classic script, including library_bindgen.js after this
// one, has evaluated.
document.addEventListener('DOMContentLoaded', function() {
try {
if (typeof window.mergedLibrary.$initBindgen !== 'function') {
throw new Error("$initBindgen not found in the merged library.");
}
// Execute the initialization (assigns `wasm`, runs start).
window.mergedLibrary.$initBindgen();
// Each clean export is a hoisted `$<name>` library symbol carrying
// `$<name>__export: true` (and `__force`). Under emscripten that
// makes it a named ESM export (instance mode) and, via the symbol's
// `Module['<name>'] = <name>` __postset, a `Module` property
// (factory mode). Discover the exports from the `__export`
// attributes and simulate the Module attachment directly from the
// symbols rather than evaluating postset source.
window.exportedSymbols = new Set();
for (const key of Object.keys(window.mergedLibrary)) {
if (!key.startsWith('$') || isDecorator(key)) continue;
if (window.mergedLibrary[key + '__export'] === true) {
window.exportedSymbols.add(key.slice(1));
}
}
for (const name of window.exportedSymbols) {
window.Module[name] = window.mergedLibrary['$' + name];
}
} catch (e) {
elem.textContent += 'test setup failed: ' + e;
return;
}
function testInitBindgenForced() {
// `$initBindgen` roots the library graph: it must be `__force`d
// and its `__deps` must carry the global helper symbols
// (previously kept via `extraLibraryFuncs`).
if (window.mergedLibrary.$initBindgen__force !== true) {
return { status: false, e: 'test result: $initBindgen is not __force: true' };
}
const deps = window.mergedLibrary.$initBindgen__deps || [];
const required = ['$addOnInit', '$CLOSURE_DTORS', '$WASM_VECTOR_LEN'];
for (const value of required) {
if (!deps.includes(value)) {
return { status: false, e: `test result: ${value} not found in $initBindgen__deps` };
}
}
return { status: true, e: 'test result: ok' };
}
function testModuleExports() {
// Validate that the exports were successfully mapped to the Module
if (typeof Module.hello !== 'function') {
return { status: false, e: 'test result: hello() is not found in Module' };
}
// Classes are `=`-prefixed string snippets (jsifier emits them as
// `var Interval = class Interval {...};`) so they never become
// `export class` declarations.
if (typeof Module.Interval !== 'string' || !Module.Interval.startsWith('=class ')) {
return { status: false, e: 'test result: Interval is not a class value snippet' };
}
// `tokio_sleep_ms` is a `#[wasm_bindgen(experimental_tokio)]` export: its
// presence checks the tokio-attribute expansion survived the
// full CLI pipeline into the emscripten glue.
if (typeof Module.tokio_sleep_ms !== 'function') {
return { status: false, e: 'test result: tokio_sleep_ms() is not found in Module' };
}
// The hoisted exports must carry both attributes so emscripten
// emits them as named ESM exports under -sMODULARIZE=instance.
for (const name of ['hello', 'Interval', 'tokio_sleep_ms']) {
if (!window.exportedSymbols.has(name)) {
return { status: false, e: `test result: ${name} does not carry __export: true` };
}
if (window.mergedLibrary['$' + name + '__force'] !== true) {
return { status: false, e: `test result: ${name} does not carry __force: true` };
}
}
// Search the accumulated library object for the specific imports
const keys = Object.keys(window.mergedLibrary);
const testNames = ['clearInterval', 'setInterval', 'log'];
for (const name of testNames) {
const regex = new RegExp(`^__wbg_${name}`);
const res = keys.find(key => regex.test(key));
if (!res) {
return { status: false, e: `test result: ${name} not found in mergedLibrary` };
}
}
return { status: true, e: 'test result: ok' };
}
const tests = [testInitBindgenForced(), testModuleExports()];
for (const res of tests) {
if (!res.status) {
elem.textContent += res.e;
return;
}
}
elem.textContent +='test result: ok';
});
})();