@yume-chan/struct 0.0.22 → 0.0.24
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 +18 -0
- package/CHANGELOG.md +13 -1
- package/LICENSE +1 -1
- package/esm/basic/field-value.d.ts +2 -2
- package/esm/basic/field-value.d.ts.map +1 -1
- package/esm/basic/field-value.js.map +1 -1
- package/esm/basic/struct-value.d.ts +6 -2
- package/esm/basic/struct-value.d.ts.map +1 -1
- package/esm/basic/struct-value.js +5 -0
- package/esm/basic/struct-value.js.map +1 -1
- package/esm/struct.d.ts +27 -14
- package/esm/struct.d.ts.map +1 -1
- package/esm/struct.js +31 -18
- package/esm/struct.js.map +1 -1
- package/esm/sync-promise.d.ts +2 -2
- package/esm/sync-promise.d.ts.map +1 -1
- package/esm/sync-promise.js.map +1 -1
- package/esm/types/bigint.d.ts +13 -14
- package/esm/types/bigint.d.ts.map +1 -1
- package/esm/types/bigint.js +16 -17
- package/esm/types/bigint.js.map +1 -1
- package/esm/types/buffer/base.d.ts +31 -27
- package/esm/types/buffer/base.d.ts.map +1 -1
- package/esm/types/buffer/base.js +25 -26
- package/esm/types/buffer/base.js.map +1 -1
- package/esm/types/buffer/fixed-length.d.ts +2 -2
- package/esm/types/buffer/fixed-length.d.ts.map +1 -1
- package/esm/types/buffer/fixed-length.js.map +1 -1
- package/esm/types/buffer/variable-length.d.ts +10 -9
- package/esm/types/buffer/variable-length.d.ts.map +1 -1
- package/esm/types/buffer/variable-length.js +30 -19
- package/esm/types/buffer/variable-length.js.map +1 -1
- package/esm/types/number.d.ts +13 -13
- package/esm/types/number.d.ts.map +1 -1
- package/esm/types/number.js +22 -34
- package/esm/types/number.js.map +1 -1
- package/esm/utils.d.ts.map +1 -1
- package/esm/utils.js +6 -4
- package/esm/utils.js.map +1 -1
- package/package.json +9 -11
- package/src/basic/field-value.ts +7 -7
- package/src/basic/struct-value.ts +21 -3
- package/src/struct.ts +106 -65
- package/src/sync-promise.ts +9 -9
- package/src/types/bigint.ts +40 -37
- package/src/types/buffer/base.ts +48 -47
- package/src/types/buffer/fixed-length.ts +9 -4
- package/src/types/buffer/variable-length.ts +55 -31
- package/src/types/number.ts +32 -39
- package/src/utils.ts +6 -4
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/types/buffer/base.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import type {
|
|
2
3
|
AsyncExactReadable,
|
|
3
4
|
ExactReadable,
|
|
@@ -10,46 +11,49 @@ import type { ValueOrPromise } from "../../utils.js";
|
|
|
10
11
|
import { decodeUtf8, encodeUtf8 } from "../../utils.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* and
|
|
14
|
+
* A converter for buffer-like fields.
|
|
15
|
+
* It converts `Uint8Array`s to custom-typed values when deserializing,
|
|
16
|
+
* and convert values back to `Uint8Array`s when serializing.
|
|
16
17
|
*
|
|
17
|
-
* @template TValue The
|
|
18
|
-
* @template TTypeScriptType
|
|
19
|
-
*
|
|
18
|
+
* @template TValue The type of the value that the converter converts to/from `Uint8Array`.
|
|
19
|
+
* @template TTypeScriptType Optionally another type to refine `TValue`.
|
|
20
|
+
* For example, `TValue` is `string`, and `TTypeScriptType` is `"foo" | "bar"`.
|
|
21
|
+
* `TValue` is specified by the developer when creating an converter implementation,
|
|
22
|
+
* `TTypeScriptType` is specified by the user when creating a field.
|
|
20
23
|
*/
|
|
21
|
-
export abstract class
|
|
24
|
+
export abstract class BufferFieldConverter<
|
|
22
25
|
TValue = unknown,
|
|
23
26
|
TTypeScriptType = TValue,
|
|
24
27
|
> {
|
|
25
28
|
readonly TTypeScriptType!: TTypeScriptType;
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
|
-
* When implemented in derived classes, converts the
|
|
31
|
+
* When implemented in derived classes, converts the custom `value` to an `Uint8Array`
|
|
29
32
|
*
|
|
30
33
|
* This function should be "pure", i.e.,
|
|
31
34
|
* same `value` should always be converted to `Uint8Array`s that have same content.
|
|
32
35
|
*/
|
|
33
36
|
abstract toBuffer(value: TValue): Uint8Array;
|
|
34
37
|
|
|
35
|
-
/** When implemented in derived classes, converts the `Uint8Array` to a
|
|
38
|
+
/** When implemented in derived classes, converts the `Uint8Array` to a custom value */
|
|
36
39
|
abstract toValue(array: Uint8Array): TValue;
|
|
37
40
|
|
|
38
41
|
/**
|
|
39
|
-
* When implemented in derived classes, gets the size in byte of the
|
|
42
|
+
* When implemented in derived classes, gets the size in byte of the custom `value`.
|
|
40
43
|
*
|
|
41
|
-
* If the size can't be
|
|
42
|
-
* implementer
|
|
43
|
-
*
|
|
44
|
+
* If the size can't be determined without first converting the `value` back to an `Uint8Array`,
|
|
45
|
+
* the implementer should return `undefined`. In which case, the caller will call `toBuffer` to
|
|
46
|
+
* convert the value to a `Uint8Array`, then read the length of the `Uint8Array`. The caller can
|
|
47
|
+
* cache the result so the serialization process doesn't need to call `toBuffer` again.
|
|
44
48
|
*/
|
|
45
|
-
abstract getSize(value: TValue): number;
|
|
49
|
+
abstract getSize(value: TValue): number | undefined;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
/** An
|
|
49
|
-
export class
|
|
52
|
+
/** An identity converter, doesn't convert to anything else. */
|
|
53
|
+
export class Uint8ArrayBufferFieldConverter<
|
|
50
54
|
TTypeScriptType = Uint8Array,
|
|
51
|
-
> extends
|
|
52
|
-
static readonly Instance = new
|
|
55
|
+
> extends BufferFieldConverter<Uint8Array, TTypeScriptType> {
|
|
56
|
+
static readonly Instance = new Uint8ArrayBufferFieldConverter();
|
|
53
57
|
|
|
54
58
|
protected constructor() {
|
|
55
59
|
super();
|
|
@@ -64,15 +68,15 @@ export class Uint8ArrayBufferFieldSubType<
|
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
getSize(value: Uint8Array): number {
|
|
67
|
-
return value.
|
|
71
|
+
return value.length;
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
/** An `BufferFieldSubType` that converts between `Uint8Array` and `string` */
|
|
72
|
-
export class
|
|
76
|
+
export class StringBufferFieldConverter<
|
|
73
77
|
TTypeScriptType = string,
|
|
74
|
-
> extends
|
|
75
|
-
static readonly Instance = new
|
|
78
|
+
> extends BufferFieldConverter<string, TTypeScriptType> {
|
|
79
|
+
static readonly Instance = new StringBufferFieldConverter();
|
|
76
80
|
|
|
77
81
|
toBuffer(value: string): Uint8Array {
|
|
78
82
|
return encodeUtf8(value);
|
|
@@ -82,30 +86,29 @@ export class StringBufferFieldSubType<
|
|
|
82
86
|
return decodeUtf8(array);
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
getSize(): number {
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
// Then get the size from that `Uint8Array`
|
|
89
|
-
return -1;
|
|
89
|
+
getSize(): number | undefined {
|
|
90
|
+
// See the note in `BufferFieldConverter.getSize`
|
|
91
|
+
return undefined;
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
export const EMPTY_UINT8_ARRAY = new Uint8Array(0);
|
|
94
96
|
|
|
95
97
|
export abstract class BufferLikeFieldDefinition<
|
|
96
|
-
|
|
98
|
+
TConverter extends BufferFieldConverter<
|
|
97
99
|
unknown,
|
|
98
100
|
unknown
|
|
99
|
-
>,
|
|
101
|
+
> = BufferFieldConverter<unknown, unknown>,
|
|
100
102
|
TOptions = void,
|
|
101
103
|
TOmitInitKey extends PropertyKey = never,
|
|
102
|
-
TTypeScriptType =
|
|
104
|
+
TTypeScriptType = TConverter["TTypeScriptType"],
|
|
103
105
|
> extends StructFieldDefinition<TOptions, TTypeScriptType, TOmitInitKey> {
|
|
104
|
-
readonly
|
|
106
|
+
readonly converter: TConverter;
|
|
107
|
+
readonly TTypeScriptType!: TTypeScriptType;
|
|
105
108
|
|
|
106
|
-
constructor(
|
|
109
|
+
constructor(converter: TConverter, options: TOptions) {
|
|
107
110
|
super(options);
|
|
108
|
-
this.
|
|
111
|
+
this.converter = converter;
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
protected getDeserializeSize(struct: StructValue): number {
|
|
@@ -119,7 +122,7 @@ export abstract class BufferLikeFieldDefinition<
|
|
|
119
122
|
create(
|
|
120
123
|
options: Readonly<StructOptions>,
|
|
121
124
|
struct: StructValue,
|
|
122
|
-
value:
|
|
125
|
+
value: TTypeScriptType,
|
|
123
126
|
array?: Uint8Array,
|
|
124
127
|
): BufferLikeFieldValue<this> {
|
|
125
128
|
return new BufferLikeFieldValue(this, options, struct, value, array);
|
|
@@ -149,7 +152,7 @@ export abstract class BufferLikeFieldDefinition<
|
|
|
149
152
|
}
|
|
150
153
|
})
|
|
151
154
|
.then((array) => {
|
|
152
|
-
const value = this.
|
|
155
|
+
const value = this.converter.toValue(array) as TTypeScriptType;
|
|
153
156
|
return this.create(options, struct, value, array);
|
|
154
157
|
})
|
|
155
158
|
.valueOrPromise();
|
|
@@ -158,7 +161,8 @@ export abstract class BufferLikeFieldDefinition<
|
|
|
158
161
|
|
|
159
162
|
export class BufferLikeFieldValue<
|
|
160
163
|
TDefinition extends BufferLikeFieldDefinition<
|
|
161
|
-
|
|
164
|
+
BufferFieldConverter<unknown, unknown>,
|
|
165
|
+
any,
|
|
162
166
|
any,
|
|
163
167
|
any
|
|
164
168
|
>,
|
|
@@ -169,7 +173,7 @@ export class BufferLikeFieldValue<
|
|
|
169
173
|
definition: TDefinition,
|
|
170
174
|
options: Readonly<StructOptions>,
|
|
171
175
|
struct: StructValue,
|
|
172
|
-
value: TDefinition["
|
|
176
|
+
value: TDefinition["TTypeScriptType"],
|
|
173
177
|
array?: Uint8Array,
|
|
174
178
|
) {
|
|
175
179
|
super(definition, options, struct, value);
|
|
@@ -183,15 +187,12 @@ export class BufferLikeFieldValue<
|
|
|
183
187
|
this.array = undefined;
|
|
184
188
|
}
|
|
185
189
|
|
|
186
|
-
serialize(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
dataView.byteOffset,
|
|
194
|
-
dataView.byteLength,
|
|
195
|
-
).set(this.array, offset);
|
|
190
|
+
override serialize(
|
|
191
|
+
dataView: DataView,
|
|
192
|
+
array: Uint8Array,
|
|
193
|
+
offset: number,
|
|
194
|
+
): void {
|
|
195
|
+
this.array ??= this.definition.converter.toBuffer(this.value);
|
|
196
|
+
array.set(this.array, offset);
|
|
196
197
|
}
|
|
197
198
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BufferFieldConverter } from "./base.js";
|
|
2
2
|
import { BufferLikeFieldDefinition } from "./base.js";
|
|
3
3
|
|
|
4
4
|
export interface FixedLengthBufferLikeFieldOptions {
|
|
@@ -6,11 +6,16 @@ export interface FixedLengthBufferLikeFieldOptions {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export class FixedLengthBufferLikeFieldDefinition<
|
|
9
|
-
|
|
9
|
+
TConverter extends BufferFieldConverter = BufferFieldConverter,
|
|
10
10
|
TOptions extends
|
|
11
11
|
FixedLengthBufferLikeFieldOptions = FixedLengthBufferLikeFieldOptions,
|
|
12
|
-
TTypeScriptType =
|
|
13
|
-
> extends BufferLikeFieldDefinition<
|
|
12
|
+
TTypeScriptType = TConverter["TTypeScriptType"],
|
|
13
|
+
> extends BufferLikeFieldDefinition<
|
|
14
|
+
TConverter,
|
|
15
|
+
TOptions,
|
|
16
|
+
never,
|
|
17
|
+
TTypeScriptType
|
|
18
|
+
> {
|
|
14
19
|
getSize(): number {
|
|
15
20
|
return this.options.length;
|
|
16
21
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
|
|
1
4
|
import type {
|
|
2
5
|
StructFieldDefinition,
|
|
3
6
|
StructOptions,
|
|
@@ -6,13 +9,13 @@ import type {
|
|
|
6
9
|
import { StructFieldValue } from "../../basic/index.js";
|
|
7
10
|
import type { KeysOfType } from "../../utils.js";
|
|
8
11
|
|
|
9
|
-
import type {
|
|
12
|
+
import type { BufferFieldConverter } from "./base.js";
|
|
10
13
|
import { BufferLikeFieldDefinition, BufferLikeFieldValue } from "./base.js";
|
|
11
14
|
|
|
12
15
|
export type LengthField<TFields> = KeysOfType<TFields, number | string>;
|
|
13
16
|
|
|
14
17
|
export interface VariableLengthBufferLikeFieldOptions<
|
|
15
|
-
TFields = object,
|
|
18
|
+
TFields extends object = object,
|
|
16
19
|
TLengthField extends LengthField<TFields> = any,
|
|
17
20
|
> {
|
|
18
21
|
/**
|
|
@@ -32,12 +35,12 @@ export interface VariableLengthBufferLikeFieldOptions<
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
export class VariableLengthBufferLikeFieldDefinition<
|
|
35
|
-
|
|
38
|
+
TConverter extends BufferFieldConverter = BufferFieldConverter,
|
|
36
39
|
TOptions extends
|
|
37
40
|
VariableLengthBufferLikeFieldOptions = VariableLengthBufferLikeFieldOptions,
|
|
38
|
-
TTypeScriptType =
|
|
41
|
+
TTypeScriptType = TConverter["TTypeScriptType"],
|
|
39
42
|
> extends BufferLikeFieldDefinition<
|
|
40
|
-
|
|
43
|
+
TConverter,
|
|
41
44
|
TOptions,
|
|
42
45
|
TOptions["lengthField"],
|
|
43
46
|
TTypeScriptType
|
|
@@ -88,11 +91,11 @@ export class VariableLengthBufferLikeStructFieldValue<
|
|
|
88
91
|
super(definition, options, struct, value, array);
|
|
89
92
|
|
|
90
93
|
if (array) {
|
|
91
|
-
this.length = array.
|
|
94
|
+
this.length = array.length;
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
// Patch the associated length field.
|
|
95
|
-
const lengthField = this.definition.options.lengthField;
|
|
98
|
+
const lengthField = this.definition.options.lengthField as PropertyKey;
|
|
96
99
|
|
|
97
100
|
const originalValue = struct.get(lengthField);
|
|
98
101
|
this.lengthFieldValue = new VariableLengthBufferLikeFieldLengthValue(
|
|
@@ -102,13 +105,24 @@ export class VariableLengthBufferLikeStructFieldValue<
|
|
|
102
105
|
struct.set(lengthField, this.lengthFieldValue);
|
|
103
106
|
}
|
|
104
107
|
|
|
105
|
-
|
|
108
|
+
#tryGetSize() {
|
|
109
|
+
const length = this.definition.converter.getSize(this.value);
|
|
110
|
+
if (length !== undefined && length < 0) {
|
|
111
|
+
throw new Error("Invalid length");
|
|
112
|
+
}
|
|
113
|
+
return length;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override getSize(): number {
|
|
106
117
|
if (this.length === undefined) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
// first try to get the size from the converter
|
|
119
|
+
this.length = this.#tryGetSize();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (this.length === undefined) {
|
|
123
|
+
// The converter doesn't know the size, so convert the value to a buffer to get its size
|
|
124
|
+
this.array = this.definition.converter.toBuffer(this.value);
|
|
125
|
+
this.length = this.array.length;
|
|
112
126
|
}
|
|
113
127
|
|
|
114
128
|
return this.length;
|
|
@@ -123,39 +137,49 @@ export class VariableLengthBufferLikeStructFieldValue<
|
|
|
123
137
|
|
|
124
138
|
// Not using `VariableLengthBufferLikeStructFieldValue` directly makes writing tests much easier...
|
|
125
139
|
type VariableLengthBufferLikeFieldValueLike = StructFieldValue<
|
|
126
|
-
StructFieldDefinition<
|
|
140
|
+
StructFieldDefinition<
|
|
141
|
+
VariableLengthBufferLikeFieldOptions<any, any>,
|
|
142
|
+
any,
|
|
143
|
+
any
|
|
144
|
+
>
|
|
127
145
|
>;
|
|
128
146
|
|
|
129
|
-
export class VariableLengthBufferLikeFieldLengthValue extends StructFieldValue
|
|
130
|
-
|
|
147
|
+
export class VariableLengthBufferLikeFieldLengthValue extends StructFieldValue<
|
|
148
|
+
StructFieldDefinition<unknown, unknown, PropertyKey>
|
|
149
|
+
> {
|
|
150
|
+
protected originalValue: StructFieldValue<
|
|
151
|
+
StructFieldDefinition<unknown, unknown, PropertyKey>
|
|
152
|
+
>;
|
|
131
153
|
|
|
132
|
-
protected
|
|
154
|
+
protected bufferValue: VariableLengthBufferLikeFieldValueLike;
|
|
133
155
|
|
|
134
156
|
constructor(
|
|
135
|
-
|
|
136
|
-
|
|
157
|
+
originalValue: StructFieldValue<
|
|
158
|
+
StructFieldDefinition<unknown, unknown, PropertyKey>
|
|
159
|
+
>,
|
|
160
|
+
bufferValue: VariableLengthBufferLikeFieldValueLike,
|
|
137
161
|
) {
|
|
138
162
|
super(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
163
|
+
originalValue.definition,
|
|
164
|
+
originalValue.options,
|
|
165
|
+
originalValue.struct,
|
|
142
166
|
0,
|
|
143
167
|
);
|
|
144
|
-
this.
|
|
145
|
-
this.
|
|
168
|
+
this.originalValue = originalValue;
|
|
169
|
+
this.bufferValue = bufferValue;
|
|
146
170
|
}
|
|
147
171
|
|
|
148
172
|
override getSize() {
|
|
149
|
-
return this.
|
|
173
|
+
return this.originalValue.getSize();
|
|
150
174
|
}
|
|
151
175
|
|
|
152
176
|
override get() {
|
|
153
|
-
let value: string | number = this.
|
|
177
|
+
let value: string | number = this.bufferValue.getSize();
|
|
154
178
|
|
|
155
|
-
const originalValue = this.
|
|
179
|
+
const originalValue = this.originalValue.get();
|
|
156
180
|
if (typeof originalValue === "string") {
|
|
157
181
|
value = value.toString(
|
|
158
|
-
this.
|
|
182
|
+
this.bufferValue.definition.options.lengthFieldRadix ?? 10,
|
|
159
183
|
);
|
|
160
184
|
}
|
|
161
185
|
|
|
@@ -167,8 +191,8 @@ export class VariableLengthBufferLikeFieldLengthValue extends StructFieldValue {
|
|
|
167
191
|
// It will always be in sync with the buffer size
|
|
168
192
|
}
|
|
169
193
|
|
|
170
|
-
serialize(dataView: DataView, offset: number) {
|
|
171
|
-
this.
|
|
172
|
-
this.
|
|
194
|
+
serialize(dataView: DataView, array: Uint8Array, offset: number) {
|
|
195
|
+
this.originalValue.set(this.get());
|
|
196
|
+
this.originalValue.serialize(dataView, array, offset);
|
|
173
197
|
}
|
|
174
198
|
}
|
package/src/types/number.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getInt16,
|
|
3
|
+
getInt32,
|
|
4
|
+
getInt8,
|
|
5
|
+
getUint16,
|
|
6
|
+
getUint32,
|
|
7
|
+
} from "@yume-chan/no-data-view";
|
|
8
|
+
|
|
1
9
|
import type {
|
|
2
10
|
AsyncExactReadable,
|
|
3
11
|
ExactReadable,
|
|
@@ -8,7 +16,7 @@ import { StructFieldDefinition, StructFieldValue } from "../basic/index.js";
|
|
|
8
16
|
import { SyncPromise } from "../sync-promise.js";
|
|
9
17
|
import type { ValueOrPromise } from "../utils.js";
|
|
10
18
|
|
|
11
|
-
export interface
|
|
19
|
+
export interface NumberFieldVariant {
|
|
12
20
|
signed: boolean;
|
|
13
21
|
size: number;
|
|
14
22
|
deserialize(array: Uint8Array, littleEndian: boolean): number;
|
|
@@ -20,8 +28,8 @@ export interface NumberFieldType {
|
|
|
20
28
|
): void;
|
|
21
29
|
}
|
|
22
30
|
|
|
23
|
-
export namespace
|
|
24
|
-
export const Uint8:
|
|
31
|
+
export namespace NumberFieldVariant {
|
|
32
|
+
export const Uint8: NumberFieldVariant = {
|
|
25
33
|
signed: false,
|
|
26
34
|
size: 1,
|
|
27
35
|
deserialize(array) {
|
|
@@ -32,73 +40,58 @@ export namespace NumberFieldType {
|
|
|
32
40
|
},
|
|
33
41
|
};
|
|
34
42
|
|
|
35
|
-
export const Int8:
|
|
43
|
+
export const Int8: NumberFieldVariant = {
|
|
36
44
|
signed: true,
|
|
37
45
|
size: 1,
|
|
38
46
|
deserialize(array) {
|
|
39
|
-
|
|
40
|
-
return (value << 24) >> 24;
|
|
47
|
+
return getInt8(array, 0);
|
|
41
48
|
},
|
|
42
49
|
serialize(dataView, offset, value) {
|
|
43
50
|
dataView.setInt8(offset, value);
|
|
44
51
|
},
|
|
45
52
|
};
|
|
46
53
|
|
|
47
|
-
export const Uint16:
|
|
54
|
+
export const Uint16: NumberFieldVariant = {
|
|
48
55
|
signed: false,
|
|
49
56
|
size: 2,
|
|
50
57
|
deserialize(array, littleEndian) {
|
|
51
58
|
// PERF: Creating many `DataView`s over small buffers is 90% slower
|
|
52
59
|
// than this. Even if the `DataView` is cached, `DataView#getUint16`
|
|
53
60
|
// is still 1% slower than this.
|
|
54
|
-
|
|
55
|
-
const b = (array[0]! << 8) | array[1]!;
|
|
56
|
-
return littleEndian ? a : b;
|
|
61
|
+
return getUint16(array, 0, littleEndian);
|
|
57
62
|
},
|
|
58
63
|
serialize(dataView, offset, value, littleEndian) {
|
|
59
64
|
dataView.setUint16(offset, value, littleEndian);
|
|
60
65
|
},
|
|
61
66
|
};
|
|
62
67
|
|
|
63
|
-
export const Int16:
|
|
68
|
+
export const Int16: NumberFieldVariant = {
|
|
64
69
|
signed: true,
|
|
65
70
|
size: 2,
|
|
66
71
|
deserialize(array, littleEndian) {
|
|
67
|
-
|
|
68
|
-
return (value << 16) >> 16;
|
|
72
|
+
return getInt16(array, 0, littleEndian);
|
|
69
73
|
},
|
|
70
74
|
serialize(dataView, offset, value, littleEndian) {
|
|
71
75
|
dataView.setInt16(offset, value, littleEndian);
|
|
72
76
|
},
|
|
73
77
|
};
|
|
74
78
|
|
|
75
|
-
export const Uint32:
|
|
79
|
+
export const Uint32: NumberFieldVariant = {
|
|
76
80
|
signed: false,
|
|
77
81
|
size: 4,
|
|
78
82
|
deserialize(array, littleEndian) {
|
|
79
|
-
|
|
80
|
-
return value >>> 0;
|
|
83
|
+
return getUint32(array, 0, littleEndian);
|
|
81
84
|
},
|
|
82
85
|
serialize(dataView, offset, value, littleEndian) {
|
|
83
86
|
dataView.setUint32(offset, value, littleEndian);
|
|
84
87
|
},
|
|
85
88
|
};
|
|
86
89
|
|
|
87
|
-
export const Int32:
|
|
90
|
+
export const Int32: NumberFieldVariant = {
|
|
88
91
|
signed: true,
|
|
89
92
|
size: 4,
|
|
90
93
|
deserialize(array, littleEndian) {
|
|
91
|
-
|
|
92
|
-
(array[3]! << 24) |
|
|
93
|
-
(array[2]! << 16) |
|
|
94
|
-
(array[1]! << 8) |
|
|
95
|
-
array[0]!;
|
|
96
|
-
const b =
|
|
97
|
-
(array[0]! << 24) |
|
|
98
|
-
(array[1]! << 16) |
|
|
99
|
-
(array[2]! << 8) |
|
|
100
|
-
array[3]!;
|
|
101
|
-
return littleEndian ? a : b;
|
|
94
|
+
return getInt32(array, 0, littleEndian);
|
|
102
95
|
},
|
|
103
96
|
serialize(dataView, offset, value, littleEndian) {
|
|
104
97
|
dataView.setInt32(offset, value, littleEndian);
|
|
@@ -107,19 +100,19 @@ export namespace NumberFieldType {
|
|
|
107
100
|
}
|
|
108
101
|
|
|
109
102
|
export class NumberFieldDefinition<
|
|
110
|
-
|
|
103
|
+
TVariant extends NumberFieldVariant = NumberFieldVariant,
|
|
111
104
|
TTypeScriptType = number,
|
|
112
105
|
> extends StructFieldDefinition<void, TTypeScriptType> {
|
|
113
|
-
readonly
|
|
106
|
+
readonly variant: TVariant;
|
|
114
107
|
|
|
115
|
-
constructor(
|
|
108
|
+
constructor(variant: TVariant, typescriptType?: TTypeScriptType) {
|
|
116
109
|
void typescriptType;
|
|
117
110
|
super();
|
|
118
|
-
this.
|
|
111
|
+
this.variant = variant;
|
|
119
112
|
}
|
|
120
113
|
|
|
121
114
|
getSize(): number {
|
|
122
|
-
return this.
|
|
115
|
+
return this.variant.size;
|
|
123
116
|
}
|
|
124
117
|
|
|
125
118
|
create(
|
|
@@ -149,24 +142,24 @@ export class NumberFieldDefinition<
|
|
|
149
142
|
return stream.readExactly(this.getSize());
|
|
150
143
|
})
|
|
151
144
|
.then((array) => {
|
|
152
|
-
const value = this.
|
|
145
|
+
const value = this.variant.deserialize(
|
|
153
146
|
array,
|
|
154
147
|
options.littleEndian,
|
|
155
148
|
);
|
|
156
|
-
return this.create(options, struct, value as
|
|
149
|
+
return this.create(options, struct, value as never);
|
|
157
150
|
})
|
|
158
151
|
.valueOrPromise();
|
|
159
152
|
}
|
|
160
153
|
}
|
|
161
154
|
|
|
162
155
|
export class NumberFieldValue<
|
|
163
|
-
TDefinition extends NumberFieldDefinition<
|
|
156
|
+
TDefinition extends NumberFieldDefinition<NumberFieldVariant, unknown>,
|
|
164
157
|
> extends StructFieldValue<TDefinition> {
|
|
165
|
-
serialize(dataView: DataView, offset: number): void {
|
|
166
|
-
this.definition.
|
|
158
|
+
serialize(dataView: DataView, array: Uint8Array, offset: number): void {
|
|
159
|
+
this.definition.variant.serialize(
|
|
167
160
|
dataView,
|
|
168
161
|
offset,
|
|
169
|
-
this.value,
|
|
162
|
+
this.value as never,
|
|
170
163
|
this.options.littleEndian,
|
|
171
164
|
);
|
|
172
165
|
}
|
package/src/utils.ts
CHANGED
|
@@ -80,13 +80,15 @@ interface GlobalExtension {
|
|
|
80
80
|
|
|
81
81
|
const { TextEncoder, TextDecoder } = globalThis as unknown as GlobalExtension;
|
|
82
82
|
|
|
83
|
-
const
|
|
84
|
-
const
|
|
83
|
+
const SharedEncoder = new TextEncoder();
|
|
84
|
+
const SharedDecoder = new TextDecoder();
|
|
85
85
|
|
|
86
86
|
export function encodeUtf8(input: string): Uint8Array {
|
|
87
|
-
return
|
|
87
|
+
return SharedEncoder.encode(input);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export function decodeUtf8(buffer: ArrayBufferView | ArrayBuffer): string {
|
|
91
|
-
|
|
91
|
+
// `TextDecoder` has internal states in stream mode,
|
|
92
|
+
// but this method is not for stream mode, so the instance can be reused
|
|
93
|
+
return SharedDecoder.decode(buffer);
|
|
92
94
|
}
|