@yume-chan/struct 0.0.18 → 0.0.20

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 (73) hide show
  1. package/CHANGELOG.json +27 -0
  2. package/CHANGELOG.md +16 -1
  3. package/README.md +126 -143
  4. package/esm/basic/definition.d.ts +43 -43
  5. package/esm/basic/definition.d.ts.map +1 -1
  6. package/esm/basic/definition.js +23 -23
  7. package/esm/basic/definition.js.map +1 -1
  8. package/esm/basic/field-value.d.ts +38 -38
  9. package/esm/basic/field-value.d.ts.map +1 -1
  10. package/esm/basic/field-value.js +45 -45
  11. package/esm/basic/index.d.ts +5 -5
  12. package/esm/basic/index.js +5 -5
  13. package/esm/basic/options.d.ts +9 -9
  14. package/esm/basic/options.js +3 -3
  15. package/esm/basic/stream.d.ts +24 -19
  16. package/esm/basic/stream.d.ts.map +1 -1
  17. package/esm/basic/stream.js +7 -1
  18. package/esm/basic/stream.js.map +1 -1
  19. package/esm/basic/struct-value.d.ts +25 -25
  20. package/esm/basic/struct-value.d.ts.map +1 -1
  21. package/esm/basic/struct-value.js +56 -56
  22. package/esm/index.d.ts +14 -13
  23. package/esm/index.d.ts.map +1 -1
  24. package/esm/index.js +6 -5
  25. package/esm/index.js.map +1 -1
  26. package/esm/struct.d.ts +140 -129
  27. package/esm/struct.d.ts.map +1 -1
  28. package/esm/struct.js +242 -210
  29. package/esm/struct.js.map +1 -1
  30. package/esm/sync-promise.d.ts +12 -12
  31. package/esm/sync-promise.js +70 -70
  32. package/esm/sync-promise.js.map +1 -1
  33. package/esm/types/bigint.d.ts +25 -24
  34. package/esm/types/bigint.d.ts.map +1 -1
  35. package/esm/types/bigint.js +47 -46
  36. package/esm/types/bigint.js.map +1 -1
  37. package/esm/types/buffer/base.d.ts +64 -63
  38. package/esm/types/buffer/base.d.ts.map +1 -1
  39. package/esm/types/buffer/base.js +102 -100
  40. package/esm/types/buffer/base.js.map +1 -1
  41. package/esm/types/buffer/fixed-length.d.ts +8 -7
  42. package/esm/types/buffer/fixed-length.d.ts.map +1 -1
  43. package/esm/types/buffer/fixed-length.js +6 -6
  44. package/esm/types/buffer/fixed-length.js.map +1 -1
  45. package/esm/types/buffer/index.d.ts +3 -3
  46. package/esm/types/buffer/index.js +3 -3
  47. package/esm/types/buffer/variable-length.d.ts +44 -42
  48. package/esm/types/buffer/variable-length.d.ts.map +1 -1
  49. package/esm/types/buffer/variable-length.js +75 -75
  50. package/esm/types/buffer/variable-length.js.map +1 -1
  51. package/esm/types/index.d.ts +3 -3
  52. package/esm/types/index.js +3 -3
  53. package/esm/types/number.d.ts +27 -26
  54. package/esm/types/number.d.ts.map +1 -1
  55. package/esm/types/number.js +111 -113
  56. package/esm/types/number.js.map +1 -1
  57. package/esm/utils.d.ts +47 -47
  58. package/esm/utils.js +15 -15
  59. package/package.json +9 -8
  60. package/src/basic/definition.ts +6 -9
  61. package/src/basic/field-value.ts +3 -3
  62. package/src/basic/index.ts +5 -5
  63. package/src/basic/stream.ts +18 -7
  64. package/src/basic/struct-value.ts +1 -1
  65. package/src/index.ts +6 -5
  66. package/src/struct.ts +91 -59
  67. package/src/sync-promise.ts +12 -12
  68. package/src/types/bigint.ts +11 -12
  69. package/src/types/buffer/base.ts +12 -12
  70. package/src/types/buffer/fixed-length.ts +2 -1
  71. package/src/types/buffer/variable-length.ts +8 -11
  72. package/src/types/number.ts +28 -33
  73. package/tsconfig.build.tsbuildinfo +1 -1
package/src/struct.ts CHANGED
@@ -1,14 +1,23 @@
1
+ import type {
2
+ AsyncExactReadable,
3
+ ExactReadable,
4
+ StructFieldDefinition,
5
+ StructFieldValue,
6
+ StructOptions,
7
+ } from "./basic/index.js";
1
8
  import {
9
+ ExactReadableEndedError,
2
10
  STRUCT_VALUE_SYMBOL,
3
11
  StructDefaultOptions,
4
12
  StructValue,
5
- type StructAsyncDeserializeStream,
6
- type StructDeserializeStream,
7
- type StructFieldDefinition,
8
- type StructFieldValue,
9
- type StructOptions,
10
13
  } from "./basic/index.js";
11
14
  import { SyncPromise } from "./sync-promise.js";
15
+ import type {
16
+ BufferFieldSubType,
17
+ FixedLengthBufferLikeFieldOptions,
18
+ LengthField,
19
+ VariableLengthBufferLikeFieldOptions,
20
+ } from "./types/index.js";
12
21
  import {
13
22
  BigIntFieldDefinition,
14
23
  BigIntFieldType,
@@ -18,22 +27,11 @@ import {
18
27
  StringBufferFieldSubType,
19
28
  Uint8ArrayBufferFieldSubType,
20
29
  VariableLengthBufferLikeFieldDefinition,
21
- type BufferFieldSubType,
22
- type FixedLengthBufferLikeFieldOptions,
23
- type LengthField,
24
- type VariableLengthBufferLikeFieldOptions,
25
30
  } from "./types/index.js";
26
- import {
27
- type Evaluate,
28
- type Identity,
29
- type Overwrite,
30
- type ValueOrPromise,
31
- } from "./utils.js";
31
+ import type { Evaluate, Identity, Overwrite, ValueOrPromise } from "./utils.js";
32
32
 
33
33
  export interface StructLike<TValue> {
34
- deserialize(
35
- stream: StructDeserializeStream | StructAsyncDeserializeStream
36
- ): Promise<TValue>;
34
+ deserialize(stream: ExactReadable | AsyncExactReadable): Promise<TValue>;
37
35
  }
38
36
 
39
37
  /**
@@ -193,6 +191,27 @@ export type StructDeserializedResult<
193
191
  ? Overwrite<TExtra, TFields>
194
192
  : TPostDeserialized;
195
193
 
194
+ export class StructDeserializeError extends Error {
195
+ public constructor(message: string) {
196
+ super(message);
197
+ Object.setPrototypeOf(this, new.target.prototype);
198
+ }
199
+ }
200
+
201
+ export class StructNotEnoughDataError extends StructDeserializeError {
202
+ public constructor() {
203
+ super(
204
+ "The underlying readable was ended before the struct was fully deserialized"
205
+ );
206
+ }
207
+ }
208
+
209
+ export class StructEmptyError extends StructDeserializeError {
210
+ public constructor() {
211
+ super("The underlying readable doesn't contain any more struct");
212
+ }
213
+ }
214
+
196
215
  export class Struct<
197
216
  TFields extends object = Record<never, never>,
198
217
  TOmitInitKey extends PropertyKey = never,
@@ -219,22 +238,28 @@ export class Struct<
219
238
 
220
239
  public readonly options: Readonly<StructOptions>;
221
240
 
222
- private _size = 0;
241
+ #size = 0;
223
242
  /**
224
243
  * Gets the static size (exclude fields that can change size at runtime)
225
244
  */
226
245
  public get size() {
227
- return this._size;
246
+ return this.#size;
228
247
  }
229
248
 
230
- private _fields: [
249
+ #fields: [
231
250
  name: PropertyKey,
232
251
  definition: StructFieldDefinition<any, any, any>
233
252
  ][] = [];
253
+ public get fields(): readonly [
254
+ name: PropertyKey,
255
+ definition: StructFieldDefinition<any, any, any>
256
+ ][] {
257
+ return this.#fields;
258
+ }
234
259
 
235
- private _extra: Record<PropertyKey, unknown> = {};
260
+ #extra: Record<PropertyKey, unknown> = {};
236
261
 
237
- private _postDeserialized?: StructPostDeserialized<any, any> | undefined;
262
+ #postDeserialized?: StructPostDeserialized<any, any> | undefined;
238
263
 
239
264
  public constructor(options?: Partial<Readonly<StructOptions>>) {
240
265
  this.options = { ...StructDefaultOptions, ...options };
@@ -257,20 +282,20 @@ export class Struct<
257
282
  TName,
258
283
  TDefinition
259
284
  > {
260
- for (const field of this._fields) {
285
+ for (const field of this.#fields) {
261
286
  if (field[0] === name) {
287
+ // Convert Symbol to string
288
+ const nameString = String(name);
262
289
  throw new Error(
263
- `This struct already have a field with name '${String(
264
- name
265
- )}'`
290
+ `This struct already have a field with name '${nameString}'`
266
291
  );
267
292
  }
268
293
  }
269
294
 
270
- this._fields.push([name, definition]);
295
+ this.#fields.push([name, definition]);
271
296
 
272
297
  const size = definition.getSize();
273
- this._size += size;
298
+ this.#size += size;
274
299
 
275
300
  // Force cast `this` to another type
276
301
  return this as any;
@@ -279,7 +304,7 @@ export class Struct<
279
304
  /**
280
305
  * Merges (flats) another `Struct`'s fields and extra fields into this one.
281
306
  */
282
- public fields<TOther extends Struct<any, any, any, any>>(
307
+ public concat<TOther extends Struct<any, any, any, any>>(
283
308
  other: TOther
284
309
  ): Struct<
285
310
  TFields & TOther["TFields"],
@@ -287,13 +312,13 @@ export class Struct<
287
312
  TExtra & TOther["TExtra"],
288
313
  TPostDeserialized
289
314
  > {
290
- for (const field of other._fields) {
291
- this._fields.push(field);
315
+ for (const field of other.#fields) {
316
+ this.#fields.push(field);
292
317
  }
293
- this._size += other._size;
318
+ this.#size += other.#size;
294
319
  Object.defineProperties(
295
- this._extra,
296
- Object.getOwnPropertyDescriptors(other._extra)
320
+ this.#extra,
321
+ Object.getOwnPropertyDescriptors(other.#extra)
297
322
  );
298
323
  return this as any;
299
324
  }
@@ -479,7 +504,7 @@ export class Struct<
479
504
  value: T & ThisType<Overwrite<Overwrite<TExtra, T>, TFields>>
480
505
  ): Struct<TFields, TOmitInitKey, Overwrite<TExtra, T>, TPostDeserialized> {
481
506
  Object.defineProperties(
482
- this._extra,
507
+ this.#extra,
483
508
  Object.getOwnPropertyDescriptors(value)
484
509
  );
485
510
  return this as any;
@@ -513,7 +538,7 @@ export class Struct<
513
538
  callback?: StructPostDeserialized<TFields, TPostSerialize>
514
539
  ): Struct<TFields, TOmitInitKey, TExtra, TPostSerialize>;
515
540
  public postDeserialize(callback?: StructPostDeserialized<TFields, any>) {
516
- this._postDeserialized = callback;
541
+ this.#postDeserialized = callback;
517
542
  return this as any;
518
543
  }
519
544
 
@@ -521,44 +546,51 @@ export class Struct<
521
546
  * Deserialize a struct value from `stream`.
522
547
  */
523
548
  public deserialize(
524
- stream: StructDeserializeStream
549
+ stream: ExactReadable
525
550
  ): StructDeserializedResult<TFields, TExtra, TPostDeserialized>;
526
551
  public deserialize(
527
- stream: StructAsyncDeserializeStream
552
+ stream: AsyncExactReadable
528
553
  ): Promise<StructDeserializedResult<TFields, TExtra, TPostDeserialized>>;
529
554
  public deserialize(
530
- stream: StructDeserializeStream | StructAsyncDeserializeStream
555
+ stream: ExactReadable | AsyncExactReadable
531
556
  ): ValueOrPromise<
532
557
  StructDeserializedResult<TFields, TExtra, TPostDeserialized>
533
558
  > {
534
- const structValue = new StructValue(this._extra);
559
+ const structValue = new StructValue(this.#extra);
535
560
 
536
561
  let promise = SyncPromise.resolve();
537
562
 
538
- for (const [name, definition] of this._fields) {
563
+ const startPosition = stream.position;
564
+ for (const [name, definition] of this.#fields) {
539
565
  promise = promise
540
566
  .then(() =>
541
- definition.deserialize(
542
- this.options,
543
- stream as any,
544
- structValue
545
- )
567
+ definition.deserialize(this.options, stream, structValue)
546
568
  )
547
- .then((fieldValue) => {
548
- structValue.set(name, fieldValue);
549
- });
569
+ .then(
570
+ (fieldValue) => {
571
+ structValue.set(name, fieldValue);
572
+ },
573
+ (e) => {
574
+ if (!(e instanceof ExactReadableEndedError)) {
575
+ throw e;
576
+ }
577
+
578
+ if (stream.position === startPosition) {
579
+ throw new StructEmptyError();
580
+ } else {
581
+ throw new StructNotEnoughDataError();
582
+ }
583
+ }
584
+ );
550
585
  }
551
586
 
552
587
  return promise
553
588
  .then(() => {
554
- const object = structValue.value;
589
+ const value = structValue.value;
555
590
 
556
591
  // Run `postDeserialized`
557
- if (this._postDeserialized) {
558
- const override = this._postDeserialized.call(
559
- object,
560
- object
561
- );
592
+ if (this.#postDeserialized) {
593
+ const override = this.#postDeserialized.call(value, value);
562
594
  // If it returns a new value, use that as result
563
595
  // Otherwise it only inspects/mutates the object in place.
564
596
  if (override !== undefined) {
@@ -566,7 +598,7 @@ export class Struct<
566
598
  }
567
599
  }
568
600
 
569
- return object;
601
+ return value;
570
602
  })
571
603
  .valueOrPromise();
572
604
  }
@@ -591,7 +623,7 @@ export class Struct<
591
623
  }
592
624
  } else {
593
625
  structValue = new StructValue({});
594
- for (const [name, definition] of this._fields) {
626
+ for (const [name, definition] of this.#fields) {
595
627
  const fieldValue = definition.create(
596
628
  this.options,
597
629
  structValue,
@@ -604,7 +636,7 @@ export class Struct<
604
636
  let structSize = 0;
605
637
  const fieldsInfo: { fieldValue: StructFieldValue; size: number }[] = [];
606
638
 
607
- for (const [name] of this._fields) {
639
+ for (const [name] of this.#fields) {
608
640
  const fieldValue = structValue.get(name);
609
641
  const size = fieldValue.getSize();
610
642
  fieldsInfo.push({ fieldValue, size });
@@ -55,10 +55,10 @@ export const SyncPromise: SyncPromiseStatic = {
55
55
  };
56
56
 
57
57
  class PendingSyncPromise<T> implements SyncPromise<T> {
58
- private promise: PromiseLike<T>;
58
+ #promise: PromiseLike<T>;
59
59
 
60
60
  public constructor(promise: PromiseLike<T>) {
61
- this.promise = promise;
61
+ this.#promise = promise;
62
62
  }
63
63
 
64
64
  public then<TResult1 = T, TResult2 = never>(
@@ -72,20 +72,20 @@ class PendingSyncPromise<T> implements SyncPromise<T> {
72
72
  | undefined
73
73
  ) {
74
74
  return new PendingSyncPromise<TResult1 | TResult2>(
75
- this.promise.then(onfulfilled, onrejected)
75
+ this.#promise.then(onfulfilled, onrejected)
76
76
  );
77
77
  }
78
78
 
79
79
  public valueOrPromise(): T | PromiseLike<T> {
80
- return this.promise;
80
+ return this.#promise;
81
81
  }
82
82
  }
83
83
 
84
84
  class ResolvedSyncPromise<T> implements SyncPromise<T> {
85
- private value: T;
85
+ #value: T;
86
86
 
87
87
  public constructor(value: T) {
88
- this.value = value;
88
+ this.#value = value;
89
89
  }
90
90
 
91
91
  public then<TResult1 = T>(
@@ -97,19 +97,19 @@ class ResolvedSyncPromise<T> implements SyncPromise<T> {
97
97
  if (!onfulfilled) {
98
98
  return this as any;
99
99
  }
100
- return SyncPromise.try(() => onfulfilled(this.value));
100
+ return SyncPromise.try(() => onfulfilled(this.#value));
101
101
  }
102
102
 
103
103
  public valueOrPromise(): T | PromiseLike<T> {
104
- return this.value;
104
+ return this.#value;
105
105
  }
106
106
  }
107
107
 
108
108
  class RejectedSyncPromise<T> implements SyncPromise<T> {
109
- private reason: any;
109
+ #reason: any;
110
110
 
111
111
  public constructor(reason: any) {
112
- this.reason = reason;
112
+ this.#reason = reason;
113
113
  }
114
114
 
115
115
  public then<TResult1 = T, TResult2 = never>(
@@ -125,10 +125,10 @@ class RejectedSyncPromise<T> implements SyncPromise<T> {
125
125
  if (!onrejected) {
126
126
  return this as any;
127
127
  }
128
- return SyncPromise.try(() => onrejected(this.reason));
128
+ return SyncPromise.try(() => onrejected(this.#reason));
129
129
  }
130
130
 
131
131
  public valueOrPromise(): T | PromiseLike<T> {
132
- throw this.reason;
132
+ throw this.#reason;
133
133
  }
134
134
  }
@@ -5,16 +5,15 @@ import {
5
5
  setBigUint64,
6
6
  } from "@yume-chan/dataview-bigint-polyfill/esm/fallback.js";
7
7
 
8
- import {
9
- StructFieldDefinition,
10
- StructFieldValue,
11
- type StructAsyncDeserializeStream,
12
- type StructDeserializeStream,
13
- type StructOptions,
14
- type StructValue,
8
+ import type {
9
+ AsyncExactReadable,
10
+ ExactReadable,
11
+ StructOptions,
12
+ StructValue,
15
13
  } from "../basic/index.js";
14
+ import { StructFieldDefinition, StructFieldValue } from "../basic/index.js";
16
15
  import { SyncPromise } from "../sync-promise.js";
17
- import { type ValueOrPromise } from "../utils.js";
16
+ import type { ValueOrPromise } from "../utils.js";
18
17
 
19
18
  type DataViewBigInt64Getter = (
20
19
  dataView: DataView,
@@ -87,21 +86,21 @@ export class BigIntFieldDefinition<
87
86
 
88
87
  public override deserialize(
89
88
  options: Readonly<StructOptions>,
90
- stream: StructDeserializeStream,
89
+ stream: ExactReadable,
91
90
  struct: StructValue
92
91
  ): BigIntFieldValue<this>;
93
92
  public override deserialize(
94
93
  options: Readonly<StructOptions>,
95
- stream: StructAsyncDeserializeStream,
94
+ stream: AsyncExactReadable,
96
95
  struct: StructValue
97
96
  ): Promise<BigIntFieldValue<this>>;
98
97
  public override deserialize(
99
98
  options: Readonly<StructOptions>,
100
- stream: StructDeserializeStream | StructAsyncDeserializeStream,
99
+ stream: ExactReadable | AsyncExactReadable,
101
100
  struct: StructValue
102
101
  ): ValueOrPromise<BigIntFieldValue<this>> {
103
102
  return SyncPromise.try(() => {
104
- return stream.read(this.getSize());
103
+ return stream.readExactly(this.getSize());
105
104
  })
106
105
  .then((array) => {
107
106
  const view = new DataView(
@@ -1,13 +1,13 @@
1
- import {
2
- StructFieldDefinition,
3
- StructFieldValue,
4
- type StructAsyncDeserializeStream,
5
- type StructDeserializeStream,
6
- type StructOptions,
7
- type StructValue,
1
+ import type {
2
+ AsyncExactReadable,
3
+ ExactReadable,
4
+ StructOptions,
5
+ StructValue,
8
6
  } from "../../basic/index.js";
7
+ import { StructFieldDefinition, StructFieldValue } from "../../basic/index.js";
9
8
  import { SyncPromise } from "../../sync-promise.js";
10
- import { decodeUtf8, encodeUtf8, type ValueOrPromise } from "../../utils.js";
9
+ import type { ValueOrPromise } from "../../utils.js";
10
+ import { decodeUtf8, encodeUtf8 } from "../../utils.js";
11
11
 
12
12
  /**
13
13
  * Base class for all types that
@@ -127,17 +127,17 @@ export abstract class BufferLikeFieldDefinition<
127
127
 
128
128
  public override deserialize(
129
129
  options: Readonly<StructOptions>,
130
- stream: StructDeserializeStream,
130
+ stream: ExactReadable,
131
131
  struct: StructValue
132
132
  ): BufferLikeFieldValue<this>;
133
133
  public override deserialize(
134
134
  options: Readonly<StructOptions>,
135
- stream: StructAsyncDeserializeStream,
135
+ stream: AsyncExactReadable,
136
136
  struct: StructValue
137
137
  ): Promise<BufferLikeFieldValue<this>>;
138
138
  public override deserialize(
139
139
  options: Readonly<StructOptions>,
140
- stream: StructDeserializeStream | StructAsyncDeserializeStream,
140
+ stream: ExactReadable | AsyncExactReadable,
141
141
  struct: StructValue
142
142
  ): ValueOrPromise<BufferLikeFieldValue<this>> {
143
143
  return SyncPromise.try(() => {
@@ -145,7 +145,7 @@ export abstract class BufferLikeFieldDefinition<
145
145
  if (size === 0) {
146
146
  return EMPTY_UINT8_ARRAY;
147
147
  } else {
148
- return stream.read(size);
148
+ return stream.readExactly(size);
149
149
  }
150
150
  })
151
151
  .then((array) => {
@@ -1,4 +1,5 @@
1
- import { BufferLikeFieldDefinition, type BufferFieldSubType } from "./base.js";
1
+ import type { BufferFieldSubType } from "./base.js";
2
+ import { BufferLikeFieldDefinition } from "./base.js";
2
3
 
3
4
  export interface FixedLengthBufferLikeFieldOptions {
4
5
  length: number;
@@ -1,16 +1,13 @@
1
- import {
2
- StructFieldValue,
3
- type StructFieldDefinition,
4
- type StructOptions,
5
- type StructValue,
1
+ import type {
2
+ StructFieldDefinition,
3
+ StructOptions,
4
+ StructValue,
6
5
  } from "../../basic/index.js";
7
- import { type KeysOfType } from "../../utils.js";
6
+ import { StructFieldValue } from "../../basic/index.js";
7
+ import type { KeysOfType } from "../../utils.js";
8
8
 
9
- import {
10
- BufferLikeFieldDefinition,
11
- BufferLikeFieldValue,
12
- type BufferFieldSubType,
13
- } from "./base.js";
9
+ import type { BufferFieldSubType } from "./base.js";
10
+ import { BufferLikeFieldDefinition, BufferLikeFieldValue } from "./base.js";
14
11
 
15
12
  export type LengthField<TFields> = KeysOfType<TFields, number | string>;
16
13
 
@@ -1,13 +1,12 @@
1
- import {
2
- StructFieldDefinition,
3
- StructFieldValue,
4
- type StructAsyncDeserializeStream,
5
- type StructDeserializeStream,
6
- type StructOptions,
7
- type StructValue,
1
+ import type {
2
+ AsyncExactReadable,
3
+ ExactReadable,
4
+ StructOptions,
5
+ StructValue,
8
6
  } from "../basic/index.js";
7
+ import { StructFieldDefinition, StructFieldValue } from "../basic/index.js";
9
8
  import { SyncPromise } from "../sync-promise.js";
10
- import { type ValueOrPromise } from "../utils.js";
9
+ import type { ValueOrPromise } from "../utils.js";
11
10
 
12
11
  export interface NumberFieldType {
13
12
  signed: boolean;
@@ -50,15 +49,12 @@ export namespace NumberFieldType {
50
49
  signed: false,
51
50
  size: 2,
52
51
  deserialize(array, littleEndian) {
53
- // PERF: Chrome's `DataView#getUint16` uses inefficient operations,
54
- // including branching, bit extending and 32-bit bit swapping.
55
- // The best way should use 16-bit bit rotation and conditional move,
56
- // like LLVM does for code similar to the below one.
57
- // This code is much faster on V8, but the actual generated assembly is unknown.
58
- return (
59
- (((array[1]! << 8) | array[0]!) * (littleEndian as any)) |
60
- (((array[0]! << 8) | array[1]!) * (!littleEndian as any))
61
- );
52
+ // PERF: Creating many `DataView`s over small buffers is 90% slower
53
+ // than this. Even if the `DataView` is cached, `DataView#getUint16`
54
+ // is still 1% slower than this.
55
+ const a = (array[1]! << 8) | array[0]!;
56
+ const b = (array[0]! << 8) | array[1]!;
57
+ return littleEndian ? a : b;
62
58
  },
63
59
  serialize(dataView, offset, value, littleEndian) {
64
60
  dataView.setUint16(offset, value, littleEndian);
@@ -93,18 +89,17 @@ export namespace NumberFieldType {
93
89
  signed: true,
94
90
  size: 4,
95
91
  deserialize(array, littleEndian) {
96
- return (
97
- (((array[3]! << 24) |
98
- (array[2]! << 16) |
99
- (array[1]! << 8) |
100
- array[0]!) *
101
- (littleEndian as any)) |
102
- (((array[0]! << 24) |
103
- (array[1]! << 16) |
104
- (array[2]! << 8) |
105
- array[3]!) *
106
- (!littleEndian as any))
107
- );
92
+ const a =
93
+ (array[3]! << 24) |
94
+ (array[2]! << 16) |
95
+ (array[1]! << 8) |
96
+ array[0]!;
97
+ const b =
98
+ (array[0]! << 24) |
99
+ (array[1]! << 16) |
100
+ (array[2]! << 8) |
101
+ array[3]!;
102
+ return littleEndian ? a : b;
108
103
  },
109
104
  serialize(dataView, offset, value, littleEndian) {
110
105
  dataView.setInt32(offset, value, littleEndian);
@@ -138,21 +133,21 @@ export class NumberFieldDefinition<
138
133
 
139
134
  public override deserialize(
140
135
  options: Readonly<StructOptions>,
141
- stream: StructDeserializeStream,
136
+ stream: ExactReadable,
142
137
  struct: StructValue
143
138
  ): NumberFieldValue<this>;
144
139
  public override deserialize(
145
140
  options: Readonly<StructOptions>,
146
- stream: StructAsyncDeserializeStream,
141
+ stream: AsyncExactReadable,
147
142
  struct: StructValue
148
143
  ): Promise<NumberFieldValue<this>>;
149
144
  public override deserialize(
150
145
  options: Readonly<StructOptions>,
151
- stream: StructDeserializeStream | StructAsyncDeserializeStream,
146
+ stream: ExactReadable | AsyncExactReadable,
152
147
  struct: StructValue
153
148
  ): ValueOrPromise<NumberFieldValue<this>> {
154
149
  return SyncPromise.try(() => {
155
- return stream.read(this.getSize());
150
+ return stream.readExactly(this.getSize());
156
151
  })
157
152
  .then((array) => {
158
153
  const value = this.type.deserialize(