binary-packet 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -31,9 +31,11 @@ Currently, these kinds of `fields` are supported:
31
31
  | `Field.FLOAT_32` | 32 bits IEEE754 floating-point | | 4 |
32
32
  | `Field.FLOAT_64` | 64 bits IEEE754 floating-point | | 8 |
33
33
  | `BinaryPacket` | BinaryPacket "subpacket" | BinaryPacket | size(BinaryPacket) |
34
- | `FieldArray` | Array of one of the types above | Up to 256 elements | 1 + length \* size(Field) |
34
+ | `FieldArray` | Dynamically-sized array of one of the types above | Up to 256 elements | 1 + length \* size(Element) |
35
+ | `FieldFixedArray` | Statically-sized array of one of the types above | Any pre-defined numbers of elements | length \* size(Element) |
35
36
 
36
- As you can see from the table above, both arrays and nested objects ("subpackets") are supported.
37
+ As you can see from the table above, both arrays and nested objects ("subpackets") are supported. \
38
+ Note that `FieldFixedArray`s are much more memory efficient and performant than `FieldArray`s, but require a pre-defined length.
37
39
 
38
40
  ## Usage Examples
39
41
 
@@ -57,7 +59,7 @@ const CellPacket = BinaryPacket.define(0, Cell)
57
59
  const Board = {
58
60
  numPlayers: Field.UNSIGNED_INT_8,
59
61
  otherStuff: Field.INT_32,
60
- cells: FieldArray(CellPacket) // equivalent to { cells: [CellPacket] }
62
+ cells: FieldArray(CellPacket)
61
63
  }
62
64
 
63
65
  // When done with the board definition we can create its BinaryPacket writer/reader.
@@ -108,14 +110,14 @@ So, take these "performance" comparisons with a grain of salt; or, even better,
108
110
 
109
111
  This library has been benchmarked against the following alternatives:
110
112
 
111
- - [msgpackr](https://www.npmjs.com/package/msgpackr) - A very popular and very fast and battle-tested serialization library. It currently offers **many** more features than binary-packet, but it appears to be 2x-4x slower in writes and 3x-10x slower in reads.
112
- - [restructure](https://www.npmjs.com/package/restructure) - A very popular schema-based serialization library, has some extra features like LazyArrays, but it is **much slower** than both binary-packet and msgpackr. And, sadly, easily crashes with complex structures.
113
+ - [msgpackr](https://www.npmjs.com/package/msgpackr) - A very popular, fast and battle-tested library. Currently offers **many** more features than binary-packet, but it appears to be 2x-4x slower in writes and 3x-10x slower in reads (depends on the packet structure) - is also less type-safe.
114
+ - [restructure](https://www.npmjs.com/package/restructure) - An older, popular schema-based library, has some extra features like LazyArrays, but it is **much slower** than both binary-packet and msgpackr. And, sadly, easily crashes with complex structures.
113
115
 
114
116
  The benchmarks are executed on three different kinds of packets:
115
117
 
116
118
  - EmptyPacket: basically an empty javascript object.
117
- - SimplePacket: objects with primitive-only fields.
118
- - ComplexPacket: objects with primitives, arrays and other nested objects/arrays.
119
+ - SimplePacket: objects with just primitive fields and statically-sized arrays.
120
+ - ComplexPacket: objects with primitives, statically-sized arrays, dynamically-sized arrays and other nested objects/arrays.
119
121
 
120
122
  You can see and run the benchmarks yourself if you clone the repository and launch `npm run benchmark`.
121
123
 
package/dist/index.d.mts CHANGED
@@ -39,10 +39,22 @@ declare const enum Field {
39
39
  FLOAT_64 = 7
40
40
  }
41
41
  /**
42
- * Defines an array of a certain type. \
43
- * As of now, only arrays with at most 256 elements are supported.
42
+ * Defines a dynamically-sized array with elements of a certain type. \
43
+ * Dynamically-sized arrays are useful when a packet's field is an array of a non pre-defined length. \
44
+ * Although, this makes dynamically-sized arrays more memory expensive as the internal buffer needs to be grown accordingly.
45
+ *
46
+ * NOTE: If an array will ALWAYS have the same length, prefer using the `FieldFixedArray` type, for both better performance and memory efficiency. \
47
+ * NOTE: As of now, dynamic arrays can have at most 256 elements.
48
+ */
49
+ declare function FieldArray<T extends Field | BinaryPacket<Definition>>(item: T): [itemType: T];
50
+ /**
51
+ * Defines a statically-sized array with elements of a certain type. \
52
+ * Fixed arrays are useful when a packet's field is an array of a pre-defined length. \
53
+ * Fixed arrays much more memory efficient and performant than non-fixed ones.
54
+ *
55
+ * NOTE: If an array will not always have the same length, use the `FieldArray` type.
44
56
  */
45
- declare function FieldArray<T extends Field | BinaryPacket<Definition>>(item: T): T[];
57
+ declare function FieldFixedArray<T extends Field | BinaryPacket<Definition>, Length extends number>(item: T, length: Length): [itemType: T, length: Length];
46
58
  declare class BinaryPacket<T extends Definition> {
47
59
  private readonly packetId;
48
60
  /**
@@ -139,10 +151,13 @@ declare class BinaryPacket<T extends Definition> {
139
151
  private constructor();
140
152
  private read;
141
153
  private write;
154
+ /**
155
+ * Fast write does not support writing dynamically-sized arrays.
156
+ */
142
157
  private fastWrite;
143
158
  /**
144
159
  * The slow writing path tries writing data into the buffer as fast as the fast writing path does. \
145
- * But, if a non-empty array is encountered, the buffer needs to grow, slightly reducing performance.
160
+ * But, if a non-empty dynamically-sized array is encountered, the buffer needs to grow, slightly reducing performance.
146
161
  */
147
162
  private slowWrite;
148
163
  }
@@ -167,7 +182,7 @@ declare class BinaryPacket<T extends Definition> {
167
182
  * // You can also specify arrays of both "primitive" fields and other BinaryPackets.
168
183
  * const Board = {
169
184
  * numPlayers: Field.UNSIGNED_INT_8,
170
- * cells: FieldArray(CellPacket) // equivalent to { cells: [CellPacket] }
185
+ * cells: FieldArray(CellPacket)
171
186
  * }
172
187
  *
173
188
  * // When done with the board definition we can create its BinaryPacket writer/reader.
@@ -190,13 +205,18 @@ declare class BinaryPacket<T extends Definition> {
190
205
  * // ...
191
206
  */
192
207
  type Definition = {
193
- [fieldName: string]: Field | Field[] | BinaryPacket<Definition> | BinaryPacket<Definition>[];
208
+ [fieldName: string]: MaybeArray<Field> | MaybeArray<BinaryPacket<Definition>>;
194
209
  };
210
+ type MaybeArray<T> = T | [itemType: T] | [itemType: T, length: number];
195
211
  /**
196
212
  * Meta-type that converts a `Definition` schema to the type of the actual JavaScript object that will be written into a packet or read from. \
197
213
  */
198
214
  type ToJson<T extends Definition> = {
199
- [K in keyof T]: T[K] extends ReadonlyArray<infer Item> ? Item extends BinaryPacket<infer BPDef> ? ToJson<BPDef>[] : number[] : T[K] extends BinaryPacket<infer BPDef> ? ToJson<BPDef> : number;
215
+ [K in keyof T]: T[K] extends [infer Item] ? Item extends BinaryPacket<infer BPDef> ? ToJson<BPDef>[] : number[] : T[K] extends [infer Item, infer Length] ? Item extends BinaryPacket<infer BPDef> ? ToJson<BPDef>[] & {
216
+ length: Length;
217
+ } : number[] & {
218
+ length: Length;
219
+ } : T[K] extends BinaryPacket<infer BPDef> ? ToJson<BPDef> : number;
200
220
  };
201
221
 
202
- export { BinaryPacket, type Definition, Field, FieldArray };
222
+ export { BinaryPacket, type Definition, Field, FieldArray, FieldFixedArray };
package/dist/index.d.ts CHANGED
@@ -39,10 +39,22 @@ declare const enum Field {
39
39
  FLOAT_64 = 7
40
40
  }
41
41
  /**
42
- * Defines an array of a certain type. \
43
- * As of now, only arrays with at most 256 elements are supported.
42
+ * Defines a dynamically-sized array with elements of a certain type. \
43
+ * Dynamically-sized arrays are useful when a packet's field is an array of a non pre-defined length. \
44
+ * Although, this makes dynamically-sized arrays more memory expensive as the internal buffer needs to be grown accordingly.
45
+ *
46
+ * NOTE: If an array will ALWAYS have the same length, prefer using the `FieldFixedArray` type, for both better performance and memory efficiency. \
47
+ * NOTE: As of now, dynamic arrays can have at most 256 elements.
48
+ */
49
+ declare function FieldArray<T extends Field | BinaryPacket<Definition>>(item: T): [itemType: T];
50
+ /**
51
+ * Defines a statically-sized array with elements of a certain type. \
52
+ * Fixed arrays are useful when a packet's field is an array of a pre-defined length. \
53
+ * Fixed arrays much more memory efficient and performant than non-fixed ones.
54
+ *
55
+ * NOTE: If an array will not always have the same length, use the `FieldArray` type.
44
56
  */
45
- declare function FieldArray<T extends Field | BinaryPacket<Definition>>(item: T): T[];
57
+ declare function FieldFixedArray<T extends Field | BinaryPacket<Definition>, Length extends number>(item: T, length: Length): [itemType: T, length: Length];
46
58
  declare class BinaryPacket<T extends Definition> {
47
59
  private readonly packetId;
48
60
  /**
@@ -139,10 +151,13 @@ declare class BinaryPacket<T extends Definition> {
139
151
  private constructor();
140
152
  private read;
141
153
  private write;
154
+ /**
155
+ * Fast write does not support writing dynamically-sized arrays.
156
+ */
142
157
  private fastWrite;
143
158
  /**
144
159
  * The slow writing path tries writing data into the buffer as fast as the fast writing path does. \
145
- * But, if a non-empty array is encountered, the buffer needs to grow, slightly reducing performance.
160
+ * But, if a non-empty dynamically-sized array is encountered, the buffer needs to grow, slightly reducing performance.
146
161
  */
147
162
  private slowWrite;
148
163
  }
@@ -167,7 +182,7 @@ declare class BinaryPacket<T extends Definition> {
167
182
  * // You can also specify arrays of both "primitive" fields and other BinaryPackets.
168
183
  * const Board = {
169
184
  * numPlayers: Field.UNSIGNED_INT_8,
170
- * cells: FieldArray(CellPacket) // equivalent to { cells: [CellPacket] }
185
+ * cells: FieldArray(CellPacket)
171
186
  * }
172
187
  *
173
188
  * // When done with the board definition we can create its BinaryPacket writer/reader.
@@ -190,13 +205,18 @@ declare class BinaryPacket<T extends Definition> {
190
205
  * // ...
191
206
  */
192
207
  type Definition = {
193
- [fieldName: string]: Field | Field[] | BinaryPacket<Definition> | BinaryPacket<Definition>[];
208
+ [fieldName: string]: MaybeArray<Field> | MaybeArray<BinaryPacket<Definition>>;
194
209
  };
210
+ type MaybeArray<T> = T | [itemType: T] | [itemType: T, length: number];
195
211
  /**
196
212
  * Meta-type that converts a `Definition` schema to the type of the actual JavaScript object that will be written into a packet or read from. \
197
213
  */
198
214
  type ToJson<T extends Definition> = {
199
- [K in keyof T]: T[K] extends ReadonlyArray<infer Item> ? Item extends BinaryPacket<infer BPDef> ? ToJson<BPDef>[] : number[] : T[K] extends BinaryPacket<infer BPDef> ? ToJson<BPDef> : number;
215
+ [K in keyof T]: T[K] extends [infer Item] ? Item extends BinaryPacket<infer BPDef> ? ToJson<BPDef>[] : number[] : T[K] extends [infer Item, infer Length] ? Item extends BinaryPacket<infer BPDef> ? ToJson<BPDef>[] & {
216
+ length: Length;
217
+ } : number[] & {
218
+ length: Length;
219
+ } : T[K] extends BinaryPacket<infer BPDef> ? ToJson<BPDef> : number;
200
220
  };
201
221
 
202
- export { BinaryPacket, type Definition, Field, FieldArray };
222
+ export { BinaryPacket, type Definition, Field, FieldArray, FieldFixedArray };
package/dist/index.js CHANGED
@@ -1,412 +1,2 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- BinaryPacket: () => BinaryPacket,
24
- Field: () => Field,
25
- FieldArray: () => FieldArray
26
- });
27
- module.exports = __toCommonJS(src_exports);
28
-
29
- // src/buffers.ts
30
- var hasNodeBuffers = typeof Buffer === "function";
31
- function growDataView(dataview, newByteLength) {
32
- const resizedBuffer = new ArrayBuffer(newByteLength);
33
- const amountToCopy = Math.min(dataview.byteLength, resizedBuffer.byteLength);
34
- let length = Math.trunc(amountToCopy / 8);
35
- new Float64Array(resizedBuffer, 0, length).set(new Float64Array(dataview.buffer, 0, length));
36
- const offset = length * 8;
37
- length = amountToCopy - offset;
38
- new Uint8Array(resizedBuffer, offset, length).set(new Uint8Array(dataview.buffer, offset, length));
39
- return new DataView(resizedBuffer);
40
- }
41
- function growNodeBuffer(buffer, newByteLength) {
42
- const newBuffer = Buffer.allocUnsafe(newByteLength);
43
- buffer.copy(newBuffer);
44
- return newBuffer;
45
- }
46
-
47
- // src/index.ts
48
- var Field = /* @__PURE__ */ ((Field2) => {
49
- Field2[Field2["UNSIGNED_INT_8"] = 0] = "UNSIGNED_INT_8";
50
- Field2[Field2["UNSIGNED_INT_16"] = 1] = "UNSIGNED_INT_16";
51
- Field2[Field2["UNSIGNED_INT_32"] = 2] = "UNSIGNED_INT_32";
52
- Field2[Field2["INT_8"] = 3] = "INT_8";
53
- Field2[Field2["INT_16"] = 4] = "INT_16";
54
- Field2[Field2["INT_32"] = 5] = "INT_32";
55
- Field2[Field2["FLOAT_32"] = 6] = "FLOAT_32";
56
- Field2[Field2["FLOAT_64"] = 7] = "FLOAT_64";
57
- return Field2;
58
- })(Field || {});
59
- function FieldArray(item) {
60
- return [item];
61
- }
62
- var BinaryPacket = class _BinaryPacket {
63
- constructor(packetId, definition) {
64
- this.packetId = packetId;
65
- this.entries = definition ? sortEntries(definition) : [];
66
- const inspection = inspectEntries(this.entries);
67
- this.minimumByteLength = inspection.minimumByteLength;
68
- this.canFastWrite = inspection.canFastWrite;
69
- }
70
- /**
71
- * Defines a new binary packet. \
72
- * Make sure that every `packetId` is unique.
73
- * @throws RangeError If packetId is negative, floating-point, or greater than 255.
74
- */
75
- static define(packetId, definition) {
76
- if (packetId < 0 || !Number.isFinite(packetId)) {
77
- throw new RangeError("Packet IDs must be positive integers.");
78
- }
79
- if (packetId > 255) {
80
- throw new RangeError(
81
- "Packet IDs greater than 255 are not supported. Do you REALLY need more than 255 different kinds of packets?"
82
- );
83
- }
84
- return new _BinaryPacket(packetId, definition);
85
- }
86
- /**
87
- * Reads just the packetId from the given Buffer. \
88
- * This method practically just reads the uint8 at offset `byteOffset` (default: 0). \
89
- * Useful if the receiving side receives multiple types of packets.
90
- */
91
- static readPacketIdNodeBuffer(buffer, byteOffset = 0) {
92
- return buffer.readUint8(byteOffset);
93
- }
94
- /**
95
- * Reads just the packetId from the given DataView. \
96
- * This method practically just reads the uint8 at offset `byteOffset` (default: 0). \
97
- * Useful if the receiving side receives multiple types of packets.
98
- */
99
- static readPacketIdDataView(dataview, byteOffset = 0) {
100
- return dataview.getUint8(byteOffset);
101
- }
102
- /**
103
- * Reads just the packetId from the given ArrayBuffer. \
104
- * This method practically just reads the uint8 at offset `byteOffset`. \
105
- * Useful if the receiving side receives multiple types of packets.
106
- *
107
- * NOTE: Due to security issues, the `byteOffset` argument cannot be defaulted and must be provided by the user. \
108
- * NOTE: For more information read the `readArrayBuffer` method documentation.
109
- */
110
- static readPacketIdArrayBuffer(arraybuffer, byteOffset) {
111
- return new Uint8Array(arraybuffer, byteOffset, 1)[0];
112
- }
113
- /**
114
- * Reads/deserializes from the given Buffer. \
115
- * Method available ONLY on NodeJS and Bun.
116
- *
117
- * If possible, always prefer reading using this method, as it is much faster than the other ones.
118
- *
119
- * NOTE: if you have an ArrayBuffer do not bother wrapping it into a node Buffer yourself. \
120
- * NOTE: if you have an ArrayBuffer use the appropriate `readArrayBuffer`.
121
- */
122
- readNodeBuffer(dataIn, offsetPointer = { offset: 0 }, byteLength = dataIn.byteLength) {
123
- return this.read(dataIn, offsetPointer, byteLength, GET_FUNCTION_BUF);
124
- }
125
- /**
126
- * Reads/deserializes from the given DataView.
127
- *
128
- * NOTE: if you have an ArrayBuffer do not bother wrapping it into a DataView yourself. \
129
- * NOTE: if you have an ArrayBuffer use the appropriate `readArrayBuffer`.
130
- */
131
- readDataView(dataIn, offsetPointer = { offset: 0 }, byteLength = dataIn.byteLength) {
132
- return this.read(dataIn, offsetPointer, byteLength, GET_FUNCTION);
133
- }
134
- /**
135
- * Reads/deserializes from the given ArrayBuffer. \
136
- * WARNING: this method is practically a HACK.
137
- *
138
- * When using this method both the `byteOffset` and `byteLength` are REQUIRED and cannot be defaulted. \
139
- * This is to prevent serious bugs and security issues. \
140
- * That is because often raw ArrayBuffers come from a pre-allocated buffer pool and do not start at byteOffset 0.
141
- *
142
- * NOTE: if you have a node Buffer do not bother wrapping it into an ArrayBuffer yourself. \
143
- * NOTE: if you have a node Buffer use the appropriate `readNodeBuffer` as it is much faster and less error prone.
144
- */
145
- readArrayBuffer(dataIn, byteOffset, byteLength) {
146
- return this.read(
147
- hasNodeBuffers ? Buffer.from(dataIn, byteOffset, byteLength) : new DataView(dataIn, byteOffset, byteLength),
148
- { offset: 0 },
149
- // The underlying buffer has already been offsetted
150
- byteLength,
151
- hasNodeBuffers ? GET_FUNCTION_BUF : GET_FUNCTION
152
- );
153
- }
154
- /**
155
- * Writes/serializes the given object into a Buffer. \
156
- * Method available ONLY on NodeJS and Bun.
157
- *
158
- * If possible, always prefer writing using this method, as it is much faster than the other ones.
159
- */
160
- writeNodeBuffer(dataOut) {
161
- const buffer = Buffer.allocUnsafe(this.minimumByteLength);
162
- return this.write(buffer, dataOut, { offset: 0 }, SET_FUNCTION_BUF, growNodeBuffer);
163
- }
164
- /**
165
- * Writes/serializes the given object into a DataView. \
166
- */
167
- writeDataView(dataOut) {
168
- const dataview = new DataView(new ArrayBuffer(this.minimumByteLength));
169
- return this.write(dataview, dataOut, { offset: 0 }, SET_FUNCTION, growDataView);
170
- }
171
- /**
172
- * Writes/serializes the given object into an ArrayBuffer. \
173
- * This method is just a wrapper around either `writeNodeBuffer` or `writeDataView`. \
174
- *
175
- * This method works with JavaScript standard raw ArrayBuffer(s) and, as such, is very error prone: \
176
- * Make sure you're using the returned byteLength and byteOffset fields in the read counterpart. \
177
- *
178
- * Always consider whether is possible to use directly `writeNodeBuffer` or `writeDataView` instead of `writeArrayBuffer`. \
179
- * For more information read the `readArrayBuffer` documentation.
180
- */
181
- writeArrayBuffer(dataOut) {
182
- const buf = hasNodeBuffers ? this.writeNodeBuffer(dataOut) : this.writeDataView(dataOut);
183
- return { buffer: buf.buffer, byteLength: buf.byteLength, byteOffset: buf.byteOffset };
184
- }
185
- entries;
186
- canFastWrite;
187
- minimumByteLength;
188
- read(dataIn, offsetPointer, byteLength, readFunctions) {
189
- if (byteLength + offsetPointer.offset < this.minimumByteLength) {
190
- throw new Error(
191
- `There is no space available to fit a packet of type ${this.packetId} at offset ${offsetPointer.offset}`
192
- );
193
- }
194
- if (readFunctions[0 /* UNSIGNED_INT_8 */](dataIn, offsetPointer.offset) !== this.packetId) {
195
- throw new Error(
196
- `Data at offset ${offsetPointer.offset} is not a packet of type ${this.packetId}`
197
- );
198
- }
199
- offsetPointer.offset += 1;
200
- const result = {};
201
- for (const [name, def] of this.entries) {
202
- if (Array.isArray(def)) {
203
- const length = readFunctions[0 /* UNSIGNED_INT_8 */](dataIn, offsetPointer.offset++);
204
- const array = Array(length);
205
- const itemType = def[0];
206
- if (typeof itemType === "object") {
207
- for (let i = 0; i < length; ++i) {
208
- array[i] = itemType.read(dataIn, offsetPointer, byteLength, readFunctions);
209
- }
210
- } else {
211
- const itemSize = BYTE_SIZE[itemType];
212
- for (let i = 0; i < length; ++i) {
213
- array[i] = readFunctions[itemType](dataIn, offsetPointer.offset);
214
- offsetPointer.offset += itemSize;
215
- }
216
- }
217
- result[name] = array;
218
- } else if (typeof def === "object") {
219
- result[name] = def.read(dataIn, offsetPointer, byteLength, readFunctions);
220
- } else {
221
- result[name] = readFunctions[def](dataIn, offsetPointer.offset);
222
- offsetPointer.offset += BYTE_SIZE[def];
223
- }
224
- }
225
- return result;
226
- }
227
- write(buffer, dataOut, offsetPointer, writeFunctions, growBufferFunction) {
228
- writeFunctions[0 /* UNSIGNED_INT_8 */](buffer, this.packetId, offsetPointer.offset);
229
- offsetPointer.offset += 1;
230
- if (this.canFastWrite) {
231
- this.fastWrite(buffer, dataOut, offsetPointer, writeFunctions);
232
- return buffer;
233
- } else {
234
- return this.slowWrite(
235
- buffer,
236
- dataOut,
237
- offsetPointer,
238
- this.minimumByteLength,
239
- this.minimumByteLength,
240
- writeFunctions,
241
- growBufferFunction
242
- );
243
- }
244
- }
245
- fastWrite(buffer, dataOut, offsetPointer, writeFunctions) {
246
- for (const [name, def] of this.entries) {
247
- if (typeof def === "object") {
248
- ;
249
- def.fastWrite(
250
- buffer,
251
- dataOut[name],
252
- offsetPointer,
253
- writeFunctions
254
- );
255
- } else {
256
- writeFunctions[def](buffer, dataOut[name], offsetPointer.offset);
257
- offsetPointer.offset += BYTE_SIZE[def];
258
- }
259
- }
260
- }
261
- /**
262
- * The slow writing path tries writing data into the buffer as fast as the fast writing path does. \
263
- * But, if a non-empty array is encountered, the buffer needs to grow, slightly reducing performance.
264
- */
265
- slowWrite(buffer, dataOut, offsetPointer, byteLength, maxByteLength, writeFunctions, growBufferFunction) {
266
- for (const [name, def] of this.entries) {
267
- const data = dataOut[name];
268
- if (Array.isArray(def)) {
269
- const length = data.length;
270
- writeFunctions[0 /* UNSIGNED_INT_8 */](buffer, length, offsetPointer.offset);
271
- offsetPointer.offset += 1;
272
- if (length > 0) {
273
- const itemType = def[0];
274
- if (typeof itemType === "object") {
275
- const neededBytesForElements = length * itemType.minimumByteLength;
276
- byteLength += neededBytesForElements;
277
- maxByteLength += neededBytesForElements;
278
- if (buffer.byteLength < maxByteLength) {
279
- buffer = growBufferFunction(buffer, maxByteLength);
280
- }
281
- for (const object of data) {
282
- writeFunctions[0 /* UNSIGNED_INT_8 */](
283
- buffer,
284
- itemType.packetId,
285
- offsetPointer.offset
286
- );
287
- offsetPointer.offset += 1;
288
- buffer = itemType.slowWrite(
289
- buffer,
290
- object,
291
- offsetPointer,
292
- byteLength,
293
- maxByteLength,
294
- writeFunctions,
295
- growBufferFunction
296
- );
297
- byteLength = offsetPointer.offset;
298
- maxByteLength = buffer.byteLength;
299
- }
300
- } else {
301
- const itemSize = BYTE_SIZE[itemType];
302
- const neededBytesForElements = length * itemSize;
303
- byteLength += neededBytesForElements;
304
- maxByteLength += neededBytesForElements;
305
- if (buffer.byteLength < maxByteLength) {
306
- buffer = growBufferFunction(buffer, maxByteLength);
307
- }
308
- for (const number of data) {
309
- writeFunctions[itemType](buffer, number, offsetPointer.offset);
310
- offsetPointer.offset += itemSize;
311
- }
312
- }
313
- }
314
- } else if (typeof def === "object") {
315
- writeFunctions[0 /* UNSIGNED_INT_8 */](buffer, def.packetId, offsetPointer.offset);
316
- offsetPointer.offset += 1;
317
- buffer = def.slowWrite(
318
- buffer,
319
- data,
320
- offsetPointer,
321
- byteLength,
322
- maxByteLength,
323
- writeFunctions,
324
- growBufferFunction
325
- );
326
- byteLength = offsetPointer.offset;
327
- maxByteLength = buffer.byteLength;
328
- } else {
329
- writeFunctions[def](buffer, data, offsetPointer.offset);
330
- offsetPointer.offset += BYTE_SIZE[def];
331
- }
332
- }
333
- return buffer;
334
- }
335
- };
336
- function sortEntries(definition) {
337
- return Object.entries(definition).sort(
338
- ([fieldName1], [fieldName2]) => fieldName1.localeCompare(fieldName2)
339
- );
340
- }
341
- function inspectEntries(entries) {
342
- let minimumByteLength = 1;
343
- let canFastWrite = true;
344
- for (const [, type] of entries) {
345
- if (Array.isArray(type)) {
346
- minimumByteLength += 1;
347
- canFastWrite = false;
348
- } else if (type instanceof BinaryPacket) {
349
- minimumByteLength += type.minimumByteLength;
350
- canFastWrite &&= type.canFastWrite;
351
- } else {
352
- minimumByteLength += BYTE_SIZE[type];
353
- }
354
- }
355
- return { minimumByteLength, canFastWrite };
356
- }
357
- var BYTE_SIZE = Array(8);
358
- BYTE_SIZE[0 /* UNSIGNED_INT_8 */] = 1;
359
- BYTE_SIZE[3 /* INT_8 */] = 1;
360
- BYTE_SIZE[1 /* UNSIGNED_INT_16 */] = 2;
361
- BYTE_SIZE[4 /* INT_16 */] = 2;
362
- BYTE_SIZE[2 /* UNSIGNED_INT_32 */] = 4;
363
- BYTE_SIZE[5 /* INT_32 */] = 4;
364
- BYTE_SIZE[6 /* FLOAT_32 */] = 4;
365
- BYTE_SIZE[7 /* FLOAT_64 */] = 8;
366
- var GET_FUNCTION = Array(8);
367
- GET_FUNCTION[0 /* UNSIGNED_INT_8 */] = (view, offset) => view.getUint8(offset);
368
- GET_FUNCTION[3 /* INT_8 */] = (view, offset) => view.getInt8(offset);
369
- GET_FUNCTION[1 /* UNSIGNED_INT_16 */] = (view, offset, le) => view.getUint16(offset, le);
370
- GET_FUNCTION[4 /* INT_16 */] = (view, offset, le) => view.getInt16(offset, le);
371
- GET_FUNCTION[2 /* UNSIGNED_INT_32 */] = (view, offset, le) => view.getUint32(offset, le);
372
- GET_FUNCTION[5 /* INT_32 */] = (view, offset, le) => view.getInt32(offset, le);
373
- GET_FUNCTION[6 /* FLOAT_32 */] = (view, offset, le) => view.getFloat32(offset, le);
374
- GET_FUNCTION[7 /* FLOAT_64 */] = (view, offset, le) => view.getFloat64(offset, le);
375
- var SET_FUNCTION = Array(8);
376
- SET_FUNCTION[0 /* UNSIGNED_INT_8 */] = (view, value, offset) => view.setUint8(offset, value);
377
- SET_FUNCTION[3 /* INT_8 */] = (view, value, offset) => view.setInt8(offset, value);
378
- SET_FUNCTION[1 /* UNSIGNED_INT_16 */] = (view, value, offset) => view.setUint16(offset, value);
379
- SET_FUNCTION[4 /* INT_16 */] = (view, value, offset) => view.setInt16(offset, value);
380
- SET_FUNCTION[2 /* UNSIGNED_INT_32 */] = (view, value, offset) => view.setUint32(offset, value);
381
- SET_FUNCTION[5 /* INT_32 */] = (view, value, offset) => view.setInt32(offset, value);
382
- SET_FUNCTION[6 /* FLOAT_32 */] = (view, value, offset) => view.setFloat32(offset, value);
383
- SET_FUNCTION[7 /* FLOAT_64 */] = (view, value, offset) => view.setFloat64(offset, value);
384
- var SET_FUNCTION_BUF = Array(8);
385
- if (hasNodeBuffers) {
386
- SET_FUNCTION_BUF[0 /* UNSIGNED_INT_8 */] = (view, value, offset) => view.writeUint8(value, offset);
387
- SET_FUNCTION_BUF[3 /* INT_8 */] = (view, value, offset) => view.writeInt8(value, offset);
388
- SET_FUNCTION_BUF[1 /* UNSIGNED_INT_16 */] = (view, value, offset) => view.writeUint16LE(value, offset);
389
- SET_FUNCTION_BUF[4 /* INT_16 */] = (view, value, offset) => view.writeInt16LE(value, offset);
390
- SET_FUNCTION_BUF[2 /* UNSIGNED_INT_32 */] = (view, value, offset) => view.writeUint32LE(value, offset);
391
- SET_FUNCTION_BUF[5 /* INT_32 */] = (view, value, offset) => view.writeInt32LE(value, offset);
392
- SET_FUNCTION_BUF[6 /* FLOAT_32 */] = (view, value, offset) => view.writeFloatLE(value, offset);
393
- SET_FUNCTION_BUF[7 /* FLOAT_64 */] = (view, value, offset) => view.writeDoubleLE(value, offset);
394
- }
395
- var GET_FUNCTION_BUF = Array(8);
396
- if (hasNodeBuffers) {
397
- GET_FUNCTION_BUF[0 /* UNSIGNED_INT_8 */] = (view, offset) => view.readUint8(offset);
398
- GET_FUNCTION_BUF[3 /* INT_8 */] = (view, offset) => view.readInt8(offset);
399
- GET_FUNCTION_BUF[1 /* UNSIGNED_INT_16 */] = (view, offset) => view.readUint16LE(offset);
400
- GET_FUNCTION_BUF[4 /* INT_16 */] = (view, offset) => view.readInt16LE(offset);
401
- GET_FUNCTION_BUF[2 /* UNSIGNED_INT_32 */] = (view, offset) => view.readUint32LE(offset);
402
- GET_FUNCTION_BUF[5 /* INT_32 */] = (view, offset) => view.readInt32LE(offset);
403
- GET_FUNCTION_BUF[6 /* FLOAT_32 */] = (view, offset) => view.readFloatLE(offset);
404
- GET_FUNCTION_BUF[7 /* FLOAT_64 */] = (view, offset) => view.readDoubleLE(offset);
405
- }
406
- // Annotate the CommonJS export names for ESM import in node:
407
- 0 && (module.exports = {
408
- BinaryPacket,
409
- Field,
410
- FieldArray
411
- });
1
+ "use strict";var E=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var g=(n,e)=>{for(var t in e)E(n,t,{get:e[t],enumerable:!0})},S=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of b(e))!L.call(n,i)&&i!==t&&E(n,i,{get:()=>e[i],enumerable:!(r=A(e,i))||r.enumerable});return n};var G=n=>S(E({},"__esModule",{value:!0}),n);var v={};g(v,{BinaryPacket:()=>p,Field:()=>w,FieldArray:()=>O,FieldFixedArray:()=>k});module.exports=G(v);var B=typeof Buffer=="function";function U(n,e){let t=new ArrayBuffer(e),r=Math.min(n.byteLength,t.byteLength),i=Math.trunc(r/8);new Float64Array(t,0,i).set(new Float64Array(n.buffer,0,i));let s=i*8;return i=r-s,new Uint8Array(t,s,i).set(new Uint8Array(n.buffer,s,i)),new DataView(t)}function h(n,e){let t=Buffer.allocUnsafe(e);return n.copy(t),t}var w=(a=>(a[a.UNSIGNED_INT_8=0]="UNSIGNED_INT_8",a[a.UNSIGNED_INT_16=1]="UNSIGNED_INT_16",a[a.UNSIGNED_INT_32=2]="UNSIGNED_INT_32",a[a.INT_8=3]="INT_8",a[a.INT_16=4]="INT_16",a[a.INT_32=5]="INT_32",a[a.FLOAT_32=6]="FLOAT_32",a[a.FLOAT_64=7]="FLOAT_64",a))(w||{});function O(n){return[n]}function k(n,e){if(e<0||!Number.isFinite(e))throw new RangeError("Length of a FixedArray must be a positive integer.");return[n,e]}var p=class n{constructor(e,t){this.packetId=e;this.entries=t?J(t):[];let r=V(this.entries);this.minimumByteLength=r.minimumByteLength,this.canFastWrite=r.canFastWrite}static define(e,t){if(e<0||!Number.isFinite(e))throw new RangeError("Packet IDs must be positive integers.");if(e>255)throw new RangeError("Packet IDs greater than 255 are not supported. Do you REALLY need more than 255 different kinds of packets?");return new n(e,t)}static readPacketIdNodeBuffer(e,t=0){return e.readUint8(t)}static readPacketIdDataView(e,t=0){return e.getUint8(t)}static readPacketIdArrayBuffer(e,t){return new Uint8Array(e,t,1)[0]}readNodeBuffer(e,t={offset:0},r=e.byteLength){return this.read(e,t,r,l)}readDataView(e,t={offset:0},r=e.byteLength){return this.read(e,t,r,m)}readArrayBuffer(e,t,r){return this.read(B?Buffer.from(e,t,r):new DataView(e,t,r),{offset:0},r,B?l:m)}writeNodeBuffer(e){let t=Buffer.allocUnsafe(this.minimumByteLength);return this.write(t,e,{offset:0},d,h)}writeDataView(e){let t=new DataView(new ArrayBuffer(this.minimumByteLength));return this.write(t,e,{offset:0},I,U)}writeArrayBuffer(e){let t=B?this.writeNodeBuffer(e):this.writeDataView(e);return{buffer:t.buffer,byteLength:t.byteLength,byteOffset:t.byteOffset}}entries;canFastWrite;minimumByteLength;read(e,t,r,i){if(r+t.offset<this.minimumByteLength)throw new Error(`There is no space available to fit a packet of type ${this.packetId} at offset ${t.offset}`);if(i[0](e,t.offset)!==this.packetId)throw new Error(`Data at offset ${t.offset} is not a packet of type ${this.packetId}`);t.offset+=1;let s={};for(let[f,o]of this.entries)if(Array.isArray(o)){let a=o[1]??i[0](e,t.offset++),y=Array(a),T=o[0];if(typeof T=="object")for(let u=0;u<a;++u)y[u]=T.read(e,t,r,i);else{let u=N[T];for(let _=0;_<a;++_)y[_]=i[T](e,t.offset),t.offset+=u}s[f]=y}else typeof o=="object"?s[f]=o.read(e,t,r,i):(s[f]=i[o](e,t.offset),t.offset+=N[o]);return s}write(e,t,r,i,s){return i[0](e,this.packetId,r.offset),r.offset+=1,this.canFastWrite?(this.fastWrite(e,t,r,i),e):this.slowWrite(e,t,r,this.minimumByteLength,this.minimumByteLength,i,s)}fastWrite(e,t,r,i){for(let[s,f]of this.entries)if(Array.isArray(f)){let o=f[0],a=f[1],y=t[s];if(typeof o=="object")for(let T=0;T<a;++T)o.fastWrite(e,y[T],r,i);else{let T=N[o];for(let u=0;u<a;++u)i[o](e,y[u],r.offset),r.offset+=T}}else typeof f=="object"?f.fastWrite(e,t[s],r,i):(i[f](e,t[s],r.offset),r.offset+=N[f])}slowWrite(e,t,r,i,s,f,o){for(let[a,y]of this.entries){let T=t[a];if(Array.isArray(y)){let u=T.length,_=y[1]===void 0;if(_&&(f[0](e,u,r.offset),r.offset+=1),u>0){let D=y[0];if(typeof D=="object"){if(_){let c=u*D.minimumByteLength;i+=c,s+=c,e.byteLength<s&&(e=o(e,s))}for(let c of T)f[0](e,D.packetId,r.offset),r.offset+=1,e=D.slowWrite(e,c,r,i,s,f,o),i=r.offset,s=e.byteLength}else{let c=N[D];if(_){let F=u*c;i+=F,s+=F,e.byteLength<s&&(e=o(e,s))}for(let F of T)f[D](e,F,r.offset),r.offset+=c}}}else typeof y=="object"?(f[0](e,y.packetId,r.offset),r.offset+=1,e=y.slowWrite(e,T,r,i,s,f,o),i=r.offset,s=e.byteLength):(f[y](e,T,r.offset),r.offset+=N[y])}return e}};function J(n){return Object.entries(n).sort(([e],[t])=>e.localeCompare(t))}function V(n){let e=1,t=!0;for(let[,r]of n)if(Array.isArray(r))if(r.length===2){let i=typeof r[0]=="object"?r[0].minimumByteLength:N[r[0]];e+=r[1]*i}else e+=1,t=!1;else r instanceof p?(e+=r.minimumByteLength,t&&=r.canFastWrite):e+=N[r];return{minimumByteLength:e,canFastWrite:t}}var N=Array(8);N[0]=1;N[3]=1;N[1]=2;N[4]=2;N[2]=4;N[5]=4;N[6]=4;N[7]=8;var m=Array(8);m[0]=(n,e)=>n.getUint8(e);m[3]=(n,e)=>n.getInt8(e);m[1]=(n,e)=>n.getUint16(e);m[4]=(n,e)=>n.getInt16(e);m[2]=(n,e)=>n.getUint32(e);m[5]=(n,e)=>n.getInt32(e);m[6]=(n,e)=>n.getFloat32(e);m[7]=(n,e)=>n.getFloat64(e);var I=Array(8);I[0]=(n,e,t)=>n.setUint8(t,e);I[3]=(n,e,t)=>n.setInt8(t,e);I[1]=(n,e,t)=>n.setUint16(t,e);I[4]=(n,e,t)=>n.setInt16(t,e);I[2]=(n,e,t)=>n.setUint32(t,e);I[5]=(n,e,t)=>n.setInt32(t,e);I[6]=(n,e,t)=>n.setFloat32(t,e);I[7]=(n,e,t)=>n.setFloat64(t,e);var d=Array(8);B&&(d[0]=(n,e,t)=>n.writeUint8(e,t),d[3]=(n,e,t)=>n.writeInt8(e,t),d[1]=(n,e,t)=>n.writeUint16LE(e,t),d[4]=(n,e,t)=>n.writeInt16LE(e,t),d[2]=(n,e,t)=>n.writeUint32LE(e,t),d[5]=(n,e,t)=>n.writeInt32LE(e,t),d[6]=(n,e,t)=>n.writeFloatLE(e,t),d[7]=(n,e,t)=>n.writeDoubleLE(e,t));var l=Array(8);B&&(l[0]=(n,e)=>n.readUint8(e),l[3]=(n,e)=>n.readInt8(e),l[1]=(n,e)=>n.readUint16LE(e),l[4]=(n,e)=>n.readInt16LE(e),l[2]=(n,e)=>n.readUint32LE(e),l[5]=(n,e)=>n.readInt32LE(e),l[6]=(n,e)=>n.readFloatLE(e),l[7]=(n,e)=>n.readDoubleLE(e));0&&(module.exports={BinaryPacket,Field,FieldArray,FieldFixedArray});
412
2
  //# sourceMappingURL=index.js.map