@amritk/nish-x86_64-linux 0.18.0 → 0.21.0
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/INSTALL.md +58 -28
- package/bin/nish +0 -0
- package/docs/AI.md +2759 -0
- package/package.json +3 -2
- package/runtime/browser.d.ts +14 -0
- package/runtime/browser.mjs +88 -0
- package/runtime/core/arrays.d.ts +18 -0
- package/runtime/core/arrays.mjs +125 -0
- package/runtime/core/checks.mjs +20 -0
- package/runtime/core/host.d.ts +70 -0
- package/runtime/core/host.mjs +311 -0
- package/runtime/core/numbers.d.ts +53 -0
- package/runtime/core/numbers.mjs +316 -0
- package/runtime/core/result.d.ts +41 -0
- package/runtime/core/result.mjs +127 -0
- package/runtime/core/strings.d.ts +14 -0
- package/runtime/core/strings.mjs +169 -0
- package/runtime/core.d.ts +9 -0
- package/runtime/core.mjs +55 -0
- package/runtime/host.d.ts +6 -0
- package/runtime/nish.d.ts +99 -5
- package/runtime/nish.h +289 -19
- package/runtime/nish.mjs +39 -3
- package/runtime/node.mjs +383 -0
- package/runtime/runtime-aes.c +490 -0
- package/runtime/runtime-bytes.c +401 -0
- package/runtime/runtime-cross.c +366 -0
- package/runtime/runtime-host.c +8 -7
- package/runtime/runtime-net.c +93 -34
- package/runtime/runtime-os.c +214 -16
- package/runtime/runtime-parallel.c +590 -107
- package/runtime/runtime-simd.c +235 -11
- package/runtime/runtime-term.c +504 -0
- package/runtime/runtime-wasm.c +5 -14
- package/runtime/runtime.c +257 -17
- package/runtime/shim.mjs +6 -915
- package/runtime/sqlite/LICENSE.md +85 -0
- package/runtime/sqlite/README.md +45 -0
- package/runtime/sqlite/nish-sqlite.c +359 -0
- package/runtime/sqlite/sqlite3.c +271131 -0
- package/runtime/sqlite/sqlite3.h +14447 -0
- package/scripts/build.sh +437 -28
- package/std/LICENSE-fast-float +23 -0
- package/std/LICENSE-fdlibm +8 -0
- package/std/README.md +108 -58
- package/std/base64.ts +116 -0
- package/std/bytes.ts +419 -0
- package/std/cli.ts +328 -0
- package/std/collections.ts +6 -5
- package/std/crypto/LICENSE-crypt_blowfish +26 -0
- package/std/crypto/LICENSE-libsecp256k1 +19 -0
- package/std/crypto/aes.ts +238 -76
- package/std/crypto/base64url.ts +125 -0
- package/std/crypto/bcrypt.ts +760 -0
- package/std/crypto/chacha20poly1305.ts +43 -9
- package/std/crypto/ed25519.ts +840 -0
- package/std/crypto/hkdf.ts +304 -12
- package/std/crypto/hmac.ts +382 -54
- package/std/crypto/p256.ts +932 -61
- package/std/crypto/x25519.ts +55 -37
- package/std/crypto/x509-random.ts +71 -0
- package/std/crypto/x509.ts +20 -131
- package/std/json-tokenizer.ts +4237 -0
- package/std/json-typed.ts +1014 -0
- package/std/json-value.ts +1182 -0
- package/std/json.ts +1202 -34
- package/std/math.ts +608 -0
- package/std/net/buffer-pool.ts +151 -0
- package/std/net/hpack.ts +416 -112
- package/std/net/http-fields.ts +93 -0
- package/std/net/http1-server.ts +501 -62
- package/std/net/http1.ts +31 -6
- package/std/net/http2-tls.ts +112 -24
- package/std/net/http2.ts +333 -75
- package/std/net/http3-server.ts +261 -43
- package/std/net/http3.ts +187 -28
- package/std/net/postgres.ts +1875 -0
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-listener.ts +108 -11
- package/std/net/quic-packet.ts +243 -82
- package/std/net/quic-recovery.ts +361 -30
- package/std/net/quic-stream.ts +424 -24
- package/std/net/quic.ts +519 -167
- package/std/net/router.ts +676 -0
- package/std/net/tls/codec.ts +426 -27
- package/std/net/tls/record-server.ts +478 -132
- package/std/net/tls/record.ts +133 -42
- package/std/net/tls/schedule.ts +464 -55
- package/std/net/tls/ticket.ts +610 -0
- package/std/net/tls-tcp.ts +196 -53
- package/std/net/tls.ts +1018 -260
- package/std/net/url.ts +571 -0
- package/std/random.ts +94 -0
- package/std/regex.ts +4274 -0
- package/std/sqlite.ts +391 -0
- package/std/term-io.ts +978 -0
- package/std/term-pixels.ts +874 -0
- package/std/term-probe.ts +459 -0
- package/std/term-rate.ts +993 -0
- package/std/term.ts +2453 -0
- package/std/text.ts +90 -7
- package/std/threads.ts +438 -14
- package/std/yaml-lines.ts +141 -0
- package/std/yaml.ts +4675 -0
package/std/base64.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nish/base64` — standard base64 (RFC 4648 §4) with `=` padding, the encoding
|
|
3
|
+
* kitty graphics frames are sent in.
|
|
4
|
+
*
|
|
5
|
+
* The alphabet is `A-Z a-z 0-9 + /`. Every three bytes become four characters,
|
|
6
|
+
* and a final group of one or two bytes becomes two or three characters filled
|
|
7
|
+
* out to four with `=` (RFC 4648 §4, the padding rules of §3.2), so the text is
|
|
8
|
+
* always a multiple of four long.
|
|
9
|
+
*
|
|
10
|
+
* - `base64EncodedLength(n)` is the characters `n` bytes encode to.
|
|
11
|
+
* - `base64EncodeInto(src, off, len, dst, at)` writes the encoding of
|
|
12
|
+
* `src[off..off+len)` into `dst` from `at` and allocates nothing, so a frame
|
|
13
|
+
* can be encoded chunk by chunk straight into its output buffer.
|
|
14
|
+
* - `base64Encode(bytes)` is the whole array as a string.
|
|
15
|
+
*
|
|
16
|
+
* This module only encodes: what it is for writes base64 and never reads it
|
|
17
|
+
* back. It is not the strict decoder of `nish/crypto/base64url`, which is a
|
|
18
|
+
* different alphabet without padding and is written not to branch on the data;
|
|
19
|
+
* what goes through here is pixels, not secrets, so a sextet becomes its
|
|
20
|
+
* character by indexing the alphabet. The output is ASCII, so the string is
|
|
21
|
+
* the same bytes natively and under Node.
|
|
22
|
+
*
|
|
23
|
+
* Private helpers share the importing program's flat symbol namespace
|
|
24
|
+
* (`docs/wp26-stdlib.md` §3e), which is why each one carries the module's name.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** The 64 characters of RFC 4648 §4's Table 1, in value order. */
|
|
28
|
+
const BASE64_ALPHABET: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
29
|
+
|
|
30
|
+
/** `=`, which fills a short final group out to four characters (RFC 4648 §3.2). */
|
|
31
|
+
const BASE64_PAD: i32 = 61
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The characters `n` bytes encode to: four for every three, a short final
|
|
35
|
+
* group counted as a whole one. Panics when `n` is negative or the length
|
|
36
|
+
* would pass 2^31 - 1, which `n` above 1,610,612,733 does.
|
|
37
|
+
*/
|
|
38
|
+
export const base64EncodedLength = (n: i32): i32 => {
|
|
39
|
+
if (n < 0) {
|
|
40
|
+
panic("base64EncodedLength: a negative byte count")
|
|
41
|
+
}
|
|
42
|
+
// (2^31 - 1) / 4 * 3 groups' worth of bytes is the most whose encoding fits.
|
|
43
|
+
if (n > 1610612733) {
|
|
44
|
+
panic("base64EncodedLength: the encoding is longer than 2^31 - 1 characters")
|
|
45
|
+
}
|
|
46
|
+
return (((n + 2) / 3) | 0) * 4
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The byte of the character for the sextet `v` (`0 <= v <= 63`). */
|
|
50
|
+
const base64CharOf = (v: i32): u8 => toU8(BASE64_ALPHABET.charCodeAt(v))
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Write the base64 of `src[off..off+len)` into `dst` from index `at`, and
|
|
54
|
+
* answer the index just past the last character written, which is
|
|
55
|
+
* `at + base64EncodedLength(len)`. Nothing is allocated. Panics when the source
|
|
56
|
+
* range is not inside `src` or the encoding does not fit in `dst` from `at`;
|
|
57
|
+
* both are checked before anything is written.
|
|
58
|
+
*/
|
|
59
|
+
export const base64EncodeInto = (src: u8[], off: i32, len: i32, dst: u8[], at: i32): i32 => {
|
|
60
|
+
// Refused before `toI32`, which saturates a longer length under
|
|
61
|
+
// `--number-mode f64` and would let a range past the true end through.
|
|
62
|
+
if (src.length > 2147483647 || dst.length > 2147483647) {
|
|
63
|
+
panic("base64EncodeInto: an array longer than 2^31 - 1 bytes")
|
|
64
|
+
}
|
|
65
|
+
const srcLength: i32 = toI32(src.length)
|
|
66
|
+
const dstLength: i32 = toI32(dst.length)
|
|
67
|
+
if (off < 0 || len < 0 || off > srcLength - len) {
|
|
68
|
+
panic("base64EncodeInto: the source range is outside the array")
|
|
69
|
+
}
|
|
70
|
+
const need: i32 = base64EncodedLength(len)
|
|
71
|
+
if (at < 0 || at > dstLength - need) {
|
|
72
|
+
panic("base64EncodeInto: the encoding does not fit in the destination")
|
|
73
|
+
}
|
|
74
|
+
let i: i32 = off
|
|
75
|
+
let o: i32 = at
|
|
76
|
+
const whole: i32 = off + len - (len % 3)
|
|
77
|
+
// The checks above make every term after the first true; they are written out
|
|
78
|
+
// because they are what proves the loop's accesses in range.
|
|
79
|
+
while (i < whole && i >= 0 && i + 2 < srcLength && o >= 0 && o + 3 < dstLength) {
|
|
80
|
+
const group: i32 = (toI32(src[i]) << 16) | (toI32(src[i + 1]) << 8) | toI32(src[i + 2])
|
|
81
|
+
dst[o] = base64CharOf(group >> 18)
|
|
82
|
+
dst[o + 1] = base64CharOf((group >> 12) & 63)
|
|
83
|
+
dst[o + 2] = base64CharOf((group >> 6) & 63)
|
|
84
|
+
dst[o + 3] = base64CharOf(group & 63)
|
|
85
|
+
i = i + 3
|
|
86
|
+
o = o + 4
|
|
87
|
+
}
|
|
88
|
+
const tail: i32 = len % 3
|
|
89
|
+
if (tail === 1) {
|
|
90
|
+
const group: i32 = toI32(src[i]) << 16
|
|
91
|
+
dst[o] = base64CharOf(group >> 18)
|
|
92
|
+
dst[o + 1] = base64CharOf((group >> 12) & 63)
|
|
93
|
+
dst[o + 2] = toU8(BASE64_PAD)
|
|
94
|
+
dst[o + 3] = toU8(BASE64_PAD)
|
|
95
|
+
o = o + 4
|
|
96
|
+
} else if (tail === 2) {
|
|
97
|
+
const group: i32 = (toI32(src[i]) << 16) | (toI32(src[i + 1]) << 8)
|
|
98
|
+
dst[o] = base64CharOf(group >> 18)
|
|
99
|
+
dst[o + 1] = base64CharOf((group >> 12) & 63)
|
|
100
|
+
dst[o + 2] = base64CharOf((group >> 6) & 63)
|
|
101
|
+
dst[o + 3] = toU8(BASE64_PAD)
|
|
102
|
+
o = o + 4
|
|
103
|
+
}
|
|
104
|
+
return o
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** `bytes` as padded base64. Panics past 1,610,612,733 bytes, whose encoding would not fit a string. */
|
|
108
|
+
export const base64Encode = (bytes: u8[]): string => {
|
|
109
|
+
if (bytes.length > 2147483647) {
|
|
110
|
+
panic("base64Encode: more than 2^31 - 1 bytes")
|
|
111
|
+
}
|
|
112
|
+
const n: i32 = toI32(bytes.length)
|
|
113
|
+
const out: u8[] = new Array<u8>(base64EncodedLength(n))
|
|
114
|
+
const end: i32 = base64EncodeInto(bytes, 0, n, out, 0)
|
|
115
|
+
return String.fromBytes(out, 0, end)
|
|
116
|
+
}
|
package/std/bytes.ts
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `std/bytes` — fixed-width integers and doubles read from, and written into,
|
|
3
|
+
* a byte array at an offset, in either byte order.
|
|
4
|
+
*
|
|
5
|
+
* A wire format, a file header or a hash's message schedule is a `u8[]` with
|
|
6
|
+
* numbers laid out in it, and every reader of one writes the same four-line
|
|
7
|
+
* shift-and-or. This module is that loop written once:
|
|
8
|
+
*
|
|
9
|
+
* import { getU32BE, setU16LE } from "nish/bytes";
|
|
10
|
+
*
|
|
11
|
+
* const header: u8[] = [0, 0, 1, 0, 0, 0];
|
|
12
|
+
* const length = getU32BE(header, 0); // 256
|
|
13
|
+
* setU16LE(header, 4, toU16(513)); // header[4] = 1, header[5] = 2
|
|
14
|
+
*
|
|
15
|
+
* Every function takes the array and the offset of its first byte; the `LE`
|
|
16
|
+
* name puts the least significant byte there, the `BE` name the most
|
|
17
|
+
* significant. The widths are `u16`, `u32` and `u64`, the signed `i32` and
|
|
18
|
+
* `i64`, which are the same bytes read as two's complement, and `f64`, whose
|
|
19
|
+
* bytes are its IEEE 754 bits (`f64ToBits`). There is no `f32`: the language
|
|
20
|
+
* has no bit cast for one.
|
|
21
|
+
*
|
|
22
|
+
* Each access is an ordinary index, so an offset whose bytes do not all lie in
|
|
23
|
+
* the array panics `index`, naming the first byte that does not. A guard in
|
|
24
|
+
* the caller does not yet remove these checks: in a loop guarded by
|
|
25
|
+
* `off + 3 < b.length`, the checker proves an index it can see but not one
|
|
26
|
+
* inside a call, and after `getU32LE` inlines, LLVM keeps the checks on
|
|
27
|
+
* `off + 1` to `off + 3`, because the guard compares the length truncated to
|
|
28
|
+
* `i32` and the checks compare it unsigned at 64 bits. A loop that needs them
|
|
29
|
+
* gone indexes the bytes itself.
|
|
30
|
+
*
|
|
31
|
+
* The in-range answers are byte for byte those of the copies `std/` keeps for
|
|
32
|
+
* itself: `sha256LoadWord` (`std/crypto/sha256.ts`) for `getU32BE`,
|
|
33
|
+
* `chacha20Word` and `poly1305Le64` (`std/crypto/chacha20poly1305.ts`) for
|
|
34
|
+
* `getU32LE` and `getU64LE`, `loadWord` and `storeWord` (`std/crypto/sha512.ts`)
|
|
35
|
+
* for `getU64BE` and `setU64BE`, `http2FramePut32` (`std/net/http2-frame.ts`)
|
|
36
|
+
* for `setU32BE`, and `tlsPutU16` (`std/net/tls/codec.ts`) for `setU16BE`. None
|
|
37
|
+
* of them is replaced by this module. Out of range they differ: the AES and
|
|
38
|
+
* TLS word helpers read zero past the end and drop bytes written there, which
|
|
39
|
+
* their callers rely on, where this module panics.
|
|
40
|
+
*
|
|
41
|
+
* Under Node (`docs/RUN_UNDER_NODE.md`) the `u16` and `u32` functions are
|
|
42
|
+
* expected to answer as they do natively, because the top byte of a `u32` is
|
|
43
|
+
* multiplied in rather than shifted and each byte written is masked before
|
|
44
|
+
* its `toU8`: there `<<` turns bit 31 into a sign and the prelude's `toU8`
|
|
45
|
+
* and `toU32` saturate, and natively the multiply and the mask fold into the
|
|
46
|
+
* shift and the truncation. The others do not yet answer there: the `i32`
|
|
47
|
+
* functions cross between signed and unsigned with `toI32` and `toU32`, which
|
|
48
|
+
* the prelude saturates too (`setI32LE(b, 0, -2)` writes zeros), and the
|
|
49
|
+
* 64-bit functions and `f64` meet its BigInt `u64` and `i64`, which `toU8`
|
|
50
|
+
* refuses.
|
|
51
|
+
*
|
|
52
|
+
* The module also has the runs a parser walks and the copy it makes of them.
|
|
53
|
+
* `skipBlank`, `skipDigits`, `skipJsonText` and `skipJsonPlain` each answer
|
|
54
|
+
* the first index in a range whose byte is not in their class — JSON's blanks,
|
|
55
|
+
* the ASCII digits, the bytes a JSON string holds as themselves, the bytes a
|
|
56
|
+
* JSON writer copies without an escape — and `copyBytes` copies a
|
|
57
|
+
* window of one array into another, or into itself, as one move:
|
|
58
|
+
*
|
|
59
|
+
* const text: u8[] = [32, 32, 52, 50, 44]; // " 42,"
|
|
60
|
+
* const start = skipBlank(text, 0, 5); // 2
|
|
61
|
+
* const end = skipDigits(text, start, 5); // 4
|
|
62
|
+
*
|
|
63
|
+
* The four runs clamp their range and never panic; `copyBytes` panics on a
|
|
64
|
+
* range outside its array. Natively each is a runtime kernel
|
|
65
|
+
* (docs/LANGUAGE.md, "Byte runs"), and the runs are variable-time: they are
|
|
66
|
+
* for text, never for secret data.
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/** The `u16` whose low byte is `b[off]` and high byte `b[off + 1]`. */
|
|
70
|
+
export const getU16LE = (b: u8[], off: i32): u16 => toU16(b[off]) | (toU16(b[off + 1]) << 8)
|
|
71
|
+
|
|
72
|
+
/** The `u16` whose high byte is `b[off]` and low byte `b[off + 1]`. */
|
|
73
|
+
export const getU16BE = (b: u8[], off: i32): u16 => (toU16(b[off]) << 8) | toU16(b[off + 1])
|
|
74
|
+
|
|
75
|
+
/** The `u32` whose bytes, least significant first, are `b[off]` to `b[off + 3]`. */
|
|
76
|
+
export const getU32LE = (b: u8[], off: i32): u32 =>
|
|
77
|
+
(toU32(b[off]) | (toU32(b[off + 1]) << 8) | (toU32(b[off + 2]) << 16)) +
|
|
78
|
+
toU32(b[off + 3]) * toU32(0x1000000)
|
|
79
|
+
|
|
80
|
+
/** The `u32` whose bytes, most significant first, are `b[off]` to `b[off + 3]`. */
|
|
81
|
+
export const getU32BE = (b: u8[], off: i32): u32 =>
|
|
82
|
+
toU32(b[off]) * toU32(0x1000000) +
|
|
83
|
+
((toU32(b[off + 1]) << 16) | (toU32(b[off + 2]) << 8) | toU32(b[off + 3]))
|
|
84
|
+
|
|
85
|
+
/** The `u64` whose bytes, least significant first, are `b[off]` to `b[off + 7]`. */
|
|
86
|
+
export const getU64LE = (b: u8[], off: i32): u64 => {
|
|
87
|
+
let v = toU64(0)
|
|
88
|
+
for (let i: i32 = 0; i < 8; i++) {
|
|
89
|
+
v = v | (toU64(b[off + i]) << toU64(i * 8))
|
|
90
|
+
}
|
|
91
|
+
return v
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The `u64` whose bytes, most significant first, are `b[off]` to `b[off + 7]`. */
|
|
95
|
+
export const getU64BE = (b: u8[], off: i32): u64 => {
|
|
96
|
+
let v = toU64(0)
|
|
97
|
+
for (let i: i32 = 0; i < 8; i++) {
|
|
98
|
+
v = (v << toU64(8)) | toU64(b[off + i])
|
|
99
|
+
}
|
|
100
|
+
return v
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** `getU32LE`'s bits as a two's-complement `i32`. */
|
|
104
|
+
export const getI32LE = (b: u8[], off: i32): i32 => toI32(getU32LE(b, off))
|
|
105
|
+
|
|
106
|
+
/** `getU32BE`'s bits as a two's-complement `i32`. */
|
|
107
|
+
export const getI32BE = (b: u8[], off: i32): i32 => toI32(getU32BE(b, off))
|
|
108
|
+
|
|
109
|
+
/** `getU64LE`'s bits as a two's-complement `i64`. */
|
|
110
|
+
export const getI64LE = (b: u8[], off: i32): i64 => toI64(getU64LE(b, off))
|
|
111
|
+
|
|
112
|
+
/** `getU64BE`'s bits as a two's-complement `i64`. */
|
|
113
|
+
export const getI64BE = (b: u8[], off: i32): i64 => toI64(getU64BE(b, off))
|
|
114
|
+
|
|
115
|
+
/** The `f64` whose IEEE 754 bits are `getU64LE`'s. */
|
|
116
|
+
export const getF64LE = (b: u8[], off: i32): f64 => bitsToF64(toI64(getU64LE(b, off)))
|
|
117
|
+
|
|
118
|
+
/** The `f64` whose IEEE 754 bits are `getU64BE`'s. */
|
|
119
|
+
export const getF64BE = (b: u8[], off: i32): f64 => bitsToF64(toI64(getU64BE(b, off)))
|
|
120
|
+
|
|
121
|
+
/** Writes `v` into `b[off]` and `b[off + 1]`, low byte first. */
|
|
122
|
+
export const setU16LE = (b: u8[], off: i32, v: u16): void => {
|
|
123
|
+
b[off] = toU8(v & 255)
|
|
124
|
+
b[off + 1] = toU8((v >> 8) & 255)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Writes `v` into `b[off]` and `b[off + 1]`, high byte first. */
|
|
128
|
+
export const setU16BE = (b: u8[], off: i32, v: u16): void => {
|
|
129
|
+
b[off] = toU8((v >> 8) & 255)
|
|
130
|
+
b[off + 1] = toU8(v & 255)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Writes `v` into `b[off]` to `b[off + 3]`, least significant byte first. */
|
|
134
|
+
export const setU32LE = (b: u8[], off: i32, v: u32): void => {
|
|
135
|
+
b[off] = toU8(v & 255)
|
|
136
|
+
b[off + 1] = toU8((v >> 8) & 255)
|
|
137
|
+
b[off + 2] = toU8((v >> 16) & 255)
|
|
138
|
+
b[off + 3] = toU8((v >> 24) & 255)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Writes `v` into `b[off]` to `b[off + 3]`, most significant byte first. */
|
|
142
|
+
export const setU32BE = (b: u8[], off: i32, v: u32): void => {
|
|
143
|
+
b[off] = toU8((v >> 24) & 255)
|
|
144
|
+
b[off + 1] = toU8((v >> 16) & 255)
|
|
145
|
+
b[off + 2] = toU8((v >> 8) & 255)
|
|
146
|
+
b[off + 3] = toU8(v & 255)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Writes `v` into `b[off]` to `b[off + 7]`, least significant byte first. */
|
|
150
|
+
export const setU64LE = (b: u8[], off: i32, v: u64): void => {
|
|
151
|
+
for (let i: i32 = 0; i < 8; i++) {
|
|
152
|
+
b[off + i] = toU8((v >> toU64(i * 8)) & toU64(255))
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Writes `v` into `b[off]` to `b[off + 7]`, most significant byte first. */
|
|
157
|
+
export const setU64BE = (b: u8[], off: i32, v: u64): void => {
|
|
158
|
+
for (let i: i32 = 0; i < 8; i++) {
|
|
159
|
+
b[off + i] = toU8((v >> toU64((7 - i) * 8)) & toU64(255))
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Writes `v`'s two's-complement bits as `setU32LE` does. */
|
|
164
|
+
export const setI32LE = (b: u8[], off: i32, v: i32): void => setU32LE(b, off, toU32(v))
|
|
165
|
+
|
|
166
|
+
/** Writes `v`'s two's-complement bits as `setU32BE` does. */
|
|
167
|
+
export const setI32BE = (b: u8[], off: i32, v: i32): void => setU32BE(b, off, toU32(v))
|
|
168
|
+
|
|
169
|
+
/** Writes `v`'s two's-complement bits as `setU64LE` does. */
|
|
170
|
+
export const setI64LE = (b: u8[], off: i32, v: i64): void => setU64LE(b, off, toU64(v))
|
|
171
|
+
|
|
172
|
+
/** Writes `v`'s two's-complement bits as `setU64BE` does. */
|
|
173
|
+
export const setI64BE = (b: u8[], off: i32, v: i64): void => setU64BE(b, off, toU64(v))
|
|
174
|
+
|
|
175
|
+
/** Writes `v`'s IEEE 754 bits as `setU64LE` does. */
|
|
176
|
+
export const setF64LE = (b: u8[], off: i32, v: f64): void => setU64LE(b, off, toU64(f64ToBits(v)))
|
|
177
|
+
|
|
178
|
+
/** Writes `v`'s IEEE 754 bits as `setU64BE` does. */
|
|
179
|
+
export const setF64BE = (b: u8[], off: i32, v: f64): void => setU64BE(b, off, toU64(f64ToBits(v)))
|
|
180
|
+
|
|
181
|
+
// ---- Byte-class runs and the byte copy (WP38 S6a) ----------------------------------------
|
|
182
|
+
|
|
183
|
+
/** JSON's four blanks (RFC 8259 §2): space, tab, newline and carriage return. */
|
|
184
|
+
const BYTES_SPACE: i32 = 32
|
|
185
|
+
const BYTES_TAB: i32 = 9
|
|
186
|
+
const BYTES_NEWLINE: i32 = 10
|
|
187
|
+
const BYTES_CARRIAGE_RETURN: i32 = 13
|
|
188
|
+
/** `0` and `9`. */
|
|
189
|
+
const BYTES_DIGIT_ZERO: i32 = 48
|
|
190
|
+
const BYTES_DIGIT_NINE: i32 = 57
|
|
191
|
+
/** The two printable ASCII bytes a JSON string escapes, `"` and `\`. */
|
|
192
|
+
const BYTES_QUOTE: i32 = 34
|
|
193
|
+
const BYTES_BACKSLASH: i32 = 92
|
|
194
|
+
/** The first byte that is not ASCII, and the continuation bytes' range. */
|
|
195
|
+
const BYTES_NON_ASCII: i32 = 128
|
|
196
|
+
const BYTES_CONTINUATION_TOP: i32 = 191
|
|
197
|
+
|
|
198
|
+
/** `to` clamped into `[0, b.length]`: where a run's scan stops. */
|
|
199
|
+
const bytesRunEnd = (b: u8[], to: i32): i32 => {
|
|
200
|
+
const n: i32 = toI32(b.length)
|
|
201
|
+
if (to < 0) {
|
|
202
|
+
return 0
|
|
203
|
+
}
|
|
204
|
+
return to < n ? to : n
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** `from` clamped into `[0, end]`: where a run's scan starts. */
|
|
208
|
+
const bytesRunStart = (from: i32, end: i32): i32 => {
|
|
209
|
+
if (from < 0) {
|
|
210
|
+
return 0
|
|
211
|
+
}
|
|
212
|
+
return from < end ? from : end
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* The first index in `[from, to)` whose byte is not one of JSON's blanks —
|
|
217
|
+
* space, tab, newline, carriage return — or `to` when every byte there is
|
|
218
|
+
* one. `to` is clamped to `[0, b.length]` and `from` to `[0, to]`, as
|
|
219
|
+
* `indexOfAny` clamps, so no range panics: one past the end answers the end.
|
|
220
|
+
*
|
|
221
|
+
* Natively the scan is the runtime's `nish_bytes_skip_blank`, which reads 16
|
|
222
|
+
* or 32 bytes at a time (docs/LANGUAGE.md, "Byte runs"). It is
|
|
223
|
+
* **variable-time**: how long it takes says how long the run is, so it is
|
|
224
|
+
* never for secret data.
|
|
225
|
+
*/
|
|
226
|
+
export const skipBlank = (b: u8[], from: i32, to: i32): i32 => {
|
|
227
|
+
const end: i32 = bytesRunEnd(b, to)
|
|
228
|
+
return skipBlankWalk(b, bytesRunStart(from, end), end)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** `skipBlank` for the ASCII digits `0` to `9`: the same clamps, the same kernel family, `nish_bytes_skip_digits`. */
|
|
232
|
+
export const skipDigits = (b: u8[], from: i32, to: i32): i32 => {
|
|
233
|
+
const end: i32 = bytesRunEnd(b, to)
|
|
234
|
+
return skipDigitsWalk(b, bytesRunStart(from, end), end)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* `skipBlank` for the bytes a JSON string holds as themselves: printable ASCII
|
|
239
|
+
* other than `"` and `\`, and every well-formed UTF-8 sequence (RFC 3629 §4)
|
|
240
|
+
* that ends before `to`. The run stops at the first quote, backslash or
|
|
241
|
+
* control byte, and at the lead byte of a sequence that is malformed — an
|
|
242
|
+
* overlong form, a surrogate, a code point past U+10FFFF, a stray continuation
|
|
243
|
+
* byte — or cut short by `to`. So a whole JSON string body with no escape is
|
|
244
|
+
* one call, and where it stops is the byte a decoder has to look at. Natively
|
|
245
|
+
* the scan is `nish_bytes_skip_json_text`: blocks of ASCII 16 or 32 bytes at a
|
|
246
|
+
* time, each multi-byte sequence a byte at a time. Variable-time, as
|
|
247
|
+
* `skipBlank` is.
|
|
248
|
+
*/
|
|
249
|
+
export const skipJsonText = (b: u8[], from: i32, to: i32): i32 => {
|
|
250
|
+
const end: i32 = bytesRunEnd(b, to)
|
|
251
|
+
return skipJsonTextWalk(b, bytesRunStart(from, end), end)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* The first index in `[from, to)` whose byte a JSON writer cannot copy as
|
|
256
|
+
* itself — a control byte below `0x20`, a quote or a backslash — or `to`, with
|
|
257
|
+
* the range clamped as `skipBlank`'s is. Every byte from `0x20` up is in the
|
|
258
|
+
* run, `0x7f` and the bytes from `0x80` up included, and no UTF-8 is checked:
|
|
259
|
+
* where `skipJsonText` is the reader's run, this is the writer's, which passes
|
|
260
|
+
* the bytes of a string through as they are. Natively the scan is
|
|
261
|
+
* `nish_bytes_skip_json_plain`, 16 bytes at a time. Variable-time, as
|
|
262
|
+
* `skipBlank` is.
|
|
263
|
+
*/
|
|
264
|
+
export const skipJsonPlain = (b: u8[], from: i32, to: i32): i32 => {
|
|
265
|
+
const end: i32 = bytesRunEnd(b, to)
|
|
266
|
+
return skipJsonPlainWalk(b, bytesRunStart(from, end), end)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* `count` bytes of `src` from `from` written over `dst` from `at`, as one
|
|
271
|
+
* copy: where `dst` and `src` are one array and the two ranges overlap, the
|
|
272
|
+
* bytes land as if every one were read before any was written, as
|
|
273
|
+
* `copyWithin` promises. Where `dst.set(src, at)` copies all of `src`, this
|
|
274
|
+
* copies a window of it, and allocates nothing.
|
|
275
|
+
*
|
|
276
|
+
* A negative `count`, or a range that does not lie inside its array —
|
|
277
|
+
* `0 <= from <= from + count <= src.length` and the same for `at` in `dst` —
|
|
278
|
+
* panics `copyBytes` before any byte is written. Natively the copy is one
|
|
279
|
+
* `llvm.memmove`.
|
|
280
|
+
*/
|
|
281
|
+
export const copyBytes = (dst: u8[], at: i32, src: u8[], from: i32, count: i32): void => {
|
|
282
|
+
if (count < 0 || at < 0 || from < 0 || at > toI32(dst.length) - count || from > toI32(src.length) - count) {
|
|
283
|
+
panic("copyBytes: the range lies outside an array")
|
|
284
|
+
}
|
|
285
|
+
copyBytesWalk(dst, at, src, from, count)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* `skipBlank`'s walk, once its range is clamped. This loop and the four
|
|
290
|
+
* below are what run under Node; natively the compiler replaces the one call
|
|
291
|
+
* each public function makes with the runtime kernel (`src/kernels.ts`), as it
|
|
292
|
+
* does `indexOfAny`'s walk, so each loop is its kernel's meaning written in
|
|
293
|
+
* the language. The `i < b.length` test never fails after the clamp; it is
|
|
294
|
+
* written because it is what proves the index.
|
|
295
|
+
*/
|
|
296
|
+
const skipBlankWalk = (b: u8[], from: i32, to: i32): i32 => {
|
|
297
|
+
let i: i32 = from
|
|
298
|
+
while (i >= 0 && i < to && i < toI32(b.length)) {
|
|
299
|
+
const c: i32 = toI32(b[i])
|
|
300
|
+
if (c !== BYTES_SPACE && c !== BYTES_TAB && c !== BYTES_NEWLINE && c !== BYTES_CARRIAGE_RETURN) {
|
|
301
|
+
return i
|
|
302
|
+
}
|
|
303
|
+
i += 1
|
|
304
|
+
}
|
|
305
|
+
return i
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** `skipDigits`'s walk, once its range is clamped. */
|
|
309
|
+
const skipDigitsWalk = (b: u8[], from: i32, to: i32): i32 => {
|
|
310
|
+
let i: i32 = from
|
|
311
|
+
while (i >= 0 && i < to && i < toI32(b.length)) {
|
|
312
|
+
const c: i32 = toI32(b[i])
|
|
313
|
+
if (c < BYTES_DIGIT_ZERO || c > BYTES_DIGIT_NINE) {
|
|
314
|
+
return i
|
|
315
|
+
}
|
|
316
|
+
i += 1
|
|
317
|
+
}
|
|
318
|
+
return i
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* The length of the well-formed UTF-8 sequence whose lead byte is `b[i]` and
|
|
323
|
+
* that ends at or before `to`, or 0: RFC 3629's table, with the narrowed
|
|
324
|
+
* second byte after `E0`, `ED`, `F0` and `F4`.
|
|
325
|
+
*/
|
|
326
|
+
const bytesUtf8Length = (b: u8[], i: i32, to: i32): i32 => {
|
|
327
|
+
const lead: i32 = toI32(b[i])
|
|
328
|
+
let low: i32 = BYTES_NON_ASCII
|
|
329
|
+
let high: i32 = BYTES_CONTINUATION_TOP
|
|
330
|
+
let n: i32 = 0
|
|
331
|
+
if (lead >= 0xc2 && lead <= 0xdf) {
|
|
332
|
+
n = 2
|
|
333
|
+
} else if (lead >= 0xe0 && lead <= 0xef) {
|
|
334
|
+
n = 3
|
|
335
|
+
if (lead === 0xe0) {
|
|
336
|
+
low = 0xa0
|
|
337
|
+
}
|
|
338
|
+
if (lead === 0xed) {
|
|
339
|
+
high = 0x9f
|
|
340
|
+
}
|
|
341
|
+
} else if (lead >= 0xf0 && lead <= 0xf4) {
|
|
342
|
+
n = 4
|
|
343
|
+
if (lead === 0xf0) {
|
|
344
|
+
low = 0x90
|
|
345
|
+
}
|
|
346
|
+
if (lead === 0xf4) {
|
|
347
|
+
high = 0x8f
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
return 0
|
|
351
|
+
}
|
|
352
|
+
if (to - i < n) {
|
|
353
|
+
return 0
|
|
354
|
+
}
|
|
355
|
+
const second: i32 = toI32(b[i + 1])
|
|
356
|
+
if (second < low || second > high) {
|
|
357
|
+
return 0
|
|
358
|
+
}
|
|
359
|
+
let k: i32 = 2
|
|
360
|
+
while (k < n) {
|
|
361
|
+
const c: i32 = toI32(b[i + k])
|
|
362
|
+
if (c < BYTES_NON_ASCII || c > BYTES_CONTINUATION_TOP) {
|
|
363
|
+
return 0
|
|
364
|
+
}
|
|
365
|
+
k += 1
|
|
366
|
+
}
|
|
367
|
+
return n
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** `skipJsonText`'s walk, once its range is clamped. */
|
|
371
|
+
const skipJsonTextWalk = (b: u8[], from: i32, to: i32): i32 => {
|
|
372
|
+
let i: i32 = from
|
|
373
|
+
while (i >= 0 && i < to && i < toI32(b.length)) {
|
|
374
|
+
const c: i32 = toI32(b[i])
|
|
375
|
+
if (c >= BYTES_NON_ASCII) {
|
|
376
|
+
const n: i32 = bytesUtf8Length(b, i, to)
|
|
377
|
+
if (n === 0) {
|
|
378
|
+
return i
|
|
379
|
+
}
|
|
380
|
+
i += n
|
|
381
|
+
continue
|
|
382
|
+
}
|
|
383
|
+
if (c < BYTES_SPACE || c === BYTES_QUOTE || c === BYTES_BACKSLASH) {
|
|
384
|
+
return i
|
|
385
|
+
}
|
|
386
|
+
i += 1
|
|
387
|
+
}
|
|
388
|
+
return i
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** `skipJsonPlain`'s walk, once its range is clamped. */
|
|
392
|
+
const skipJsonPlainWalk = (b: u8[], from: i32, to: i32): i32 => {
|
|
393
|
+
let i: i32 = from
|
|
394
|
+
while (i >= 0 && i < to && i < toI32(b.length)) {
|
|
395
|
+
const c: i32 = toI32(b[i])
|
|
396
|
+
if (c < BYTES_SPACE || c === BYTES_QUOTE || c === BYTES_BACKSLASH) {
|
|
397
|
+
return i
|
|
398
|
+
}
|
|
399
|
+
i += 1
|
|
400
|
+
}
|
|
401
|
+
return i
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/** `copyBytes`'s walk, once its ranges are checked: forward, or backward when `dst` is `src` and the bytes move up. */
|
|
405
|
+
const copyBytesWalk = (dst: u8[], at: i32, src: u8[], from: i32, count: i32): void => {
|
|
406
|
+
if (at <= from) {
|
|
407
|
+
let k: i32 = 0
|
|
408
|
+
while (k < count) {
|
|
409
|
+
dst[at + k] = src[from + k]
|
|
410
|
+
k += 1
|
|
411
|
+
}
|
|
412
|
+
return
|
|
413
|
+
}
|
|
414
|
+
let k: i32 = count - 1
|
|
415
|
+
while (k >= 0) {
|
|
416
|
+
dst[at + k] = src[from + k]
|
|
417
|
+
k -= 1
|
|
418
|
+
}
|
|
419
|
+
}
|