@yume-chan/struct 0.0.19 → 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.
- package/CHANGELOG.json +21 -0
- package/CHANGELOG.md +11 -1
- package/README.md +126 -143
- package/esm/basic/definition.d.ts +3 -3
- package/esm/basic/definition.d.ts.map +1 -1
- package/esm/basic/definition.js.map +1 -1
- package/esm/basic/stream.d.ts +11 -6
- package/esm/basic/stream.d.ts.map +1 -1
- package/esm/basic/stream.js +7 -1
- package/esm/basic/stream.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/struct.d.ts +19 -9
- package/esm/struct.d.ts.map +1 -1
- package/esm/struct.js +57 -25
- package/esm/struct.js.map +1 -1
- package/esm/sync-promise.js +12 -12
- package/esm/sync-promise.js.map +1 -1
- package/esm/types/bigint.d.ts +3 -3
- package/esm/types/bigint.d.ts.map +1 -1
- package/esm/types/bigint.js +1 -1
- package/esm/types/bigint.js.map +1 -1
- package/esm/types/buffer/base.d.ts +3 -3
- package/esm/types/buffer/base.d.ts.map +1 -1
- package/esm/types/buffer/base.js +1 -1
- package/esm/types/buffer/base.js.map +1 -1
- package/esm/types/number.d.ts +3 -3
- package/esm/types/number.d.ts.map +1 -1
- package/esm/types/number.js +14 -16
- package/esm/types/number.js.map +1 -1
- package/package.json +6 -6
- package/src/basic/definition.ts +3 -6
- package/src/basic/stream.ts +17 -6
- package/src/index.ts +1 -0
- package/src/struct.ts +79 -46
- package/src/sync-promise.ts +12 -12
- package/src/types/bigint.ts +6 -6
- package/src/types/buffer/base.ts +6 -6
- package/src/types/number.ts +23 -27
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/basic/definition.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { StructFieldValue } from "./field-value.js";
|
|
2
2
|
import type { StructOptions } from "./options.js";
|
|
3
|
-
import type {
|
|
4
|
-
StructAsyncDeserializeStream,
|
|
5
|
-
StructDeserializeStream,
|
|
6
|
-
} from "./stream.js";
|
|
3
|
+
import type { AsyncExactReadable, ExactReadable } from "./stream.js";
|
|
7
4
|
import type { StructValue } from "./struct-value.js";
|
|
8
5
|
|
|
9
6
|
/**
|
|
@@ -60,12 +57,12 @@ export abstract class StructFieldDefinition<
|
|
|
60
57
|
*/
|
|
61
58
|
public abstract deserialize(
|
|
62
59
|
options: Readonly<StructOptions>,
|
|
63
|
-
stream:
|
|
60
|
+
stream: ExactReadable,
|
|
64
61
|
structValue: StructValue
|
|
65
62
|
): StructFieldValue<this>;
|
|
66
63
|
public abstract deserialize(
|
|
67
64
|
options: Readonly<StructOptions>,
|
|
68
|
-
stream:
|
|
65
|
+
stream: AsyncExactReadable,
|
|
69
66
|
struct: StructValue
|
|
70
67
|
): Promise<StructFieldValue<this>>;
|
|
71
68
|
}
|
package/src/basic/stream.ts
CHANGED
|
@@ -2,22 +2,33 @@ import type { ValueOrPromise } from "../utils.js";
|
|
|
2
2
|
|
|
3
3
|
// TODO: allow over reading (returning a `Uint8Array`, an `offset` and a `length`) to avoid copying
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export class ExactReadableEndedError extends Error {
|
|
6
|
+
public constructor() {
|
|
7
|
+
super("ExactReadable ended");
|
|
8
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ExactReadable {
|
|
13
|
+
readonly position: number;
|
|
14
|
+
|
|
6
15
|
/**
|
|
7
16
|
* Read data from the underlying data source.
|
|
8
17
|
*
|
|
9
18
|
* The stream must return exactly `length` bytes or data. If that's not possible
|
|
10
|
-
* (due to end of file or other error condition), it must throw an
|
|
19
|
+
* (due to end of file or other error condition), it must throw an {@link ExactReadableEndedError}.
|
|
11
20
|
*/
|
|
12
|
-
|
|
21
|
+
readExactly(length: number): Uint8Array;
|
|
13
22
|
}
|
|
14
23
|
|
|
15
|
-
export interface
|
|
24
|
+
export interface AsyncExactReadable {
|
|
25
|
+
readonly position: number;
|
|
26
|
+
|
|
16
27
|
/**
|
|
17
28
|
* Read data from the underlying data source.
|
|
18
29
|
*
|
|
19
30
|
* The stream must return exactly `length` bytes or data. If that's not possible
|
|
20
|
-
* (due to end of file or other error condition), it must throw an
|
|
31
|
+
* (due to end of file or other error condition), it must throw an {@link ExactReadableEndedError}.
|
|
21
32
|
*/
|
|
22
|
-
|
|
33
|
+
readExactly(length: number): ValueOrPromise<Uint8Array>;
|
|
23
34
|
}
|
package/src/index.ts
CHANGED
package/src/struct.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
AsyncExactReadable,
|
|
3
|
+
ExactReadable,
|
|
4
4
|
StructFieldDefinition,
|
|
5
5
|
StructFieldValue,
|
|
6
6
|
StructOptions,
|
|
7
7
|
} from "./basic/index.js";
|
|
8
8
|
import {
|
|
9
|
+
ExactReadableEndedError,
|
|
9
10
|
STRUCT_VALUE_SYMBOL,
|
|
10
11
|
StructDefaultOptions,
|
|
11
12
|
StructValue,
|
|
@@ -30,9 +31,7 @@ import {
|
|
|
30
31
|
import type { Evaluate, Identity, Overwrite, ValueOrPromise } from "./utils.js";
|
|
31
32
|
|
|
32
33
|
export interface StructLike<TValue> {
|
|
33
|
-
deserialize(
|
|
34
|
-
stream: StructDeserializeStream | StructAsyncDeserializeStream
|
|
35
|
-
): Promise<TValue>;
|
|
34
|
+
deserialize(stream: ExactReadable | AsyncExactReadable): Promise<TValue>;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
/**
|
|
@@ -192,6 +191,27 @@ export type StructDeserializedResult<
|
|
|
192
191
|
? Overwrite<TExtra, TFields>
|
|
193
192
|
: TPostDeserialized;
|
|
194
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
|
+
|
|
195
215
|
export class Struct<
|
|
196
216
|
TFields extends object = Record<never, never>,
|
|
197
217
|
TOmitInitKey extends PropertyKey = never,
|
|
@@ -218,22 +238,28 @@ export class Struct<
|
|
|
218
238
|
|
|
219
239
|
public readonly options: Readonly<StructOptions>;
|
|
220
240
|
|
|
221
|
-
|
|
241
|
+
#size = 0;
|
|
222
242
|
/**
|
|
223
243
|
* Gets the static size (exclude fields that can change size at runtime)
|
|
224
244
|
*/
|
|
225
245
|
public get size() {
|
|
226
|
-
return this
|
|
246
|
+
return this.#size;
|
|
227
247
|
}
|
|
228
248
|
|
|
229
|
-
|
|
249
|
+
#fields: [
|
|
230
250
|
name: PropertyKey,
|
|
231
251
|
definition: StructFieldDefinition<any, any, any>
|
|
232
252
|
][] = [];
|
|
253
|
+
public get fields(): readonly [
|
|
254
|
+
name: PropertyKey,
|
|
255
|
+
definition: StructFieldDefinition<any, any, any>
|
|
256
|
+
][] {
|
|
257
|
+
return this.#fields;
|
|
258
|
+
}
|
|
233
259
|
|
|
234
|
-
|
|
260
|
+
#extra: Record<PropertyKey, unknown> = {};
|
|
235
261
|
|
|
236
|
-
|
|
262
|
+
#postDeserialized?: StructPostDeserialized<any, any> | undefined;
|
|
237
263
|
|
|
238
264
|
public constructor(options?: Partial<Readonly<StructOptions>>) {
|
|
239
265
|
this.options = { ...StructDefaultOptions, ...options };
|
|
@@ -256,20 +282,20 @@ export class Struct<
|
|
|
256
282
|
TName,
|
|
257
283
|
TDefinition
|
|
258
284
|
> {
|
|
259
|
-
for (const field of this
|
|
285
|
+
for (const field of this.#fields) {
|
|
260
286
|
if (field[0] === name) {
|
|
287
|
+
// Convert Symbol to string
|
|
288
|
+
const nameString = String(name);
|
|
261
289
|
throw new Error(
|
|
262
|
-
`This struct already have a field with name '${
|
|
263
|
-
name
|
|
264
|
-
)}'`
|
|
290
|
+
`This struct already have a field with name '${nameString}'`
|
|
265
291
|
);
|
|
266
292
|
}
|
|
267
293
|
}
|
|
268
294
|
|
|
269
|
-
this.
|
|
295
|
+
this.#fields.push([name, definition]);
|
|
270
296
|
|
|
271
297
|
const size = definition.getSize();
|
|
272
|
-
this
|
|
298
|
+
this.#size += size;
|
|
273
299
|
|
|
274
300
|
// Force cast `this` to another type
|
|
275
301
|
return this as any;
|
|
@@ -278,7 +304,7 @@ export class Struct<
|
|
|
278
304
|
/**
|
|
279
305
|
* Merges (flats) another `Struct`'s fields and extra fields into this one.
|
|
280
306
|
*/
|
|
281
|
-
public
|
|
307
|
+
public concat<TOther extends Struct<any, any, any, any>>(
|
|
282
308
|
other: TOther
|
|
283
309
|
): Struct<
|
|
284
310
|
TFields & TOther["TFields"],
|
|
@@ -286,13 +312,13 @@ export class Struct<
|
|
|
286
312
|
TExtra & TOther["TExtra"],
|
|
287
313
|
TPostDeserialized
|
|
288
314
|
> {
|
|
289
|
-
for (const field of other
|
|
290
|
-
this.
|
|
315
|
+
for (const field of other.#fields) {
|
|
316
|
+
this.#fields.push(field);
|
|
291
317
|
}
|
|
292
|
-
this
|
|
318
|
+
this.#size += other.#size;
|
|
293
319
|
Object.defineProperties(
|
|
294
|
-
this
|
|
295
|
-
Object.getOwnPropertyDescriptors(other
|
|
320
|
+
this.#extra,
|
|
321
|
+
Object.getOwnPropertyDescriptors(other.#extra)
|
|
296
322
|
);
|
|
297
323
|
return this as any;
|
|
298
324
|
}
|
|
@@ -478,7 +504,7 @@ export class Struct<
|
|
|
478
504
|
value: T & ThisType<Overwrite<Overwrite<TExtra, T>, TFields>>
|
|
479
505
|
): Struct<TFields, TOmitInitKey, Overwrite<TExtra, T>, TPostDeserialized> {
|
|
480
506
|
Object.defineProperties(
|
|
481
|
-
this
|
|
507
|
+
this.#extra,
|
|
482
508
|
Object.getOwnPropertyDescriptors(value)
|
|
483
509
|
);
|
|
484
510
|
return this as any;
|
|
@@ -512,7 +538,7 @@ export class Struct<
|
|
|
512
538
|
callback?: StructPostDeserialized<TFields, TPostSerialize>
|
|
513
539
|
): Struct<TFields, TOmitInitKey, TExtra, TPostSerialize>;
|
|
514
540
|
public postDeserialize(callback?: StructPostDeserialized<TFields, any>) {
|
|
515
|
-
this
|
|
541
|
+
this.#postDeserialized = callback;
|
|
516
542
|
return this as any;
|
|
517
543
|
}
|
|
518
544
|
|
|
@@ -520,44 +546,51 @@ export class Struct<
|
|
|
520
546
|
* Deserialize a struct value from `stream`.
|
|
521
547
|
*/
|
|
522
548
|
public deserialize(
|
|
523
|
-
stream:
|
|
549
|
+
stream: ExactReadable
|
|
524
550
|
): StructDeserializedResult<TFields, TExtra, TPostDeserialized>;
|
|
525
551
|
public deserialize(
|
|
526
|
-
stream:
|
|
552
|
+
stream: AsyncExactReadable
|
|
527
553
|
): Promise<StructDeserializedResult<TFields, TExtra, TPostDeserialized>>;
|
|
528
554
|
public deserialize(
|
|
529
|
-
stream:
|
|
555
|
+
stream: ExactReadable | AsyncExactReadable
|
|
530
556
|
): ValueOrPromise<
|
|
531
557
|
StructDeserializedResult<TFields, TExtra, TPostDeserialized>
|
|
532
558
|
> {
|
|
533
|
-
const structValue = new StructValue(this
|
|
559
|
+
const structValue = new StructValue(this.#extra);
|
|
534
560
|
|
|
535
561
|
let promise = SyncPromise.resolve();
|
|
536
562
|
|
|
537
|
-
|
|
563
|
+
const startPosition = stream.position;
|
|
564
|
+
for (const [name, definition] of this.#fields) {
|
|
538
565
|
promise = promise
|
|
539
566
|
.then(() =>
|
|
540
|
-
definition.deserialize(
|
|
541
|
-
this.options,
|
|
542
|
-
stream as any,
|
|
543
|
-
structValue
|
|
544
|
-
)
|
|
567
|
+
definition.deserialize(this.options, stream, structValue)
|
|
545
568
|
)
|
|
546
|
-
.then(
|
|
547
|
-
|
|
548
|
-
|
|
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
|
+
);
|
|
549
585
|
}
|
|
550
586
|
|
|
551
587
|
return promise
|
|
552
588
|
.then(() => {
|
|
553
|
-
const
|
|
589
|
+
const value = structValue.value;
|
|
554
590
|
|
|
555
591
|
// Run `postDeserialized`
|
|
556
|
-
if (this
|
|
557
|
-
const override = this.
|
|
558
|
-
object,
|
|
559
|
-
object
|
|
560
|
-
);
|
|
592
|
+
if (this.#postDeserialized) {
|
|
593
|
+
const override = this.#postDeserialized.call(value, value);
|
|
561
594
|
// If it returns a new value, use that as result
|
|
562
595
|
// Otherwise it only inspects/mutates the object in place.
|
|
563
596
|
if (override !== undefined) {
|
|
@@ -565,7 +598,7 @@ export class Struct<
|
|
|
565
598
|
}
|
|
566
599
|
}
|
|
567
600
|
|
|
568
|
-
return
|
|
601
|
+
return value;
|
|
569
602
|
})
|
|
570
603
|
.valueOrPromise();
|
|
571
604
|
}
|
|
@@ -590,7 +623,7 @@ export class Struct<
|
|
|
590
623
|
}
|
|
591
624
|
} else {
|
|
592
625
|
structValue = new StructValue({});
|
|
593
|
-
for (const [name, definition] of this
|
|
626
|
+
for (const [name, definition] of this.#fields) {
|
|
594
627
|
const fieldValue = definition.create(
|
|
595
628
|
this.options,
|
|
596
629
|
structValue,
|
|
@@ -603,7 +636,7 @@ export class Struct<
|
|
|
603
636
|
let structSize = 0;
|
|
604
637
|
const fieldsInfo: { fieldValue: StructFieldValue; size: number }[] = [];
|
|
605
638
|
|
|
606
|
-
for (const [name] of this
|
|
639
|
+
for (const [name] of this.#fields) {
|
|
607
640
|
const fieldValue = structValue.get(name);
|
|
608
641
|
const size = fieldValue.getSize();
|
|
609
642
|
fieldsInfo.push({ fieldValue, size });
|
package/src/sync-promise.ts
CHANGED
|
@@ -55,10 +55,10 @@ export const SyncPromise: SyncPromiseStatic = {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
class PendingSyncPromise<T> implements SyncPromise<T> {
|
|
58
|
-
|
|
58
|
+
#promise: PromiseLike<T>;
|
|
59
59
|
|
|
60
60
|
public constructor(promise: PromiseLike<T>) {
|
|
61
|
-
this
|
|
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
|
|
75
|
+
this.#promise.then(onfulfilled, onrejected)
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
public valueOrPromise(): T | PromiseLike<T> {
|
|
80
|
-
return this
|
|
80
|
+
return this.#promise;
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
class ResolvedSyncPromise<T> implements SyncPromise<T> {
|
|
85
|
-
|
|
85
|
+
#value: T;
|
|
86
86
|
|
|
87
87
|
public constructor(value: T) {
|
|
88
|
-
this
|
|
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
|
|
100
|
+
return SyncPromise.try(() => onfulfilled(this.#value));
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
public valueOrPromise(): T | PromiseLike<T> {
|
|
104
|
-
return this
|
|
104
|
+
return this.#value;
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
class RejectedSyncPromise<T> implements SyncPromise<T> {
|
|
109
|
-
|
|
109
|
+
#reason: any;
|
|
110
110
|
|
|
111
111
|
public constructor(reason: any) {
|
|
112
|
-
this
|
|
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
|
|
128
|
+
return SyncPromise.try(() => onrejected(this.#reason));
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
public valueOrPromise(): T | PromiseLike<T> {
|
|
132
|
-
throw this
|
|
132
|
+
throw this.#reason;
|
|
133
133
|
}
|
|
134
134
|
}
|
package/src/types/bigint.ts
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from "@yume-chan/dataview-bigint-polyfill/esm/fallback.js";
|
|
7
7
|
|
|
8
8
|
import type {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
AsyncExactReadable,
|
|
10
|
+
ExactReadable,
|
|
11
11
|
StructOptions,
|
|
12
12
|
StructValue,
|
|
13
13
|
} from "../basic/index.js";
|
|
@@ -86,21 +86,21 @@ export class BigIntFieldDefinition<
|
|
|
86
86
|
|
|
87
87
|
public override deserialize(
|
|
88
88
|
options: Readonly<StructOptions>,
|
|
89
|
-
stream:
|
|
89
|
+
stream: ExactReadable,
|
|
90
90
|
struct: StructValue
|
|
91
91
|
): BigIntFieldValue<this>;
|
|
92
92
|
public override deserialize(
|
|
93
93
|
options: Readonly<StructOptions>,
|
|
94
|
-
stream:
|
|
94
|
+
stream: AsyncExactReadable,
|
|
95
95
|
struct: StructValue
|
|
96
96
|
): Promise<BigIntFieldValue<this>>;
|
|
97
97
|
public override deserialize(
|
|
98
98
|
options: Readonly<StructOptions>,
|
|
99
|
-
stream:
|
|
99
|
+
stream: ExactReadable | AsyncExactReadable,
|
|
100
100
|
struct: StructValue
|
|
101
101
|
): ValueOrPromise<BigIntFieldValue<this>> {
|
|
102
102
|
return SyncPromise.try(() => {
|
|
103
|
-
return stream.
|
|
103
|
+
return stream.readExactly(this.getSize());
|
|
104
104
|
})
|
|
105
105
|
.then((array) => {
|
|
106
106
|
const view = new DataView(
|
package/src/types/buffer/base.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
AsyncExactReadable,
|
|
3
|
+
ExactReadable,
|
|
4
4
|
StructOptions,
|
|
5
5
|
StructValue,
|
|
6
6
|
} from "../../basic/index.js";
|
|
@@ -127,17 +127,17 @@ export abstract class BufferLikeFieldDefinition<
|
|
|
127
127
|
|
|
128
128
|
public override deserialize(
|
|
129
129
|
options: Readonly<StructOptions>,
|
|
130
|
-
stream:
|
|
130
|
+
stream: ExactReadable,
|
|
131
131
|
struct: StructValue
|
|
132
132
|
): BufferLikeFieldValue<this>;
|
|
133
133
|
public override deserialize(
|
|
134
134
|
options: Readonly<StructOptions>,
|
|
135
|
-
stream:
|
|
135
|
+
stream: AsyncExactReadable,
|
|
136
136
|
struct: StructValue
|
|
137
137
|
): Promise<BufferLikeFieldValue<this>>;
|
|
138
138
|
public override deserialize(
|
|
139
139
|
options: Readonly<StructOptions>,
|
|
140
|
-
stream:
|
|
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.
|
|
148
|
+
return stream.readExactly(size);
|
|
149
149
|
}
|
|
150
150
|
})
|
|
151
151
|
.then((array) => {
|
package/src/types/number.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
AsyncExactReadable,
|
|
3
|
+
ExactReadable,
|
|
4
4
|
StructOptions,
|
|
5
5
|
StructValue,
|
|
6
6
|
} from "../basic/index.js";
|
|
@@ -49,15 +49,12 @@ export namespace NumberFieldType {
|
|
|
49
49
|
signed: false,
|
|
50
50
|
size: 2,
|
|
51
51
|
deserialize(array, littleEndian) {
|
|
52
|
-
// PERF:
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return
|
|
58
|
-
(((array[1]! << 8) | array[0]!) * (littleEndian as any)) |
|
|
59
|
-
(((array[0]! << 8) | array[1]!) * (!littleEndian as any))
|
|
60
|
-
);
|
|
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;
|
|
61
58
|
},
|
|
62
59
|
serialize(dataView, offset, value, littleEndian) {
|
|
63
60
|
dataView.setUint16(offset, value, littleEndian);
|
|
@@ -92,18 +89,17 @@ export namespace NumberFieldType {
|
|
|
92
89
|
signed: true,
|
|
93
90
|
size: 4,
|
|
94
91
|
deserialize(array, littleEndian) {
|
|
95
|
-
|
|
96
|
-
(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
);
|
|
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;
|
|
107
103
|
},
|
|
108
104
|
serialize(dataView, offset, value, littleEndian) {
|
|
109
105
|
dataView.setInt32(offset, value, littleEndian);
|
|
@@ -137,21 +133,21 @@ export class NumberFieldDefinition<
|
|
|
137
133
|
|
|
138
134
|
public override deserialize(
|
|
139
135
|
options: Readonly<StructOptions>,
|
|
140
|
-
stream:
|
|
136
|
+
stream: ExactReadable,
|
|
141
137
|
struct: StructValue
|
|
142
138
|
): NumberFieldValue<this>;
|
|
143
139
|
public override deserialize(
|
|
144
140
|
options: Readonly<StructOptions>,
|
|
145
|
-
stream:
|
|
141
|
+
stream: AsyncExactReadable,
|
|
146
142
|
struct: StructValue
|
|
147
143
|
): Promise<NumberFieldValue<this>>;
|
|
148
144
|
public override deserialize(
|
|
149
145
|
options: Readonly<StructOptions>,
|
|
150
|
-
stream:
|
|
146
|
+
stream: ExactReadable | AsyncExactReadable,
|
|
151
147
|
struct: StructValue
|
|
152
148
|
): ValueOrPromise<NumberFieldValue<this>> {
|
|
153
149
|
return SyncPromise.try(() => {
|
|
154
|
-
return stream.
|
|
150
|
+
return stream.readExactly(this.getSize());
|
|
155
151
|
})
|
|
156
152
|
.then((array) => {
|
|
157
153
|
const value = this.type.deserialize(
|