Skip to content

Commit b8f99e8

Browse files
Move consolePrinter to its own file to expose it as a public API
1 parent c367729 commit b8f99e8

File tree

2 files changed

+96
-59
lines changed

2 files changed

+96
-59
lines changed

packages/npm-packages/ruby-wasm-wasi/src/browser.ts

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,6 @@
11
import { init, WASI } from "@wasmer/wasi";
22
import { RubyVM } from "./index.js";
3-
4-
const consolePrinter = () => {
5-
let memory: WebAssembly.Memory | undefined = undefined;
6-
let view: DataView | undefined = undefined;
7-
8-
const decoder = new TextDecoder();
9-
10-
return {
11-
addToImports(imports: WebAssembly.Imports): void {
12-
const original = imports.wasi_snapshot_preview1.fd_write as (
13-
fd: number,
14-
iovs: number,
15-
iovsLen: number,
16-
nwritten: number,
17-
) => number;
18-
imports.wasi_snapshot_preview1.fd_write = (
19-
fd: number,
20-
iovs: number,
21-
iovsLen: number,
22-
nwritten: number,
23-
): number => {
24-
if (fd !== 1 && fd !== 2) {
25-
return original(fd, iovs, iovsLen, nwritten);
26-
}
27-
28-
if (typeof memory === "undefined" || typeof view === "undefined") {
29-
throw new Error("Memory is not set");
30-
}
31-
if (view.buffer.byteLength === 0) {
32-
view = new DataView(memory.buffer);
33-
}
34-
35-
const buffers = Array.from({ length: iovsLen }, (_, i) => {
36-
const ptr = iovs + i * 8;
37-
const buf = view.getUint32(ptr, true);
38-
const bufLen = view.getUint32(ptr + 4, true);
39-
return new Uint8Array(memory.buffer, buf, bufLen);
40-
});
41-
42-
let written = 0;
43-
let str = "";
44-
for (const buffer of buffers) {
45-
str += decoder.decode(buffer);
46-
written += buffer.byteLength;
47-
}
48-
view.setUint32(nwritten, written, true);
49-
50-
const log = fd === 1 ? console.log : console.warn;
51-
log(str);
52-
53-
return 0;
54-
};
55-
},
56-
setMemory(m: WebAssembly.Memory) {
57-
memory = m;
58-
view = new DataView(m.buffer);
59-
},
60-
};
61-
};
3+
import { consolePrinter } from "./console.js";
624

635
export const DefaultRubyVM = async (
646
rubyModule: WebAssembly.Module,
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* Create a console printer that can be used as an overlay of WASI imports.
3+
* See the example below for how to use it.
4+
*
5+
* ```javascript
6+
* const imports = {
7+
* "wasi_snapshot_preview1": wasi.wasiImport,
8+
* }
9+
* const printer = consolePrinter();
10+
* printer.addToImports(imports);
11+
*
12+
* const instance = await WebAssembly.instantiate(module, imports);
13+
* printer.setMemory(instance.exports.memory);
14+
* ```
15+
*
16+
* Note that the `stdout` and `stderr` functions are called with text, not
17+
* bytes. This means that bytes written to stdout/stderr will be decoded as
18+
* UTF-8 and then passed to the `stdout`/`stderr` functions every time a write
19+
* occurs without buffering.
20+
*
21+
* @param stdout A function that will be called when stdout is written to.
22+
* Defaults to `console.log`.
23+
* @param stderr A function that will be called when stderr is written to.
24+
* Defaults to `console.warn`.
25+
* @returns An object that can be used as an overlay of WASI imports.
26+
*/
27+
export function consolePrinter(
28+
{
29+
stdout,
30+
stderr,
31+
}: {
32+
stdout: (str: string) => void;
33+
stderr: (str: string) => void;
34+
} = {
35+
stdout: console.log,
36+
stderr: console.warn,
37+
},
38+
) {
39+
let memory: WebAssembly.Memory | undefined = undefined;
40+
let view: DataView | undefined = undefined;
41+
42+
const decoder = new TextDecoder();
43+
44+
return {
45+
addToImports(imports: WebAssembly.Imports): void {
46+
const original = imports.wasi_snapshot_preview1.fd_write as (
47+
fd: number,
48+
iovs: number,
49+
iovsLen: number,
50+
nwritten: number,
51+
) => number;
52+
imports.wasi_snapshot_preview1.fd_write = (
53+
fd: number,
54+
iovs: number,
55+
iovsLen: number,
56+
nwritten: number,
57+
): number => {
58+
if (fd !== 1 && fd !== 2) {
59+
return original(fd, iovs, iovsLen, nwritten);
60+
}
61+
62+
if (typeof memory === "undefined" || typeof view === "undefined") {
63+
throw new Error("Memory is not set");
64+
}
65+
if (view.buffer.byteLength === 0) {
66+
view = new DataView(memory.buffer);
67+
}
68+
69+
const buffers = Array.from({ length: iovsLen }, (_, i) => {
70+
const ptr = iovs + i * 8;
71+
const buf = view.getUint32(ptr, true);
72+
const bufLen = view.getUint32(ptr + 4, true);
73+
return new Uint8Array(memory.buffer, buf, bufLen);
74+
});
75+
76+
let written = 0;
77+
let str = "";
78+
for (const buffer of buffers) {
79+
str += decoder.decode(buffer);
80+
written += buffer.byteLength;
81+
}
82+
view.setUint32(nwritten, written, true);
83+
84+
const log = fd === 1 ? stdout : stderr;
85+
log(str);
86+
87+
return 0;
88+
};
89+
},
90+
setMemory(m: WebAssembly.Memory) {
91+
memory = m;
92+
view = new DataView(m.buffer);
93+
},
94+
};
95+
}

0 commit comments

Comments
 (0)