@fuman/io 0.0.1

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.
Files changed (81) hide show
  1. package/LICENSE +8 -0
  2. package/_utils.cjs +23 -0
  3. package/_utils.d.ts +2 -0
  4. package/_utils.js +23 -0
  5. package/bits/index.d.ts +2 -0
  6. package/bits/reader.cjs +122 -0
  7. package/bits/reader.d.ts +15 -0
  8. package/bits/reader.js +122 -0
  9. package/bits/utils.cjs +49 -0
  10. package/bits/utils.d.ts +12 -0
  11. package/bits/utils.js +49 -0
  12. package/buf-reader.cjs +60 -0
  13. package/buf-reader.d.ts +9 -0
  14. package/buf-reader.js +60 -0
  15. package/bytes.cjs +114 -0
  16. package/bytes.d.ts +24 -0
  17. package/bytes.js +114 -0
  18. package/codec/delimiter.cjs +38 -0
  19. package/codec/delimiter.d.ts +22 -0
  20. package/codec/delimiter.js +38 -0
  21. package/codec/index.d.ts +6 -0
  22. package/codec/length-delimited.cjs +42 -0
  23. package/codec/length-delimited.d.ts +14 -0
  24. package/codec/length-delimited.js +42 -0
  25. package/codec/reader.cjs +51 -0
  26. package/codec/reader.d.ts +12 -0
  27. package/codec/reader.js +51 -0
  28. package/codec/text-delimiter.cjs +24 -0
  29. package/codec/text-delimiter.d.ts +11 -0
  30. package/codec/text-delimiter.js +24 -0
  31. package/codec/types.d.ts +16 -0
  32. package/codec/writer.cjs +24 -0
  33. package/codec/writer.d.ts +10 -0
  34. package/codec/writer.js +24 -0
  35. package/errors.cjs +9 -0
  36. package/errors.d.ts +9 -0
  37. package/errors.js +9 -0
  38. package/index.cjs +39 -0
  39. package/index.d.ts +12 -0
  40. package/index.js +39 -0
  41. package/package.json +29 -0
  42. package/read/adapters.cjs +90 -0
  43. package/read/adapters.d.ts +4 -0
  44. package/read/adapters.js +90 -0
  45. package/read/async/index.cjs +5 -0
  46. package/read/async/index.d.ts +1 -0
  47. package/read/async/index.js +5 -0
  48. package/read/async/strings.cjs +40 -0
  49. package/read/async/strings.d.ts +3 -0
  50. package/read/async/strings.js +40 -0
  51. package/read/index.cjs +40 -0
  52. package/read/index.d.ts +4 -0
  53. package/read/index.js +40 -0
  54. package/read/numbers.cjs +181 -0
  55. package/read/numbers.d.ts +27 -0
  56. package/read/numbers.js +181 -0
  57. package/read/strings.cjs +67 -0
  58. package/read/strings.d.ts +9 -0
  59. package/read/strings.js +67 -0
  60. package/reader-with-final.cjs +69 -0
  61. package/reader-with-final.d.ts +13 -0
  62. package/reader-with-final.js +69 -0
  63. package/streams.cjs +15 -0
  64. package/streams.d.ts +1 -0
  65. package/streams.js +15 -0
  66. package/types.d.ts +66 -0
  67. package/write/adapters.cjs +38 -0
  68. package/write/adapters.d.ts +4 -0
  69. package/write/adapters.js +38 -0
  70. package/write/index.cjs +37 -0
  71. package/write/index.d.ts +3 -0
  72. package/write/index.js +37 -0
  73. package/write/numbers.cjs +311 -0
  74. package/write/numbers.d.ts +27 -0
  75. package/write/numbers.js +311 -0
  76. package/write/pipe.cjs +11 -0
  77. package/write/pipe.d.ts +2 -0
  78. package/write/pipe.js +11 -0
  79. package/write/strings.cjs +38 -0
  80. package/write/strings.d.ts +6 -0
  81. package/write/strings.js +38 -0
package/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ Copyright 2024 alina sireneva
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
package/_utils.cjs ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ function nextPowerOfTwo(n) {
4
+ n--;
5
+ n |= n >> 1;
6
+ n |= n >> 2;
7
+ n |= n >> 4;
8
+ n |= n >> 8;
9
+ n |= n >> 16;
10
+ return n + 1;
11
+ }
12
+ const dvCache = /* @__PURE__ */ new WeakMap();
13
+ function getDv(buffer) {
14
+ const ab = buffer.buffer;
15
+ let dv = dvCache.get(ab);
16
+ if (!dv) {
17
+ dv = new DataView(ab);
18
+ dvCache.set(ab, dv);
19
+ }
20
+ return dv;
21
+ }
22
+ exports.getDv = getDv;
23
+ exports.nextPowerOfTwo = nextPowerOfTwo;
package/_utils.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function nextPowerOfTwo(n: number): number;
2
+ export declare function getDv(buffer: Uint8Array): DataView;
package/_utils.js ADDED
@@ -0,0 +1,23 @@
1
+ function nextPowerOfTwo(n) {
2
+ n--;
3
+ n |= n >> 1;
4
+ n |= n >> 2;
5
+ n |= n >> 4;
6
+ n |= n >> 8;
7
+ n |= n >> 16;
8
+ return n + 1;
9
+ }
10
+ const dvCache = /* @__PURE__ */ new WeakMap();
11
+ function getDv(buffer) {
12
+ const ab = buffer.buffer;
13
+ let dv = dvCache.get(ab);
14
+ if (!dv) {
15
+ dv = new DataView(ab);
16
+ dvCache.set(ab, dv);
17
+ }
18
+ return dv;
19
+ }
20
+ export {
21
+ getDv,
22
+ nextPowerOfTwo
23
+ };
@@ -0,0 +1,2 @@
1
+ export * from './reader.js';
2
+ export * from './utils.js';
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const utils = require("@fuman/utils");
4
+ const strings = require("../read/strings.cjs");
5
+ class BitReader {
6
+ #readable;
7
+ #currentByte = 0;
8
+ #currentBitIdx = 0;
9
+ constructor(readable) {
10
+ this.#readable = readable;
11
+ }
12
+ /** Whether the reader is currently aligned on a byte boundary */
13
+ get isAligned() {
14
+ return this.#currentBitIdx === 0;
15
+ }
16
+ /** Skip any remaining bits in the current byte. No-op if already aligned */
17
+ align() {
18
+ this.#currentBitIdx = 0;
19
+ }
20
+ /** The current bit position within the last consumed byte */
21
+ get bitPosition() {
22
+ return this.#currentBitIdx;
23
+ }
24
+ readSync(bytes) {
25
+ if (this.#currentBitIdx === 0) {
26
+ return this.#readable.readSync(bytes);
27
+ }
28
+ if (bytes === 1) {
29
+ return utils.u8.allocWith([this.readBits(8)]);
30
+ }
31
+ const bit = this.#currentBitIdx;
32
+ const nbit = 8 - bit;
33
+ const mask1 = (1 << nbit) - 1;
34
+ const result = utils.u8.alloc(bytes);
35
+ const tmp = this.#readable.readSync(bytes);
36
+ for (let i = 0; i < bytes; i++) {
37
+ const byte1 = this.#currentByte;
38
+ const byte2 = tmp[i];
39
+ result[i] = (byte1 & mask1) << bit | byte2 >> nbit;
40
+ this.#currentByte = byte2;
41
+ }
42
+ return result;
43
+ }
44
+ readBits(size) {
45
+ let result = 0;
46
+ if (this.#currentBitIdx !== 0) {
47
+ const bitsLeft = 8 - this.#currentBitIdx;
48
+ if (size <= bitsLeft) {
49
+ result = this.#currentByte & (1 << size) - 1;
50
+ this.#currentBitIdx += size;
51
+ if (this.#currentBitIdx === 8) {
52
+ this.#currentBitIdx = 0;
53
+ }
54
+ return result;
55
+ }
56
+ result = this.#currentByte & (1 << bitsLeft) - 1;
57
+ size -= bitsLeft;
58
+ this.#currentBitIdx = 0;
59
+ }
60
+ const bytes = Math.ceil(size / 8);
61
+ const data = strings.exactly(this.#readable, bytes);
62
+ let byteIdx = 0;
63
+ while (size >= 8) {
64
+ result = result << 8 | data[byteIdx++];
65
+ size -= 8;
66
+ }
67
+ if (size > 0) {
68
+ this.#currentByte = data[byteIdx];
69
+ this.#currentBitIdx = size;
70
+ result = result << size | this.#currentByte >> 8 - size;
71
+ }
72
+ return result;
73
+ }
74
+ readBitsBig(size) {
75
+ let result = 0n;
76
+ if (this.#currentBitIdx !== 0) {
77
+ const bitsLeft = 8 - this.#currentBitIdx;
78
+ if (size <= bitsLeft) {
79
+ result = BigInt(this.#currentByte) & (1n << BigInt(size)) - 1n;
80
+ this.#currentBitIdx += Number(size);
81
+ if (this.#currentBitIdx === 8) {
82
+ this.#currentBitIdx = 0;
83
+ }
84
+ return result;
85
+ }
86
+ result = BigInt(this.#currentByte) & (1n << BigInt(bitsLeft)) - 1n;
87
+ size -= bitsLeft;
88
+ this.#currentBitIdx = 0;
89
+ }
90
+ const bytes = Math.ceil(size / 8);
91
+ const data = strings.exactly(this.#readable, bytes);
92
+ let sizeBig = BigInt(size);
93
+ let byteIdx = 0;
94
+ while (sizeBig >= 8n) {
95
+ result = result << 8n | BigInt(data[byteIdx++]);
96
+ sizeBig -= 8n;
97
+ }
98
+ if (sizeBig > 0n) {
99
+ this.#currentByte = data[byteIdx];
100
+ this.#currentBitIdx = size;
101
+ result = result << sizeBig | BigInt(this.#currentByte) >> 8n - sizeBig;
102
+ }
103
+ return result;
104
+ }
105
+ skipBits(size) {
106
+ if (size % 8 === 0) {
107
+ const buf = strings.exactly(this.#readable, size / 8);
108
+ this.#currentByte = buf[buf.length - 1];
109
+ return;
110
+ }
111
+ let bytesToRead = Math.ceil(size / 8);
112
+ if (this.#currentBitIdx !== 0) {
113
+ bytesToRead -= 1;
114
+ }
115
+ if (bytesToRead > 0) {
116
+ const buf = strings.exactly(this.#readable, bytesToRead);
117
+ this.#currentByte = buf[bytesToRead - 1];
118
+ }
119
+ this.#currentBitIdx = (this.#currentBitIdx + size) % 8;
120
+ }
121
+ }
122
+ exports.BitReader = BitReader;
@@ -0,0 +1,15 @@
1
+ import { ISyncReadable } from '../types.js';
2
+ export declare class BitReader implements ISyncReadable {
3
+ #private;
4
+ constructor(readable: ISyncReadable);
5
+ /** Whether the reader is currently aligned on a byte boundary */
6
+ get isAligned(): boolean;
7
+ /** Skip any remaining bits in the current byte. No-op if already aligned */
8
+ align(): void;
9
+ /** The current bit position within the last consumed byte */
10
+ get bitPosition(): number;
11
+ readSync(bytes: number): Uint8Array;
12
+ readBits(size: number): number;
13
+ readBitsBig(size: number): bigint;
14
+ skipBits(size: number): void;
15
+ }
package/bits/reader.js ADDED
@@ -0,0 +1,122 @@
1
+ import { u8 } from "@fuman/utils";
2
+ import { exactly } from "../read/strings.js";
3
+ class BitReader {
4
+ #readable;
5
+ #currentByte = 0;
6
+ #currentBitIdx = 0;
7
+ constructor(readable) {
8
+ this.#readable = readable;
9
+ }
10
+ /** Whether the reader is currently aligned on a byte boundary */
11
+ get isAligned() {
12
+ return this.#currentBitIdx === 0;
13
+ }
14
+ /** Skip any remaining bits in the current byte. No-op if already aligned */
15
+ align() {
16
+ this.#currentBitIdx = 0;
17
+ }
18
+ /** The current bit position within the last consumed byte */
19
+ get bitPosition() {
20
+ return this.#currentBitIdx;
21
+ }
22
+ readSync(bytes) {
23
+ if (this.#currentBitIdx === 0) {
24
+ return this.#readable.readSync(bytes);
25
+ }
26
+ if (bytes === 1) {
27
+ return u8.allocWith([this.readBits(8)]);
28
+ }
29
+ const bit = this.#currentBitIdx;
30
+ const nbit = 8 - bit;
31
+ const mask1 = (1 << nbit) - 1;
32
+ const result = u8.alloc(bytes);
33
+ const tmp = this.#readable.readSync(bytes);
34
+ for (let i = 0; i < bytes; i++) {
35
+ const byte1 = this.#currentByte;
36
+ const byte2 = tmp[i];
37
+ result[i] = (byte1 & mask1) << bit | byte2 >> nbit;
38
+ this.#currentByte = byte2;
39
+ }
40
+ return result;
41
+ }
42
+ readBits(size) {
43
+ let result = 0;
44
+ if (this.#currentBitIdx !== 0) {
45
+ const bitsLeft = 8 - this.#currentBitIdx;
46
+ if (size <= bitsLeft) {
47
+ result = this.#currentByte & (1 << size) - 1;
48
+ this.#currentBitIdx += size;
49
+ if (this.#currentBitIdx === 8) {
50
+ this.#currentBitIdx = 0;
51
+ }
52
+ return result;
53
+ }
54
+ result = this.#currentByte & (1 << bitsLeft) - 1;
55
+ size -= bitsLeft;
56
+ this.#currentBitIdx = 0;
57
+ }
58
+ const bytes = Math.ceil(size / 8);
59
+ const data = exactly(this.#readable, bytes);
60
+ let byteIdx = 0;
61
+ while (size >= 8) {
62
+ result = result << 8 | data[byteIdx++];
63
+ size -= 8;
64
+ }
65
+ if (size > 0) {
66
+ this.#currentByte = data[byteIdx];
67
+ this.#currentBitIdx = size;
68
+ result = result << size | this.#currentByte >> 8 - size;
69
+ }
70
+ return result;
71
+ }
72
+ readBitsBig(size) {
73
+ let result = 0n;
74
+ if (this.#currentBitIdx !== 0) {
75
+ const bitsLeft = 8 - this.#currentBitIdx;
76
+ if (size <= bitsLeft) {
77
+ result = BigInt(this.#currentByte) & (1n << BigInt(size)) - 1n;
78
+ this.#currentBitIdx += Number(size);
79
+ if (this.#currentBitIdx === 8) {
80
+ this.#currentBitIdx = 0;
81
+ }
82
+ return result;
83
+ }
84
+ result = BigInt(this.#currentByte) & (1n << BigInt(bitsLeft)) - 1n;
85
+ size -= bitsLeft;
86
+ this.#currentBitIdx = 0;
87
+ }
88
+ const bytes = Math.ceil(size / 8);
89
+ const data = exactly(this.#readable, bytes);
90
+ let sizeBig = BigInt(size);
91
+ let byteIdx = 0;
92
+ while (sizeBig >= 8n) {
93
+ result = result << 8n | BigInt(data[byteIdx++]);
94
+ sizeBig -= 8n;
95
+ }
96
+ if (sizeBig > 0n) {
97
+ this.#currentByte = data[byteIdx];
98
+ this.#currentBitIdx = size;
99
+ result = result << sizeBig | BigInt(this.#currentByte) >> 8n - sizeBig;
100
+ }
101
+ return result;
102
+ }
103
+ skipBits(size) {
104
+ if (size % 8 === 0) {
105
+ const buf = exactly(this.#readable, size / 8);
106
+ this.#currentByte = buf[buf.length - 1];
107
+ return;
108
+ }
109
+ let bytesToRead = Math.ceil(size / 8);
110
+ if (this.#currentBitIdx !== 0) {
111
+ bytesToRead -= 1;
112
+ }
113
+ if (bytesToRead > 0) {
114
+ const buf = exactly(this.#readable, bytesToRead);
115
+ this.#currentByte = buf[bytesToRead - 1];
116
+ }
117
+ this.#currentBitIdx = (this.#currentBitIdx + size) % 8;
118
+ }
119
+ }
120
+ export {
121
+ BitReader
122
+ };
package/bits/utils.cjs ADDED
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const REV_8BIT_LOOKUP = [
4
+ 0,
5
+ 8,
6
+ 4,
7
+ 12,
8
+ 2,
9
+ 10,
10
+ 6,
11
+ 14,
12
+ 1,
13
+ 9,
14
+ 5,
15
+ 13,
16
+ 3,
17
+ 11,
18
+ 7,
19
+ 15
20
+ ];
21
+ function reverse8Bits(byte) {
22
+ return REV_8BIT_LOOKUP[byte & 15] << 4 | REV_8BIT_LOOKUP[byte >> 4];
23
+ }
24
+ function reverseBits(value, size) {
25
+ let result = 0;
26
+ for (let i = 0; i < size; i++) {
27
+ result |= (value >> i & 1) << size - i - 1;
28
+ }
29
+ return result;
30
+ }
31
+ function reverseBitsBig(value, size) {
32
+ if (typeof size === "number") {
33
+ size = BigInt(size);
34
+ }
35
+ let result = 0n;
36
+ for (let i = 0n; i < size; i++) {
37
+ result |= (value >> i & 1n) << size - i - 1n;
38
+ }
39
+ return result;
40
+ }
41
+ function reverseBitsAll(buf) {
42
+ for (let i = 0; i < buf.length; i++) {
43
+ buf[i] = reverse8Bits(buf[i]);
44
+ }
45
+ }
46
+ exports.reverse8Bits = reverse8Bits;
47
+ exports.reverseBits = reverseBits;
48
+ exports.reverseBitsAll = reverseBitsAll;
49
+ exports.reverseBitsBig = reverseBitsBig;
@@ -0,0 +1,12 @@
1
+ /** Reverse bit ordering of a single byte */
2
+ export declare function reverse8Bits(byte: number): number;
3
+ /** Reverse bits of a numeric value, treating it as a `size`-bit number */
4
+ export declare function reverseBits(value: number, size: number): number;
5
+ /** Reverse bits of a bigint, treating it as a `size`-bit number */
6
+ export declare function reverseBitsBig(value: bigint, size: number | bigint): bigint;
7
+ /**
8
+ * Reverse the bit ordering of each byte in the byte array, **in place**
9
+ *
10
+ * @example `reverseBitsAll(new Uint8Array([0b10101010, 0b01010101])) // becomes [0b01010101, 0b10101010]
11
+ */
12
+ export declare function reverseBitsAll(buf: Uint8Array): void;
package/bits/utils.js ADDED
@@ -0,0 +1,49 @@
1
+ const REV_8BIT_LOOKUP = [
2
+ 0,
3
+ 8,
4
+ 4,
5
+ 12,
6
+ 2,
7
+ 10,
8
+ 6,
9
+ 14,
10
+ 1,
11
+ 9,
12
+ 5,
13
+ 13,
14
+ 3,
15
+ 11,
16
+ 7,
17
+ 15
18
+ ];
19
+ function reverse8Bits(byte) {
20
+ return REV_8BIT_LOOKUP[byte & 15] << 4 | REV_8BIT_LOOKUP[byte >> 4];
21
+ }
22
+ function reverseBits(value, size) {
23
+ let result = 0;
24
+ for (let i = 0; i < size; i++) {
25
+ result |= (value >> i & 1) << size - i - 1;
26
+ }
27
+ return result;
28
+ }
29
+ function reverseBitsBig(value, size) {
30
+ if (typeof size === "number") {
31
+ size = BigInt(size);
32
+ }
33
+ let result = 0n;
34
+ for (let i = 0n; i < size; i++) {
35
+ result |= (value >> i & 1n) << size - i - 1n;
36
+ }
37
+ return result;
38
+ }
39
+ function reverseBitsAll(buf) {
40
+ for (let i = 0; i < buf.length; i++) {
41
+ buf[i] = reverse8Bits(buf[i]);
42
+ }
43
+ }
44
+ export {
45
+ reverse8Bits,
46
+ reverseBits,
47
+ reverseBitsAll,
48
+ reverseBitsBig
49
+ };
package/buf-reader.cjs ADDED
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const utils = require("@fuman/utils");
4
+ const DEFAULT_BUF_SIZE = 4096;
5
+ const MIN_BUF_SIZE = 16;
6
+ class BufReader {
7
+ #buffer;
8
+ #readable;
9
+ #readPos = 0;
10
+ #writePos = 0;
11
+ #eof = false;
12
+ static create(readable, size = DEFAULT_BUF_SIZE) {
13
+ return new BufReader(readable, size);
14
+ }
15
+ constructor(readable, size = DEFAULT_BUF_SIZE) {
16
+ if (size < MIN_BUF_SIZE) {
17
+ size = MIN_BUF_SIZE;
18
+ }
19
+ this.#buffer = utils.u8.alloc(size);
20
+ this.#readable = readable;
21
+ }
22
+ get bufferSize() {
23
+ return this.#buffer.byteLength;
24
+ }
25
+ get buffered() {
26
+ return this.#writePos - this.#readPos;
27
+ }
28
+ async #fill() {
29
+ if (this.#readPos > 0) {
30
+ this.#buffer.copyWithin(0, this.#readPos, this.#writePos);
31
+ this.#writePos -= this.#readPos;
32
+ this.#readPos = 0;
33
+ }
34
+ if (this.#writePos >= this.#buffer.byteLength) {
35
+ throw new Error("tried to fill full buffer");
36
+ }
37
+ const read = await this.#readable.read(this.#buffer.subarray(this.#writePos));
38
+ if (read === 0) {
39
+ this.#eof = true;
40
+ return;
41
+ }
42
+ this.#writePos += read;
43
+ }
44
+ async read(into) {
45
+ if (this.#eof) {
46
+ return 0;
47
+ }
48
+ if (this.#readPos === this.#writePos) {
49
+ if (into.byteLength >= this.#buffer.byteLength) {
50
+ return this.#readable.read(into);
51
+ }
52
+ await this.#fill();
53
+ }
54
+ const sliceSize = Math.min(this.#writePos - this.#readPos, into.byteLength);
55
+ into.set(this.#buffer.subarray(this.#readPos, this.#readPos + sliceSize));
56
+ this.#readPos += sliceSize;
57
+ return sliceSize;
58
+ }
59
+ }
60
+ exports.BufReader = BufReader;
@@ -0,0 +1,9 @@
1
+ import { IReadable } from './types.js';
2
+ export declare class BufReader implements IReadable {
3
+ #private;
4
+ static create(readable: IReadable, size?: number): BufReader;
5
+ constructor(readable: IReadable, size?: number);
6
+ get bufferSize(): number;
7
+ get buffered(): number;
8
+ read(into: Uint8Array): Promise<number>;
9
+ }
package/buf-reader.js ADDED
@@ -0,0 +1,60 @@
1
+ import { u8 } from "@fuman/utils";
2
+ const DEFAULT_BUF_SIZE = 4096;
3
+ const MIN_BUF_SIZE = 16;
4
+ class BufReader {
5
+ #buffer;
6
+ #readable;
7
+ #readPos = 0;
8
+ #writePos = 0;
9
+ #eof = false;
10
+ static create(readable, size = DEFAULT_BUF_SIZE) {
11
+ return new BufReader(readable, size);
12
+ }
13
+ constructor(readable, size = DEFAULT_BUF_SIZE) {
14
+ if (size < MIN_BUF_SIZE) {
15
+ size = MIN_BUF_SIZE;
16
+ }
17
+ this.#buffer = u8.alloc(size);
18
+ this.#readable = readable;
19
+ }
20
+ get bufferSize() {
21
+ return this.#buffer.byteLength;
22
+ }
23
+ get buffered() {
24
+ return this.#writePos - this.#readPos;
25
+ }
26
+ async #fill() {
27
+ if (this.#readPos > 0) {
28
+ this.#buffer.copyWithin(0, this.#readPos, this.#writePos);
29
+ this.#writePos -= this.#readPos;
30
+ this.#readPos = 0;
31
+ }
32
+ if (this.#writePos >= this.#buffer.byteLength) {
33
+ throw new Error("tried to fill full buffer");
34
+ }
35
+ const read = await this.#readable.read(this.#buffer.subarray(this.#writePos));
36
+ if (read === 0) {
37
+ this.#eof = true;
38
+ return;
39
+ }
40
+ this.#writePos += read;
41
+ }
42
+ async read(into) {
43
+ if (this.#eof) {
44
+ return 0;
45
+ }
46
+ if (this.#readPos === this.#writePos) {
47
+ if (into.byteLength >= this.#buffer.byteLength) {
48
+ return this.#readable.read(into);
49
+ }
50
+ await this.#fill();
51
+ }
52
+ const sliceSize = Math.min(this.#writePos - this.#readPos, into.byteLength);
53
+ into.set(this.#buffer.subarray(this.#readPos, this.#readPos + sliceSize));
54
+ this.#readPos += sliceSize;
55
+ return sliceSize;
56
+ }
57
+ }
58
+ export {
59
+ BufReader
60
+ };
package/bytes.cjs ADDED
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const utils = require("@fuman/utils");
4
+ const _utils = require("./_utils.cjs");
5
+ class Bytes {
6
+ /** Underlying buffer */
7
+ #buffer;
8
+ /** Position of the write cursor (should always be >= {@link #readPos}) */
9
+ #writePos = 0;
10
+ /** Position of the read cursor */
11
+ #readPos = 0;
12
+ #preferredCapacity;
13
+ constructor(buf) {
14
+ this.#buffer = buf;
15
+ this.#preferredCapacity = buf.length;
16
+ }
17
+ static alloc(capacity = 1024 * 16) {
18
+ const bytes = new Bytes(utils.u8.alloc(capacity));
19
+ return bytes;
20
+ }
21
+ static from(data) {
22
+ const bytes = new Bytes(data);
23
+ bytes.#writePos = data.length;
24
+ return bytes;
25
+ }
26
+ /** Total number of bytes in the underlying buffer */
27
+ get capacity() {
28
+ return this.#buffer.byteLength;
29
+ }
30
+ /** Number of bytes available to be read */
31
+ get available() {
32
+ return this.#writePos - this.#readPos;
33
+ }
34
+ /** Number of bytes written */
35
+ get written() {
36
+ return this.#writePos;
37
+ }
38
+ #sharedRead = new Uint8Array(1);
39
+ readSync(bytes) {
40
+ if (this.#readPos >= this.#writePos) {
41
+ return utils.u8.empty;
42
+ }
43
+ if (bytes === 1) {
44
+ this.#sharedRead[0] = this.#buffer[this.#readPos++];
45
+ return this.#sharedRead;
46
+ }
47
+ const end = Math.min(this.#writePos, this.#readPos + bytes);
48
+ const result = this.#buffer.subarray(this.#readPos, end);
49
+ this.#readPos = end;
50
+ return result;
51
+ }
52
+ async read(into) {
53
+ const size = Math.min(into.length, this.#writePos - this.#readPos);
54
+ into.set(this.#buffer.subarray(this.#readPos, this.#readPos + size));
55
+ this.#readPos += size;
56
+ return size;
57
+ }
58
+ #lastWriteSize = 0;
59
+ writeSync(size) {
60
+ this.#lastWriteSize = size;
61
+ const newPos = this.#writePos + size;
62
+ if (newPos > this.#buffer.length) {
63
+ const newBuffer = utils.u8.alloc(_utils.nextPowerOfTwo(newPos));
64
+ newBuffer.set(this.#buffer);
65
+ this.#buffer = newBuffer;
66
+ }
67
+ const slice = this.#buffer.subarray(this.#writePos, newPos);
68
+ this.#writePos = newPos;
69
+ return slice;
70
+ }
71
+ disposeWriteSync(written) {
72
+ if (written !== void 0) {
73
+ if (written > this.#lastWriteSize) {
74
+ throw new RangeError(`written exceeds last write size: ${written} > ${this.#lastWriteSize}`);
75
+ }
76
+ this.#writePos -= this.#lastWriteSize - written;
77
+ }
78
+ }
79
+ async write(bytes) {
80
+ this.writeSync(bytes.length).set(bytes);
81
+ this.disposeWriteSync();
82
+ }
83
+ result() {
84
+ return this.#buffer.subarray(0, this.#writePos);
85
+ }
86
+ /** Reclaim memory by only keeping the yet-unread data */
87
+ reclaim() {
88
+ if (this.#readPos === 0) return;
89
+ const remaining = this.#writePos - this.#readPos;
90
+ if (remaining > 0) {
91
+ if (remaining < this.#preferredCapacity && this.capacity > this.#preferredCapacity) {
92
+ const newBuffer = utils.u8.alloc(this.#preferredCapacity);
93
+ newBuffer.set(this.#buffer.subarray(this.#readPos, this.#writePos));
94
+ this.#buffer = newBuffer;
95
+ } else {
96
+ this.#buffer.copyWithin(0, this.#readPos, this.#writePos);
97
+ }
98
+ }
99
+ this.#writePos = remaining;
100
+ this.#readPos = 0;
101
+ }
102
+ /** Mark last n bytes as unread */
103
+ rewind(n) {
104
+ if (n > this.#readPos) {
105
+ throw new RangeError(`rewind: ${n} > ${this.#readPos}`);
106
+ }
107
+ this.#readPos -= n;
108
+ }
109
+ reset() {
110
+ this.#readPos = 0;
111
+ this.#writePos = 0;
112
+ }
113
+ }
114
+ exports.Bytes = Bytes;