xitdb 0.13.0 → 0.14.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.
Files changed (61) hide show
  1. package/README.md +16 -15
  2. package/dist/core-buffered-file.d.ts +2 -2
  3. package/dist/core-buffered-file.js +182 -0
  4. package/dist/core-file.d.ts +1 -1
  5. package/dist/core-file.js +105 -0
  6. package/dist/core-memory.d.ts +1 -1
  7. package/dist/core-memory.js +152 -0
  8. package/dist/core.js +1 -0
  9. package/dist/database.d.ts +174 -49
  10. package/dist/database.js +3047 -0
  11. package/dist/exceptions.d.ts +4 -0
  12. package/dist/exceptions.js +62 -0
  13. package/dist/hasher.js +49 -0
  14. package/dist/index.d.ts +30 -26
  15. package/dist/index.js +35 -3923
  16. package/dist/read-array-list.d.ts +3 -3
  17. package/dist/read-array-list.js +35 -0
  18. package/dist/read-counted-hash-map.d.ts +2 -2
  19. package/dist/read-counted-hash-map.js +19 -0
  20. package/dist/read-counted-hash-set.d.ts +2 -2
  21. package/dist/read-counted-hash-set.js +19 -0
  22. package/dist/read-cursor.d.ts +11 -5
  23. package/dist/read-cursor.js +577 -0
  24. package/dist/read-hash-map.d.ts +4 -4
  25. package/dist/read-hash-map.js +65 -0
  26. package/dist/read-hash-set.d.ts +4 -4
  27. package/dist/read-hash-set.js +47 -0
  28. package/dist/read-linked-array-list.d.ts +3 -3
  29. package/dist/read-linked-array-list.js +35 -0
  30. package/dist/read-sorted-map.d.ts +21 -0
  31. package/dist/read-sorted-map.js +73 -0
  32. package/dist/read-sorted-set.d.ts +19 -0
  33. package/dist/read-sorted-set.js +65 -0
  34. package/dist/slot-pointer.d.ts +1 -1
  35. package/dist/slot-pointer.js +11 -0
  36. package/dist/slot.d.ts +2 -2
  37. package/dist/slot.js +41 -0
  38. package/dist/slotted.d.ts +1 -1
  39. package/dist/slotted.js +1 -0
  40. package/dist/tag.d.ts +3 -1
  41. package/dist/tag.js +25 -0
  42. package/dist/write-array-list.d.ts +4 -4
  43. package/dist/write-array-list.js +42 -0
  44. package/dist/write-counted-hash-map.d.ts +2 -2
  45. package/dist/write-counted-hash-map.js +18 -0
  46. package/dist/write-counted-hash-set.d.ts +2 -2
  47. package/dist/write-counted-hash-set.js +18 -0
  48. package/dist/write-cursor.d.ts +5 -5
  49. package/dist/write-cursor.js +124 -0
  50. package/dist/write-hash-map.d.ts +4 -4
  51. package/dist/write-hash-map.js +90 -0
  52. package/dist/write-hash-set.d.ts +4 -4
  53. package/dist/write-hash-set.js +59 -0
  54. package/dist/write-linked-array-list.d.ts +4 -4
  55. package/dist/write-linked-array-list.js +52 -0
  56. package/dist/write-sorted-map.d.ts +12 -0
  57. package/dist/write-sorted-map.js +37 -0
  58. package/dist/write-sorted-set.d.ts +10 -0
  59. package/dist/write-sorted-set.js +29 -0
  60. package/dist/writeable-data.js +68 -0
  61. package/package.json +6 -6
package/README.md CHANGED
@@ -97,18 +97,18 @@ const moment = new ReadHashMap(momentCursor!);
97
97
  // the cursor to "foo" and then calling readBytes on it
98
98
  const fooCursor = moment.getCursor('foo');
99
99
  const fooValue = fooCursor!.readBytes(MAX_READ_BYTES);
100
- expect(new TextDecoder().decode(fooValue)).toBe('foo');
100
+ assert.strictEqual(new TextDecoder().decode(fooValue), 'foo');
101
101
 
102
102
  // to get the "fruits" list, we get the cursor to it and
103
103
  // then pass it to the ReadArrayList constructor
104
104
  const fruitsCursor = moment.getCursor('fruits');
105
105
  const fruits = new ReadArrayList(fruitsCursor!);
106
- expect(fruits.count()).toBe(3);
106
+ assert.strictEqual(fruits.count(), 3);
107
107
 
108
108
  // now we can get the first item from the fruits list and read it
109
109
  const appleCursor = fruits.getCursor(0);
110
110
  const appleValue = appleCursor!.readBytes(MAX_READ_BYTES);
111
- expect(new TextDecoder().decode(appleValue)).toBe('apple');
111
+ assert.strictEqual(new TextDecoder().decode(appleValue), 'apple');
112
112
  ```
113
113
 
114
114
  ## Initializing a Database
@@ -132,8 +132,9 @@ In xitdb there are a variety of immutable data structures that you can nest arbi
132
132
  * `CountedHashMap` and `CountedHashSet` are just a `HashMap` and `HashSet` that maintain a count of their contents
133
133
  * `ArrayList` is a growable array
134
134
  * `LinkedArrayList` is like an `ArrayList` that can also be efficiently sliced and concatenated
135
+ * `SortedMap` and `SortedSet` are like a `HashMap` and `HashSet` where the keys are byte arrays kept in lexicographic order
135
136
 
136
- All data structures use the hash array mapped trie, invented by Phil Bagwell. The `LinkedArrayList` is based on his later work on RRB trees. These data structures were originally made immutable and widely available by Rich Hickey in Clojure. To my knowledge, they haven't been available in any open source database until xitdb.
137
+ The `Hash`-based data structures and the `Arraylist` use the hash array mapped trie, invented by Phil Bagwell (originally made immutable and widely available by Rich Hickey in Clojure). The `LinkedArrayList`, `SortedMap`, and `SortedSet` are based on a B-tree.
137
138
 
138
139
  There are also scalar types you can store in the above-mentioned data structures:
139
140
 
@@ -157,7 +158,7 @@ Then, you can read it like this:
157
158
  ```typescript
158
159
  const randomNumberCursor = moment.getCursor('random-number');
159
160
  const randomNumber = randomNumberCursor!.readBytesObject(MAX_READ_BYTES);
160
- expect(new TextDecoder().decode(randomNumber.formatTag!)).toBe('bi');
161
+ assert.strictEqual(new TextDecoder().decode(randomNumber.formatTag!), 'bi');
161
162
  const randomBigInt = randomNumber.value;
162
163
  ```
163
164
 
@@ -191,12 +192,12 @@ const moment = new ReadHashMap(momentCursor!);
191
192
  // the food list includes the fruits
192
193
  const foodCursor = moment.getCursor('food');
193
194
  const food = new ReadArrayList(foodCursor!);
194
- expect(food.count()).toBe(6);
195
+ assert.strictEqual(food.count(), 6);
195
196
 
196
197
  // ...but the fruits list hasn't been changed
197
198
  const fruitsCursor = moment.getCursor('fruits');
198
199
  const fruits = new ReadArrayList(fruitsCursor!);
199
- expect(fruits.count()).toBe(3);
200
+ assert.strictEqual(fruits.count(), 3);
200
201
  ```
201
202
 
202
203
  Before we continue, let's save the latest history index, so we can revert back to this moment of the database later:
@@ -232,12 +233,12 @@ const moment = new ReadHashMap(momentCursor!);
232
233
  // the cities list contains all four
233
234
  const citiesCursor = moment.getCursor('cities');
234
235
  const cities = new ReadArrayList(citiesCursor!);
235
- expect(cities.count()).toBe(4);
236
+ assert.strictEqual(cities.count(), 4);
236
237
 
237
238
  // ..but so does big-cities! we did not intend to mutate this
238
239
  const bigCitiesCursor = moment.getCursor('big-cities');
239
240
  const bigCities = new ReadArrayList(bigCitiesCursor!);
240
- expect(bigCities.count()).toBe(4);
241
+ assert.strictEqual(bigCities.count(), 4);
241
242
  ```
242
243
 
243
244
  The reason that `big-cities` was mutated is because all data in a given transaction is temporarily mutable. This is a very important optimization, but in this case, it's not what we want.
@@ -278,12 +279,12 @@ const moment = new ReadHashMap(momentCursor!);
278
279
  // the cities list contains all four
279
280
  const citiesCursor = moment.getCursor('cities');
280
281
  const cities = new ReadArrayList(citiesCursor!);
281
- expect(cities.count()).toBe(4);
282
+ assert.strictEqual(cities.count(), 4);
282
283
 
283
284
  // and big-cities only contains the original two
284
285
  const bigCitiesCursor = moment.getCursor('big-cities');
285
286
  const bigCities = new ReadArrayList(bigCitiesCursor!);
286
- expect(bigCities.count()).toBe(2);
287
+ assert.strictEqual(bigCities.count(), 2);
287
288
  ```
288
289
 
289
290
  ## Large Byte Arrays
@@ -315,7 +316,7 @@ for (let n; (n = cursorReader.read(buf)) > 0; ) {
315
316
  }
316
317
  }
317
318
  if (line.length > 0) lineCount++;
318
- expect(lineCount).toBe(50);
319
+ assert.strictEqual(lineCount, 50);
319
320
  ```
320
321
 
321
322
  ## Iterators
@@ -377,7 +378,7 @@ The size of the hash in bytes will be stored in the database's header. If you tr
377
378
  ```typescript
378
379
  core.seek(0);
379
380
  const header = Header.read(core);
380
- expect(header.hashSize).toBe(20);
381
+ assert.strictEqual(header.hashSize, 20);
381
382
  ```
382
383
 
383
384
  The hash size alone does not disambiguate hashing algorithms, though. In addition, xitdb reserves four bytes in the header that you can use to put the name of the algorithm. You must provide it in the `Hasher` constructor:
@@ -391,7 +392,7 @@ The hash id is only written to the database header when it is first initialized.
391
392
  ```typescript
392
393
  core.seek(0);
393
394
  const header = Header.read(core);
394
- expect(Hasher.idToString(header.hashId)).toBe("sha1");
395
+ assert.strictEqual(Hasher.idToString(header.hashId), "sha1");
395
396
  ```
396
397
 
397
398
  If you want to use SHA-256, I recommend using `sha2` as the hash id. You can then distinguish between SHA-256 and SHA-512 using the hash size, like this:
@@ -431,7 +432,7 @@ const compactDb = db.compact(compactCore);
431
432
 
432
433
  // read from the new compacted db
433
434
  const history = new ReadArrayList(compactDb.rootCursor());
434
- expect(history.count()).toBe(1);
435
+ assert.strictEqual(history.count(), 1);
435
436
  ```
436
437
 
437
438
  This compacted database will be in a separate file. If you want to delete the original database and replace it with this one, you'll need to do that yourself. It is not possible to compact a database in-place (using the same file as the target database); doing so would fail and would render your original database unreadable.
@@ -1,5 +1,5 @@
1
- import type { Core, DataReader, DataWriter } from './core';
2
- import { CoreFile } from './core-file';
1
+ import type { Core, DataReader, DataWriter } from './core.js';
2
+ import { CoreFile } from './core-file.js';
3
3
  export declare class CoreBufferedFile implements Core {
4
4
  file: RandomAccessBufferedFile;
5
5
  constructor(filePath: string, bufferSize?: number);
@@ -0,0 +1,182 @@
1
+ import { CoreFile } from './core-file.js';
2
+ import { CoreMemory } from './core-memory.js';
3
+ export class CoreBufferedFile {
4
+ file;
5
+ constructor(filePath, bufferSize) {
6
+ this.file = new RandomAccessBufferedFile(filePath, bufferSize);
7
+ }
8
+ reader() {
9
+ return this.file;
10
+ }
11
+ writer() {
12
+ return this.file;
13
+ }
14
+ length() {
15
+ return this.file.length();
16
+ }
17
+ seek(pos) {
18
+ this.file.seek(pos);
19
+ }
20
+ position() {
21
+ return this.file.position();
22
+ }
23
+ setLength(len) {
24
+ this.file.setLength(len);
25
+ }
26
+ flush() {
27
+ this.file.flush();
28
+ }
29
+ sync() {
30
+ this.file.sync();
31
+ }
32
+ [Symbol.dispose]() {
33
+ this.file.file[Symbol.dispose]();
34
+ }
35
+ }
36
+ const DEFAULT_BUFFER_SIZE = 8 * 1024 * 1024; // 8MB
37
+ class RandomAccessBufferedFile {
38
+ file;
39
+ memory;
40
+ bufferSize; // flushes when the memory is >= this size
41
+ filePos;
42
+ memoryPos;
43
+ constructor(filePath, bufferSize = DEFAULT_BUFFER_SIZE) {
44
+ this.file = new CoreFile(filePath);
45
+ this.memory = new CoreMemory();
46
+ this.bufferSize = bufferSize;
47
+ this.filePos = 0;
48
+ this.memoryPos = 0;
49
+ }
50
+ seek(pos) {
51
+ // flush if we are going past the end of the in-memory buffer
52
+ if (pos > this.memoryPos + this.memory.length()) {
53
+ this.flush();
54
+ }
55
+ this.filePos = pos;
56
+ // if the buffer is empty, set its position to this offset as well
57
+ if (this.memory.length() === 0) {
58
+ this.memoryPos = pos;
59
+ }
60
+ }
61
+ length() {
62
+ return Math.max(this.memoryPos + this.memory.length(), this.file.length());
63
+ }
64
+ position() {
65
+ return this.filePos;
66
+ }
67
+ setLength(len) {
68
+ this.flush();
69
+ this.file.setLength(len);
70
+ this.filePos = Math.min(len, this.filePos);
71
+ }
72
+ flush() {
73
+ if (this.memory.length() > 0) {
74
+ this.file.seek(this.memoryPos);
75
+ this.file.writer().write(this.memory.memory.toByteArray());
76
+ this.memoryPos = 0;
77
+ this.memory.memory.reset();
78
+ }
79
+ }
80
+ sync() {
81
+ this.flush();
82
+ this.file.sync();
83
+ }
84
+ // DataWriter interface
85
+ write(buffer) {
86
+ if (this.memory.length() + buffer.length > this.bufferSize) {
87
+ this.flush();
88
+ }
89
+ if (this.filePos >= this.memoryPos && this.filePos <= this.memoryPos + this.memory.length()) {
90
+ this.memory.seek(this.filePos - this.memoryPos);
91
+ this.memory.memory.write(buffer);
92
+ }
93
+ else {
94
+ // a direct disk write that overlaps the buffered region would be
95
+ // clobbered by a later flush of stale buffer bytes, so flush first
96
+ if (this.filePos < this.memoryPos + this.memory.length() && this.filePos + buffer.length > this.memoryPos) {
97
+ this.flush();
98
+ }
99
+ // Write directly to file
100
+ this.file.seek(this.filePos);
101
+ this.file.writer().write(buffer);
102
+ }
103
+ this.filePos += buffer.length;
104
+ }
105
+ writeByte(v) {
106
+ this.write(new Uint8Array([v & 0xff]));
107
+ }
108
+ writeShort(v) {
109
+ const buffer = new ArrayBuffer(2);
110
+ const view = new DataView(buffer);
111
+ view.setInt16(0, v & 0xffff, false); // big-endian
112
+ this.write(new Uint8Array(buffer));
113
+ }
114
+ writeLong(v) {
115
+ const buffer = new ArrayBuffer(8);
116
+ const view = new DataView(buffer);
117
+ view.setBigInt64(0, BigInt(v), false);
118
+ this.write(new Uint8Array(buffer));
119
+ }
120
+ // DataReader interface
121
+ readFully(buffer) {
122
+ let pos = 0;
123
+ // read from the disk -- before the in-memory buffer
124
+ if (this.filePos < this.memoryPos) {
125
+ const sizeBeforeMem = Math.min(this.memoryPos - this.filePos, buffer.length);
126
+ const tempBuffer = new Uint8Array(sizeBeforeMem);
127
+ this.file.seek(this.filePos);
128
+ this.file.reader().readFully(tempBuffer);
129
+ buffer.set(tempBuffer, pos);
130
+ pos += sizeBeforeMem;
131
+ this.filePos += sizeBeforeMem;
132
+ }
133
+ if (pos === buffer.length)
134
+ return;
135
+ // read from the in-memory buffer
136
+ if (this.filePos >= this.memoryPos && this.filePos < this.memoryPos + this.memory.length()) {
137
+ const memPos = this.filePos - this.memoryPos;
138
+ const sizeInMem = Math.min(this.memory.length() - memPos, buffer.length - pos);
139
+ this.memory.seek(memPos);
140
+ const memBuffer = new Uint8Array(sizeInMem);
141
+ this.memory.memory.readFully(memBuffer);
142
+ buffer.set(memBuffer, pos);
143
+ pos += sizeInMem;
144
+ this.filePos += sizeInMem;
145
+ }
146
+ if (pos === buffer.length)
147
+ return;
148
+ // read from the disk -- after the in-memory buffer
149
+ if (this.filePos >= this.memoryPos + this.memory.length()) {
150
+ const sizeAfterMem = buffer.length - pos;
151
+ const tempBuffer = new Uint8Array(sizeAfterMem);
152
+ this.file.seek(this.filePos);
153
+ this.file.reader().readFully(tempBuffer);
154
+ buffer.set(tempBuffer, pos);
155
+ pos += sizeAfterMem;
156
+ this.filePos += sizeAfterMem;
157
+ }
158
+ }
159
+ readByte() {
160
+ const bytes = new Uint8Array(1);
161
+ this.readFully(bytes);
162
+ return bytes[0];
163
+ }
164
+ readShort() {
165
+ const bytes = new Uint8Array(2);
166
+ this.readFully(bytes);
167
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
168
+ return view.getInt16(0, false); // big-endian
169
+ }
170
+ readInt() {
171
+ const bytes = new Uint8Array(4);
172
+ this.readFully(bytes);
173
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
174
+ return view.getInt32(0, false); // big-endian
175
+ }
176
+ readLong() {
177
+ const bytes = new Uint8Array(8);
178
+ this.readFully(bytes);
179
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
180
+ return Number(view.getBigInt64(0, false));
181
+ }
182
+ }
@@ -1,4 +1,4 @@
1
- import type { Core, DataReader, DataWriter } from './core';
1
+ import type { Core, DataReader, DataWriter } from './core.js';
2
2
  export declare class CoreFile implements Core {
3
3
  filePath: string;
4
4
  private _position;
@@ -0,0 +1,105 @@
1
+ import * as fs from 'fs';
2
+ export class CoreFile {
3
+ filePath;
4
+ _position = 0;
5
+ fd;
6
+ constructor(filePath) {
7
+ this.filePath = filePath;
8
+ // Create file if it doesn't exist
9
+ try {
10
+ fs.accessSync(filePath);
11
+ }
12
+ catch {
13
+ fs.writeFileSync(filePath, new Uint8Array(0));
14
+ }
15
+ // Open file for reading and writing
16
+ this.fd = fs.openSync(filePath, 'r+');
17
+ }
18
+ reader() {
19
+ return new FileDataReader(this);
20
+ }
21
+ writer() {
22
+ return new FileDataWriter(this);
23
+ }
24
+ length() {
25
+ const stats = fs.fstatSync(this.fd);
26
+ return stats.size;
27
+ }
28
+ seek(pos) {
29
+ this._position = pos;
30
+ }
31
+ position() {
32
+ return this._position;
33
+ }
34
+ setLength(len) {
35
+ fs.ftruncateSync(this.fd, len);
36
+ }
37
+ flush() {
38
+ }
39
+ sync() {
40
+ fs.fsyncSync(this.fd);
41
+ }
42
+ [Symbol.dispose]() {
43
+ fs.closeSync(this.fd);
44
+ }
45
+ }
46
+ class FileDataReader {
47
+ core;
48
+ constructor(core) {
49
+ this.core = core;
50
+ }
51
+ readFully(b) {
52
+ const position = this.core.position();
53
+ fs.readSync(this.core.fd, b, 0, b.length, position);
54
+ this.core.seek(position + b.length);
55
+ }
56
+ readByte() {
57
+ const bytes = new Uint8Array(1);
58
+ this.readFully(bytes);
59
+ return bytes[0];
60
+ }
61
+ readShort() {
62
+ const bytes = new Uint8Array(2);
63
+ this.readFully(bytes);
64
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
65
+ return view.getInt16(0, false);
66
+ }
67
+ readInt() {
68
+ const bytes = new Uint8Array(4);
69
+ this.readFully(bytes);
70
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
71
+ return view.getInt32(0, false);
72
+ }
73
+ readLong() {
74
+ const bytes = new Uint8Array(8);
75
+ this.readFully(bytes);
76
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
77
+ return Number(view.getBigInt64(0, false));
78
+ }
79
+ }
80
+ class FileDataWriter {
81
+ core;
82
+ constructor(core) {
83
+ this.core = core;
84
+ }
85
+ write(buffer) {
86
+ const position = this.core.position();
87
+ fs.writeSync(this.core.fd, buffer, 0, buffer.length, position);
88
+ this.core.seek(position + buffer.length);
89
+ }
90
+ writeByte(v) {
91
+ this.write(new Uint8Array([v & 0xff]));
92
+ }
93
+ writeShort(v) {
94
+ const buffer = new ArrayBuffer(2);
95
+ const view = new DataView(buffer);
96
+ view.setInt16(0, v, false);
97
+ this.write(new Uint8Array(buffer));
98
+ }
99
+ writeLong(v) {
100
+ const buffer = new ArrayBuffer(8);
101
+ const view = new DataView(buffer);
102
+ view.setBigInt64(0, BigInt(v), false);
103
+ this.write(new Uint8Array(buffer));
104
+ }
105
+ }
@@ -1,4 +1,4 @@
1
- import type { Core, DataReader, DataWriter } from './core';
1
+ import type { Core, DataReader, DataWriter } from './core.js';
2
2
  export declare class CoreMemory implements Core {
3
3
  memory: RandomAccessMemory;
4
4
  constructor();
@@ -0,0 +1,152 @@
1
+ export class CoreMemory {
2
+ memory;
3
+ constructor() {
4
+ this.memory = new RandomAccessMemory();
5
+ }
6
+ reader() {
7
+ return this.memory;
8
+ }
9
+ writer() {
10
+ return this.memory;
11
+ }
12
+ length() {
13
+ return this.memory.size();
14
+ }
15
+ seek(pos) {
16
+ this.memory.seek(pos);
17
+ }
18
+ position() {
19
+ return this.memory.getPosition();
20
+ }
21
+ setLength(len) {
22
+ this.memory.setLength(len);
23
+ }
24
+ flush() {
25
+ // no-op for in-memory
26
+ }
27
+ sync() {
28
+ // no-op for in-memory
29
+ }
30
+ }
31
+ class RandomAccessMemory {
32
+ buffer;
33
+ _position = 0;
34
+ _count = 0;
35
+ constructor(initialSize = 1024) {
36
+ this.buffer = new Uint8Array(initialSize);
37
+ }
38
+ ensureCapacity(minCapacity) {
39
+ if (minCapacity > this.buffer.length) {
40
+ let newCapacity = this.buffer.length * 2;
41
+ if (newCapacity < minCapacity) {
42
+ newCapacity = minCapacity;
43
+ }
44
+ const newBuffer = new Uint8Array(newCapacity);
45
+ newBuffer.set(this.buffer.subarray(0, this._count));
46
+ this.buffer = newBuffer;
47
+ }
48
+ }
49
+ size() {
50
+ return this._count;
51
+ }
52
+ seek(pos) {
53
+ if (pos > this._count) {
54
+ this._position = this._count;
55
+ }
56
+ else {
57
+ this._position = pos;
58
+ }
59
+ }
60
+ getPosition() {
61
+ return this._position;
62
+ }
63
+ setLength(len) {
64
+ if (len === 0) {
65
+ this.reset();
66
+ }
67
+ else {
68
+ if (len > this._count)
69
+ throw new Error('Cannot extend length');
70
+ this._count = len;
71
+ if (this._position > len) {
72
+ this._position = len;
73
+ }
74
+ }
75
+ }
76
+ reset() {
77
+ this._count = 0;
78
+ this._position = 0;
79
+ }
80
+ toByteArray() {
81
+ return this.buffer.slice(0, this._count);
82
+ }
83
+ // DataWriter interface
84
+ write(data) {
85
+ const pos = this._position;
86
+ if (pos < this._count) {
87
+ const bytesBeforeEnd = Math.min(data.length, this._count - pos);
88
+ for (let i = 0; i < bytesBeforeEnd; i++) {
89
+ this.buffer[pos + i] = data[i];
90
+ }
91
+ if (bytesBeforeEnd < data.length) {
92
+ const bytesAfterEnd = data.length - bytesBeforeEnd;
93
+ this.ensureCapacity(this._count + bytesAfterEnd);
94
+ this.buffer.set(data.subarray(bytesBeforeEnd), this._count);
95
+ this._count += bytesAfterEnd;
96
+ }
97
+ }
98
+ else {
99
+ this.ensureCapacity(this._count + data.length);
100
+ this.buffer.set(data, this._count);
101
+ this._count += data.length;
102
+ }
103
+ this._position = pos + data.length;
104
+ }
105
+ writeByte(v) {
106
+ this.write(new Uint8Array([v & 0xff]));
107
+ }
108
+ writeShort(v) {
109
+ const buffer = new ArrayBuffer(2);
110
+ const view = new DataView(buffer);
111
+ view.setInt16(0, v, false); // big-endian
112
+ this.write(new Uint8Array(buffer));
113
+ }
114
+ writeLong(v) {
115
+ const buffer = new ArrayBuffer(8);
116
+ const view = new DataView(buffer);
117
+ view.setBigInt64(0, BigInt(v), false);
118
+ this.write(new Uint8Array(buffer));
119
+ }
120
+ // DataReader interface
121
+ readFully(b) {
122
+ const pos = this._position;
123
+ if (pos + b.length > this._count) {
124
+ throw new Error('End of stream');
125
+ }
126
+ b.set(this.buffer.subarray(pos, pos + b.length));
127
+ this._position = pos + b.length;
128
+ }
129
+ readByte() {
130
+ const bytes = new Uint8Array(1);
131
+ this.readFully(bytes);
132
+ return bytes[0];
133
+ }
134
+ readShort() {
135
+ const bytes = new Uint8Array(2);
136
+ this.readFully(bytes);
137
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
138
+ return view.getInt16(0, false); // big-endian
139
+ }
140
+ readInt() {
141
+ const bytes = new Uint8Array(4);
142
+ this.readFully(bytes);
143
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
144
+ return view.getInt32(0, false); // big-endian
145
+ }
146
+ readLong() {
147
+ const bytes = new Uint8Array(8);
148
+ this.readFully(bytes);
149
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
150
+ return Number(view.getBigInt64(0, false));
151
+ }
152
+ }
package/dist/core.js ADDED
@@ -0,0 +1 @@
1
+ export {};