char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somport stdio extension to typescriptf20b64f

main
2.4 KiB85 linesraw
1import { safePromise } from "ext:core/promises";
2import {
3  ArrayBufferPrototypeGetResizable,
4  getter,
5  TypedArrayPrototypeGetBuffer,
6  TypedArrayPrototypeGetByteLength,
7  TypedArrayPrototypeGetTag,
8  TypeError,
9  Uint8Array,
10  Uint8ArrayPrototypeSet,
11} from "ext:core/primordials";
12import {
13  op_stdio_cancel_read,
14  op_stdio_flush,
15  op_stdio_read,
16  op_stdio_write,
17} from "ext:core/ops";
18import {
19  byobRequest as getRequest,
20  close,
21  enqueue,
22  ReadableStream,
23  ReadableStreamBYOBRequest,
24  respond,
25  WritableStream,
26} from "ext:webstreams/streams.js";
27const getView = getter(ReadableStreamBYOBRequest.prototype, "view");
28
29let canceled = false;
30const stdin = new ReadableStream<Uint8Array<ArrayBuffer>>({
31  type: "bytes",
32  async pull(controller) {
33    const request = getRequest(controller);
34    const view = request && getView(request);
35    const bytes = await safePromise(op_stdio_read(
36      view ? TypedArrayPrototypeGetByteLength(view) : 64 * 1024,
37    ));
38    if (canceled) return;
39    if (bytes === null) {
40      close(controller);
41      if (request) respond(request, 0);
42    } else if (request) {
43      Uint8ArrayPrototypeSet(view!, bytes);
44      respond(request, TypedArrayPrototypeGetByteLength(bytes));
45    } else {
46      enqueue(controller, bytes);
47    }
48  },
49  cancel() {
50    canceled = true;
51    op_stdio_cancel_read();
52  },
53}, { highWaterMark: 0 });
54
55const output = (stderr: boolean) =>
56  new WritableStream<Uint8Array<ArrayBufferLike>>({
57    write(bytes) {
58      if (TypedArrayPrototypeGetTag(bytes) !== "Uint8Array") {
59        throw new TypeError("Stdio writes require Uint8Array chunks");
60      }
61      const buffer = TypedArrayPrototypeGetBuffer(bytes);
62      let snapshot: boolean;
63      try {
64        snapshot = ArrayBufferPrototypeGetResizable(buffer);
65      } catch {
66        snapshot = true; // SharedArrayBuffer fails the ArrayBuffer brand check.
67      }
68      // serde_v8 needs fixed, unshared storage; the captured constructor copies only the view.
69      if (snapshot) bytes = new Uint8Array(bytes);
70      return op_stdio_write([stderr, bytes as Uint8Array<ArrayBuffer>]);
71    },
72    close() {
73      return op_stdio_flush(stderr);
74    },
75  }, {
76    highWaterMark: 64 * 1024,
77    size(bytes) {
78      return TypedArrayPrototypeGetTag(bytes) === "Uint8Array"
79        ? TypedArrayPrototypeGetByteLength(bytes)
80        : 1;
81    },
82  });
83
84const stdout = output(false), stderr = output(true);
85export { stderr, stdin, stdout };