Skip to content

Instantly share code, notes, and snippets.

@okikio
Last active January 10, 2023 06:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save okikio/6eb88f317ceeb2146b8268a255744fc6 to your computer and use it in GitHub Desktop.
Save okikio/6eb88f317ceeb2146b8268a255744fc6 to your computer and use it in GitHub Desktop.
uint8array-to-utf-8.ts

Perf.

Make sure the Uint8Array has at least 4 bytes or you know that the stream isn't done.

e.g. https://codepen.io/okikio/pen/MWBjdNB?editors=0011

import { asCodePoints } from "uint8array-to-utf-8"

function later(delay) {
  return new Promise(resolve => setTimeout(resolve, delay));
}

function createResponse(sliceLen = 12) {
  return new Response(
    new ReadableStream({
      async start(controller) {
        const buffer = new TextEncoder().encode(
          `.c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€”`,
        );

        let i = sliceLen, len = buffer.length - sliceLen;
        for (; i < len; i += sliceLen) {
          controller.enqueue(buffer.slice(i - sliceLen, i));
          await later(2);
        }

        controller.enqueue(buffer.slice(len));
        controller.close();
      },
    }),
  );
}

async function* getIterableStream(stream) {
  const reader = stream.getReader();

  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) return;
      yield value;
    }
  } finally {
    reader.releaseLock();
  }
}

async function main() {
  const response = createResponse();
  
  for await (const codePoint of asCodePoints(getIterableStream(response.body))) {
    console.log(String.fromCodePoint(codePoint));
  }
}

main();
// 1-byte encoding
const LEAD_OF_1B = 0x80 // 1000 0000 (lead byte of 1-byte encoding)
const MASK_OF_1B = 0x3F // 0011 1111
// 2-byte encoding
const BITS_OF_2B = 6 // bits 7 -> 12
const LEAD_OF_2B = 0xC0 // 1100 0000 (lead byte of 2-byte encoding)
const MASK_OF_2B = 0x1F // 0001 1111
// 3-byte encoding
const BITS_OF_3B = 12 // bits 13 -> 18
const LEAD_OF_3B = 0xE0 // 1110 0000 (lead byte of 3-byte encoding)
const MASK_OF_3B = 0x0F // 0000 1111
// 4-byte encoding
const BITS_OF_4B = 18 // highest bits 19 -> 21
const LEAD_OF_4B = 0xF0 // 1111 0000 (lead byte of 4-byte encoding)
const MASK_OF_4B = 0x07 // 0000 0111
// 5-byte encoding
const LEAD_OF_5B = 0xF8 // 1111 1000 (lead byte of 5-byte encoding)
export function* getUTF8CodePoints(/** @type {Uint8Array} */ bytes) {
let i = -1, /** @type {number} */ byte;
while (++i < bytes.length) {
byte = bytes[i]
yield (
// 1-byte UTF-8 sequence
byte < LEAD_OF_1B ?
byte
// 2-byte UTF-8 sequence
: LEAD_OF_2B == (LEAD_OF_3B & byte) ?
(MASK_OF_2B & byte) << BITS_OF_2B |
MASK_OF_1B & bytes[++i]
// 3-byte UTF-8 sequence
: LEAD_OF_3B == (LEAD_OF_4B & byte) ?
(MASK_OF_3B & byte) << BITS_OF_3B |
(MASK_OF_1B & bytes[++i]) << BITS_OF_2B |
MASK_OF_1B & bytes[++i]
// 4-byte UTF-8 sequence
: LEAD_OF_4B == (LEAD_OF_5B & byte) ?
(MASK_OF_4B & byte) << BITS_OF_4B |
(MASK_OF_1B & bytes[++i]) << BITS_OF_3B |
(MASK_OF_1B & bytes[++i]) << 6 |
MASK_OF_1B & bytes[++i]
// 1-byte UTF-8 sequence (fallback)
: byte
)
}
}
import { asCodePoints } from "./uint8array-to-utf-8";
/* ========================================================================== */
function later(delay) {
return new Promise(resolve => setTimeout(resolve, delay));
}
/* ========================================================================== */
function createResponse(sliceLen = 12) {
return new Response(
new ReadableStream({
async start(controller) {
const buffer = new TextEncoder().encode(
`.c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€” .c\\πŸ€” { color: blue; } /* πŸ€”πŸ€”πŸ€”`,
);
let i = sliceLen, len = buffer.length - sliceLen;
for (; i < len; i += sliceLen) {
controller.enqueue(buffer.slice(i - sliceLen, i));
await later(2);
}
controller.enqueue(buffer.slice(len));
controller.close();
},
}),
);
}
/* ========================================================================== */
async function* getIterableStream(stream) {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) return;
yield value;
}
} finally {
reader.releaseLock();
}
}
/* ========================================================================== */
async function main() {
const response = createResponse();
for await (const codePoint of asCodePoints(getIterableStream(response.body))) {
console.log(String.fromCodePoint(codePoint));
}
}
main();
// 1-byte encoding
const LEAD_FOR_1B = 0x80; // 1000 0000
const MASK_FOR_1B = 0x3F; // 0011 1111
// 2-byte encoding
const BITS_FOR_2B = 6; // bits 7 -> 12
const LEAD_FOR_2B = 0xC0; // 1100 0000
const MASK_FOR_2B = 0x1F; // 0001 1111
// 3-byte encoding
const BITS_FOR_3B = 12; // bits 13 -> 18
const LEAD_FOR_3B = 0xE0; // 1110 0000
const MASK_FOR_3B = 0x0F; // 0000 1111
// 4-byte encoding
const BITS_FOR_4B = 18; // highest bits 19 -> 21
const LEAD_FOR_4B = 0xF0; // 1111 0000
const MASK_FOR_4B = 0x07; // 0000 0111
// 5-byte encoding
const LEAD_FOR_5B = 0xF8; // 1111 1000
/* ========================================================================== */
export function getByteLength(byte) {
return (
byte < LEAD_FOR_1B ? 1 :
LEAD_FOR_2B === (LEAD_FOR_3B & byte) ? 2 :
LEAD_FOR_3B === (LEAD_FOR_4B & byte) ? 3 :
LEAD_FOR_4B === (LEAD_FOR_5B & byte) ? 4 : 1
);
}
/* ========================================================================== */
/**
* UTF-8 bytes to code point
*
* UTF-8 can be represented by 1 to 4 bytes, this help calculate
*/
export function bytesToCodePoint(byteLength, [byte1, byte2, byte3, byte4]) {
return (
// 1-byte UTF-8 sequence
byteLength === 1 ?
byte1
// 2-byte UTF-8 sequence
: byteLength === 2 ?
(MASK_FOR_2B & byte1) << BITS_FOR_2B |
MASK_FOR_1B & byte2
// 3-byte UTF-8 sequence
: byteLength === 3 ?
(MASK_FOR_3B & byte1) << BITS_FOR_3B |
(MASK_FOR_1B & byte2) << BITS_FOR_2B |
MASK_FOR_1B & byte3
// 4-byte UTF-8 sequence
: byteLength === 4 ?
(MASK_FOR_4B & byte1) << BITS_FOR_4B |
(MASK_FOR_1B & byte2) << BITS_FOR_3B |
(MASK_FOR_1B & byte3) << 6 |
MASK_FOR_1B & byte4
// 1-byte UTF-8 sequence (fallback)
: byte1
);
}
/* ========================================================================== */
export async function* asCodePoints<T extends unknown>(
iterable: Iterator<T, Uint8Array>,
) {
/**
* - `byteSequence` is the array of the UTF-8 byte sequence being evaluated.
* - `byteSequenceTalliedLength` is the length of the UTF-8 byte sequence as determined by the lead byte.
* - `byteSequenceCurrentLength` is the length of the UTF-8 byte sequence as consumed by the iterator.
*/
const byteSequence = [];
let byteSequenceCurrentLength = 0;
let byteSequenceTalliedLength = 0;
for await (const bytes of iterable) {
for (const byte of bytes) {
byteSequenceCurrentLength = byteSequence.push(byte);
if (byteSequenceTalliedLength === 0) {
byteSequenceTalliedLength = getByteLength(byte);
}
if (byteSequenceTalliedLength === byteSequenceCurrentLength) {
yield bytesToCodePoint(
byteSequenceTalliedLength,
byteSequence.splice(0),
);
byteSequenceTalliedLength = 0;
byteSequenceCurrentLength = 0;
}
}
}
if (byteSequenceCurrentLength > 0) {
yield bytesToCodePoint(byteSequenceTalliedLength, byteSequence.splice(0));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment