@yume-chan/struct 0.0.23 → 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 +12 -0
- package/CHANGELOG.md +8 -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 +8 -10
- 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/sync-promise.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface SyncPromise<T> {
|
|
|
5
5
|
| null
|
|
6
6
|
| undefined,
|
|
7
7
|
onrejected?:
|
|
8
|
-
| ((reason:
|
|
8
|
+
| ((reason: unknown) => TResult2 | PromiseLike<TResult2>)
|
|
9
9
|
| null
|
|
10
10
|
| undefined,
|
|
11
11
|
): SyncPromise<TResult1 | TResult2>;
|
|
@@ -14,7 +14,7 @@ export interface SyncPromise<T> {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
interface SyncPromiseStatic {
|
|
17
|
-
reject<T = never>(reason?:
|
|
17
|
+
reject<T = never>(reason?: unknown): SyncPromise<T>;
|
|
18
18
|
|
|
19
19
|
resolve(): SyncPromise<void>;
|
|
20
20
|
resolve<T>(value: T | PromiseLike<T>): SyncPromise<T>;
|
|
@@ -23,7 +23,7 @@ interface SyncPromiseStatic {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export const SyncPromise: SyncPromiseStatic = {
|
|
26
|
-
reject<T = never>(reason?:
|
|
26
|
+
reject<T = never>(reason?: unknown): SyncPromise<T> {
|
|
27
27
|
return new RejectedSyncPromise(reason);
|
|
28
28
|
},
|
|
29
29
|
resolve<T>(value?: T | PromiseLike<T>): SyncPromise<T> {
|
|
@@ -67,7 +67,7 @@ class PendingSyncPromise<T> implements SyncPromise<T> {
|
|
|
67
67
|
| null
|
|
68
68
|
| undefined,
|
|
69
69
|
onrejected?:
|
|
70
|
-
| ((reason:
|
|
70
|
+
| ((reason: unknown) => TResult2 | PromiseLike<TResult2>)
|
|
71
71
|
| null
|
|
72
72
|
| undefined,
|
|
73
73
|
) {
|
|
@@ -95,7 +95,7 @@ class ResolvedSyncPromise<T> implements SyncPromise<T> {
|
|
|
95
95
|
| undefined,
|
|
96
96
|
) {
|
|
97
97
|
if (!onfulfilled) {
|
|
98
|
-
return this as
|
|
98
|
+
return this as never;
|
|
99
99
|
}
|
|
100
100
|
return SyncPromise.try(() => onfulfilled(this.#value));
|
|
101
101
|
}
|
|
@@ -106,9 +106,9 @@ class ResolvedSyncPromise<T> implements SyncPromise<T> {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
class RejectedSyncPromise<T> implements SyncPromise<T> {
|
|
109
|
-
#reason:
|
|
109
|
+
#reason: unknown;
|
|
110
110
|
|
|
111
|
-
constructor(reason:
|
|
111
|
+
constructor(reason: unknown) {
|
|
112
112
|
this.#reason = reason;
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -118,12 +118,12 @@ class RejectedSyncPromise<T> implements SyncPromise<T> {
|
|
|
118
118
|
| null
|
|
119
119
|
| undefined,
|
|
120
120
|
onrejected?:
|
|
121
|
-
| ((reason:
|
|
121
|
+
| ((reason: unknown) => TResult2 | PromiseLike<TResult2>)
|
|
122
122
|
| null
|
|
123
123
|
| undefined,
|
|
124
124
|
) {
|
|
125
125
|
if (!onrejected) {
|
|
126
|
-
return this as
|
|
126
|
+
return this as never;
|
|
127
127
|
}
|
|
128
128
|
return SyncPromise.try(() => onrejected(this.#reason));
|
|
129
129
|
}
|
package/src/types/bigint.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from "@yume-chan/
|
|
2
|
+
getInt64,
|
|
3
|
+
getUint64,
|
|
4
|
+
setInt64,
|
|
5
|
+
setUint64,
|
|
6
|
+
} from "@yume-chan/no-data-view";
|
|
7
7
|
|
|
8
8
|
import type {
|
|
9
9
|
AsyncExactReadable,
|
|
@@ -15,57 +15,57 @@ import { StructFieldDefinition, StructFieldValue } from "../basic/index.js";
|
|
|
15
15
|
import { SyncPromise } from "../sync-promise.js";
|
|
16
16
|
import type { ValueOrPromise } from "../utils.js";
|
|
17
17
|
|
|
18
|
-
type
|
|
19
|
-
|
|
18
|
+
export type BigIntDeserializer = (
|
|
19
|
+
array: Uint8Array,
|
|
20
20
|
byteOffset: number,
|
|
21
|
-
littleEndian: boolean
|
|
21
|
+
littleEndian: boolean,
|
|
22
22
|
) => bigint;
|
|
23
23
|
|
|
24
|
-
type
|
|
25
|
-
|
|
24
|
+
export type BigIntSerializer = (
|
|
25
|
+
array: Uint8Array,
|
|
26
26
|
byteOffset: number,
|
|
27
27
|
value: bigint,
|
|
28
|
-
littleEndian: boolean
|
|
28
|
+
littleEndian: boolean,
|
|
29
29
|
) => void;
|
|
30
30
|
|
|
31
|
-
export class
|
|
31
|
+
export class BigIntFieldVariant {
|
|
32
32
|
readonly TTypeScriptType!: bigint;
|
|
33
33
|
|
|
34
34
|
readonly size: number;
|
|
35
35
|
|
|
36
|
-
readonly
|
|
36
|
+
readonly deserialize: BigIntDeserializer;
|
|
37
37
|
|
|
38
|
-
readonly
|
|
38
|
+
readonly serialize: BigIntSerializer;
|
|
39
39
|
|
|
40
40
|
constructor(
|
|
41
41
|
size: number,
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
deserialize: BigIntDeserializer,
|
|
43
|
+
serialize: BigIntSerializer,
|
|
44
44
|
) {
|
|
45
45
|
this.size = size;
|
|
46
|
-
this.
|
|
47
|
-
this.
|
|
46
|
+
this.deserialize = deserialize;
|
|
47
|
+
this.serialize = serialize;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
static readonly Int64 = new
|
|
50
|
+
static readonly Int64 = new BigIntFieldVariant(8, getInt64, setInt64);
|
|
51
51
|
|
|
52
|
-
static readonly Uint64 = new
|
|
52
|
+
static readonly Uint64 = new BigIntFieldVariant(8, getUint64, setUint64);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export class BigIntFieldDefinition<
|
|
56
|
-
|
|
57
|
-
TTypeScriptType =
|
|
56
|
+
TVariant extends BigIntFieldVariant = BigIntFieldVariant,
|
|
57
|
+
TTypeScriptType = TVariant["TTypeScriptType"],
|
|
58
58
|
> extends StructFieldDefinition<void, TTypeScriptType> {
|
|
59
|
-
readonly
|
|
59
|
+
readonly variant: TVariant;
|
|
60
60
|
|
|
61
|
-
constructor(
|
|
61
|
+
constructor(variant: TVariant, typescriptType?: TTypeScriptType) {
|
|
62
62
|
void typescriptType;
|
|
63
63
|
super();
|
|
64
|
-
this.
|
|
64
|
+
this.variant = variant;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
getSize(): number {
|
|
68
|
-
return this.
|
|
68
|
+
return this.variant.size;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
create(
|
|
@@ -95,26 +95,29 @@ export class BigIntFieldDefinition<
|
|
|
95
95
|
return stream.readExactly(this.getSize());
|
|
96
96
|
})
|
|
97
97
|
.then((array) => {
|
|
98
|
-
const
|
|
99
|
-
array
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
const value = this.variant.deserialize(
|
|
99
|
+
array,
|
|
100
|
+
0,
|
|
101
|
+
options.littleEndian,
|
|
102
102
|
);
|
|
103
|
-
|
|
104
|
-
return this.create(options, struct, value as any);
|
|
103
|
+
return this.create(options, struct, value as never);
|
|
105
104
|
})
|
|
106
105
|
.valueOrPromise();
|
|
107
106
|
}
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
export class BigIntFieldValue<
|
|
111
|
-
TDefinition extends BigIntFieldDefinition<
|
|
110
|
+
TDefinition extends BigIntFieldDefinition<BigIntFieldVariant, unknown>,
|
|
112
111
|
> extends StructFieldValue<TDefinition> {
|
|
113
|
-
serialize(
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
override serialize(
|
|
113
|
+
dataView: DataView,
|
|
114
|
+
array: Uint8Array,
|
|
115
|
+
offset: number,
|
|
116
|
+
): void {
|
|
117
|
+
this.definition.variant.serialize(
|
|
118
|
+
array,
|
|
116
119
|
offset,
|
|
117
|
-
this.value,
|
|
120
|
+
this.value as never,
|
|
118
121
|
this.options.littleEndian,
|
|
119
122
|
);
|
|
120
123
|
}
|
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
|
}
|