@yume-chan/struct 0.0.24 → 2.0.0
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.md +40 -1
- package/LICENSE +1 -1
- package/README.md +85 -714
- package/esm/bipedal.d.ts +6 -0
- package/esm/bipedal.d.ts.map +1 -0
- package/esm/bipedal.js +38 -0
- package/esm/bipedal.js.map +1 -0
- package/esm/buffer.d.ts +30 -0
- package/esm/buffer.d.ts.map +1 -0
- package/esm/buffer.js +170 -0
- package/esm/buffer.js.map +1 -0
- package/esm/concat.d.ts +13 -0
- package/esm/concat.d.ts.map +1 -0
- package/esm/concat.js +10 -0
- package/esm/concat.js.map +1 -0
- package/esm/extend.d.ts +6 -0
- package/esm/extend.d.ts.map +1 -0
- package/esm/extend.js +10 -0
- package/esm/extend.js.map +1 -0
- package/esm/field/factory.d.ts +13 -0
- package/esm/field/factory.d.ts.map +1 -0
- package/esm/field/factory.js +21 -0
- package/esm/field/factory.js.map +1 -0
- package/esm/field/index.d.ts +4 -0
- package/esm/field/index.d.ts.map +1 -0
- package/esm/field/index.js +4 -0
- package/esm/field/index.js.map +1 -0
- package/esm/field/serialize.d.ts +8 -0
- package/esm/field/serialize.d.ts.map +1 -0
- package/esm/field/serialize.js +33 -0
- package/esm/field/serialize.js.map +1 -0
- package/esm/field/types.d.ts +33 -0
- package/esm/field/types.d.ts.map +1 -0
- package/esm/field/types.js +2 -0
- package/esm/field/types.js.map +1 -0
- package/esm/index.d.ts +9 -4
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -4
- package/esm/index.js.map +1 -1
- package/esm/number.d.ts +13 -0
- package/esm/number.d.ts.map +1 -0
- package/esm/number.js +57 -0
- package/esm/number.js.map +1 -0
- package/esm/{basic/stream.d.ts → readable.d.ts} +9 -3
- package/esm/readable.d.ts.map +1 -0
- package/esm/readable.js +26 -0
- package/esm/readable.js.map +1 -0
- package/esm/string.d.ts +16 -0
- package/esm/string.d.ts.map +1 -0
- package/esm/string.js +13 -0
- package/esm/string.js.map +1 -0
- package/esm/struct.d.ts +22 -140
- package/esm/struct.d.ts.map +1 -1
- package/esm/struct.js +109 -227
- package/esm/struct.js.map +1 -1
- package/esm/types.d.ts +20 -0
- package/esm/types.d.ts.map +1 -0
- package/esm/types.js +2 -0
- package/esm/types.js.map +1 -0
- package/esm/utils.d.ts +10 -45
- package/esm/utils.d.ts.map +1 -1
- package/esm/utils.js +8 -9
- package/esm/utils.js.map +1 -1
- package/package.json +11 -12
- package/src/bipedal.ts +65 -0
- package/src/buffer.ts +334 -0
- package/src/concat.ts +78 -0
- package/src/extend.ts +37 -0
- package/src/field/factory.ts +64 -0
- package/src/field/index.ts +3 -0
- package/src/field/serialize.ts +58 -0
- package/src/field/types.ts +48 -0
- package/src/index.ts +9 -4
- package/src/number.ts +134 -0
- package/src/{basic/stream.ts → readable.ts} +31 -4
- package/src/string.ts +41 -0
- package/src/struct.ts +200 -670
- package/src/types.ts +37 -0
- package/src/utils.ts +14 -67
- package/tsconfig.build.json +6 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/CHANGELOG.json +0 -173
- package/esm/basic/definition.d.ts +0 -44
- package/esm/basic/definition.d.ts.map +0 -1
- package/esm/basic/definition.js +0 -24
- package/esm/basic/definition.js.map +0 -1
- package/esm/basic/field-value.d.ts +0 -39
- package/esm/basic/field-value.d.ts.map +0 -1
- package/esm/basic/field-value.js +0 -46
- package/esm/basic/field-value.js.map +0 -1
- package/esm/basic/index.d.ts +0 -6
- package/esm/basic/index.d.ts.map +0 -1
- package/esm/basic/index.js +0 -6
- package/esm/basic/index.js.map +0 -1
- package/esm/basic/options.d.ts +0 -10
- package/esm/basic/options.d.ts.map +0 -1
- package/esm/basic/options.js +0 -4
- package/esm/basic/options.js.map +0 -1
- package/esm/basic/stream.d.ts.map +0 -1
- package/esm/basic/stream.js +0 -8
- package/esm/basic/stream.js.map +0 -1
- package/esm/basic/struct-value.d.ts +0 -30
- package/esm/basic/struct-value.d.ts.map +0 -1
- package/esm/basic/struct-value.js +0 -62
- package/esm/basic/struct-value.js.map +0 -1
- package/esm/sync-promise.d.ts +0 -13
- package/esm/sync-promise.d.ts.map +0 -1
- package/esm/sync-promise.js +0 -71
- package/esm/sync-promise.js.map +0 -1
- package/esm/types/bigint.d.ts +0 -25
- package/esm/types/bigint.d.ts.map +0 -1
- package/esm/types/bigint.js +0 -46
- package/esm/types/bigint.js.map +0 -1
- package/esm/types/buffer/base.d.ts +0 -69
- package/esm/types/buffer/base.d.ts.map +0 -1
- package/esm/types/buffer/base.js +0 -100
- package/esm/types/buffer/base.js.map +0 -1
- package/esm/types/buffer/fixed-length.d.ts +0 -9
- package/esm/types/buffer/fixed-length.d.ts.map +0 -1
- package/esm/types/buffer/fixed-length.js +0 -7
- package/esm/types/buffer/fixed-length.js.map +0 -1
- package/esm/types/buffer/index.d.ts +0 -4
- package/esm/types/buffer/index.d.ts.map +0 -1
- package/esm/types/buffer/index.js +0 -4
- package/esm/types/buffer/index.js.map +0 -1
- package/esm/types/buffer/variable-length.d.ts +0 -46
- package/esm/types/buffer/variable-length.d.ts.map +0 -1
- package/esm/types/buffer/variable-length.js +0 -87
- package/esm/types/buffer/variable-length.js.map +0 -1
- package/esm/types/index.d.ts +0 -4
- package/esm/types/index.d.ts.map +0 -1
- package/esm/types/index.js +0 -4
- package/esm/types/index.js.map +0 -1
- package/esm/types/number.d.ts +0 -28
- package/esm/types/number.d.ts.map +0 -1
- package/esm/types/number.js +0 -99
- package/esm/types/number.js.map +0 -1
- package/src/basic/definition.ts +0 -68
- package/src/basic/field-value.ts +0 -75
- package/src/basic/index.ts +0 -5
- package/src/basic/options.ts +0 -19
- package/src/basic/struct-value.ts +0 -85
- package/src/sync-promise.ts +0 -134
- package/src/types/bigint.ts +0 -124
- package/src/types/buffer/base.ts +0 -198
- package/src/types/buffer/fixed-length.ts +0 -22
- package/src/types/buffer/index.ts +0 -3
- package/src/types/buffer/variable-length.ts +0 -198
- package/src/types/index.ts +0 -3
- package/src/types/number.ts +0 -166
package/src/bipedal.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { MaybePromiseLike } from "@yume-chan/async";
|
|
2
|
+
import { isPromiseLike } from "@yume-chan/async";
|
|
3
|
+
|
|
4
|
+
function advance<T>(
|
|
5
|
+
iterator: Iterator<unknown, T, unknown>,
|
|
6
|
+
next: unknown,
|
|
7
|
+
): MaybePromiseLike<T> {
|
|
8
|
+
while (true) {
|
|
9
|
+
const { done, value } = iterator.next(next);
|
|
10
|
+
if (done) {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
if (isPromiseLike(value)) {
|
|
14
|
+
return value.then(
|
|
15
|
+
(value) => advance(iterator, { resolved: value }),
|
|
16
|
+
(error: unknown) => advance(iterator, { error }),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
next = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type BipedalGenerator<This, T, A extends unknown[]> = (
|
|
24
|
+
this: This,
|
|
25
|
+
then: <U>(value: MaybePromiseLike<U>) => Iterable<unknown, U, unknown>,
|
|
26
|
+
...args: A
|
|
27
|
+
) => Generator<unknown, T, unknown>;
|
|
28
|
+
|
|
29
|
+
/* #__NO_SIDE_EFFECTS__ */
|
|
30
|
+
export function bipedal<This, T, A extends unknown[]>(
|
|
31
|
+
fn: BipedalGenerator<This, T, A>,
|
|
32
|
+
bindThis?: This,
|
|
33
|
+
): { (this: This, ...args: A): MaybePromiseLike<T> } {
|
|
34
|
+
function result(this: This, ...args: A): MaybePromiseLike<T> {
|
|
35
|
+
const iterator = fn.call(
|
|
36
|
+
this,
|
|
37
|
+
function* <U>(
|
|
38
|
+
value: MaybePromiseLike<U>,
|
|
39
|
+
): Generator<
|
|
40
|
+
PromiseLike<U>,
|
|
41
|
+
U,
|
|
42
|
+
{ resolved: U } | { error: unknown }
|
|
43
|
+
> {
|
|
44
|
+
if (isPromiseLike(value)) {
|
|
45
|
+
const result = yield value;
|
|
46
|
+
if ("resolved" in result) {
|
|
47
|
+
return result.resolved;
|
|
48
|
+
} else {
|
|
49
|
+
throw result.error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return value;
|
|
54
|
+
},
|
|
55
|
+
...args,
|
|
56
|
+
) as never;
|
|
57
|
+
return advance(iterator, undefined);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (bindThis) {
|
|
61
|
+
return result.bind(bindThis);
|
|
62
|
+
} else {
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/buffer.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import type { Field } from "./field/index.js";
|
|
2
|
+
import { field } from "./field/index.js";
|
|
3
|
+
|
|
4
|
+
export const EmptyUint8Array = new Uint8Array(0);
|
|
5
|
+
|
|
6
|
+
export interface Converter<From, To> {
|
|
7
|
+
convert: (value: From) => To;
|
|
8
|
+
back: (value: To) => From;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface BufferLengthConverter<K, KT> extends Converter<KT, number> {
|
|
12
|
+
field: K;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BufferLike {
|
|
16
|
+
(length: number): Field<Uint8Array, never, never, Uint8Array>;
|
|
17
|
+
<U>(
|
|
18
|
+
length: number,
|
|
19
|
+
converter: Converter<Uint8Array, U>,
|
|
20
|
+
): Field<U, never, never, Uint8Array>;
|
|
21
|
+
|
|
22
|
+
<K extends string>(
|
|
23
|
+
lengthField: K,
|
|
24
|
+
): Field<Uint8Array, K, Record<K, number>, Uint8Array>;
|
|
25
|
+
<K extends string, U>(
|
|
26
|
+
lengthField: K,
|
|
27
|
+
converter: Converter<Uint8Array, U>,
|
|
28
|
+
): Field<U, K, Record<K, number>, Uint8Array>;
|
|
29
|
+
|
|
30
|
+
<K extends string, KT>(
|
|
31
|
+
length: BufferLengthConverter<K, KT>,
|
|
32
|
+
): Field<Uint8Array, K, Record<K, KT>, Uint8Array>;
|
|
33
|
+
<K extends string, KT, U>(
|
|
34
|
+
length: BufferLengthConverter<K, KT>,
|
|
35
|
+
converter: Converter<Uint8Array, U>,
|
|
36
|
+
): Field<U, K, Record<K, KT>, Uint8Array>;
|
|
37
|
+
|
|
38
|
+
<LengthOmitInit extends string, LengthDependencies>(
|
|
39
|
+
length: Field<number, LengthOmitInit, LengthDependencies, number>,
|
|
40
|
+
): Field<Uint8Array, LengthOmitInit, LengthDependencies, Uint8Array>;
|
|
41
|
+
<LengthOmitInit extends string, LengthDependencies, U>(
|
|
42
|
+
length: Field<number, LengthOmitInit, LengthDependencies, number>,
|
|
43
|
+
converter: Converter<Uint8Array, U>,
|
|
44
|
+
): Field<U, LengthOmitInit, LengthDependencies, Uint8Array>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function _buffer(length: number): Field<Uint8Array, never, never, Uint8Array>;
|
|
48
|
+
function _buffer<U>(
|
|
49
|
+
length: number,
|
|
50
|
+
converter: Converter<Uint8Array, U>,
|
|
51
|
+
): Field<U, never, never, Uint8Array>;
|
|
52
|
+
|
|
53
|
+
function _buffer<K extends string>(
|
|
54
|
+
lengthField: K,
|
|
55
|
+
): Field<Uint8Array, K, Record<K, number>, Uint8Array>;
|
|
56
|
+
function _buffer<K extends string, U>(
|
|
57
|
+
lengthField: K,
|
|
58
|
+
converter: Converter<Uint8Array, U>,
|
|
59
|
+
): Field<U, K, Record<K, number>, Uint8Array>;
|
|
60
|
+
|
|
61
|
+
function _buffer<K extends string, KT>(
|
|
62
|
+
length: BufferLengthConverter<K, KT>,
|
|
63
|
+
): Field<Uint8Array, K, Record<K, KT>, Uint8Array>;
|
|
64
|
+
function _buffer<K extends string, KT, U>(
|
|
65
|
+
length: BufferLengthConverter<K, KT>,
|
|
66
|
+
converter: Converter<Uint8Array, U>,
|
|
67
|
+
): Field<U, K, Record<K, KT>, Uint8Array>;
|
|
68
|
+
|
|
69
|
+
function _buffer<LengthOmitInit extends string, LengthDependencies>(
|
|
70
|
+
length: Field<number, LengthOmitInit, LengthDependencies, number>,
|
|
71
|
+
): Field<Uint8Array, LengthOmitInit, LengthDependencies, Uint8Array>;
|
|
72
|
+
function _buffer<LengthOmitInit extends string, LengthDependencies, U>(
|
|
73
|
+
length: Field<number, LengthOmitInit, LengthDependencies, number>,
|
|
74
|
+
converter: Converter<Uint8Array, U>,
|
|
75
|
+
): Field<U, LengthOmitInit, LengthDependencies, Uint8Array>;
|
|
76
|
+
|
|
77
|
+
/* #__NO_SIDE_EFFECTS__ */
|
|
78
|
+
function _buffer(
|
|
79
|
+
lengthOrField:
|
|
80
|
+
| string
|
|
81
|
+
| number
|
|
82
|
+
| Field<number, string, unknown, number>
|
|
83
|
+
| BufferLengthConverter<string, unknown>,
|
|
84
|
+
converter?: Converter<Uint8Array, unknown>,
|
|
85
|
+
): Field<unknown, string, Record<string, unknown>, Uint8Array> {
|
|
86
|
+
// Fixed length
|
|
87
|
+
if (typeof lengthOrField === "number") {
|
|
88
|
+
if (converter) {
|
|
89
|
+
if (lengthOrField === 0) {
|
|
90
|
+
return field(
|
|
91
|
+
0,
|
|
92
|
+
"byob",
|
|
93
|
+
() => {},
|
|
94
|
+
// eslint-disable-next-line require-yield
|
|
95
|
+
function* () {
|
|
96
|
+
return converter.convert(EmptyUint8Array);
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return field(
|
|
102
|
+
0,
|
|
103
|
+
"byob",
|
|
104
|
+
(value, { buffer, index }) => {
|
|
105
|
+
buffer.set(value.slice(0, lengthOrField), index);
|
|
106
|
+
},
|
|
107
|
+
function* (then, reader) {
|
|
108
|
+
const array = yield* then(
|
|
109
|
+
reader.readExactly(lengthOrField),
|
|
110
|
+
);
|
|
111
|
+
return converter.convert(array);
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
init(value) {
|
|
115
|
+
return converter.back(value);
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (lengthOrField === 0) {
|
|
122
|
+
return field(
|
|
123
|
+
0,
|
|
124
|
+
"byob",
|
|
125
|
+
() => {},
|
|
126
|
+
// eslint-disable-next-line require-yield
|
|
127
|
+
function* () {
|
|
128
|
+
return EmptyUint8Array;
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return field(
|
|
134
|
+
0,
|
|
135
|
+
"byob",
|
|
136
|
+
(value, { buffer, index }) => {
|
|
137
|
+
buffer.set(value.slice(0, lengthOrField), index);
|
|
138
|
+
},
|
|
139
|
+
// eslint-disable-next-line require-yield
|
|
140
|
+
function* (_then, reader) {
|
|
141
|
+
return reader.readExactly(lengthOrField);
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Declare length field
|
|
147
|
+
// Some field types are `function`s
|
|
148
|
+
if (
|
|
149
|
+
(typeof lengthOrField === "object" ||
|
|
150
|
+
typeof lengthOrField === "function") &&
|
|
151
|
+
"serialize" in lengthOrField
|
|
152
|
+
) {
|
|
153
|
+
if (converter) {
|
|
154
|
+
return field(
|
|
155
|
+
lengthOrField.size,
|
|
156
|
+
"default",
|
|
157
|
+
(value, { littleEndian }) => {
|
|
158
|
+
if (lengthOrField.type === "default") {
|
|
159
|
+
const lengthBuffer = lengthOrField.serialize(
|
|
160
|
+
value.length,
|
|
161
|
+
{ littleEndian },
|
|
162
|
+
);
|
|
163
|
+
const result = new Uint8Array(
|
|
164
|
+
lengthBuffer.length + value.length,
|
|
165
|
+
);
|
|
166
|
+
result.set(lengthBuffer, 0);
|
|
167
|
+
result.set(value, lengthBuffer.length);
|
|
168
|
+
return result;
|
|
169
|
+
} else {
|
|
170
|
+
const result = new Uint8Array(
|
|
171
|
+
lengthOrField.size + value.length,
|
|
172
|
+
);
|
|
173
|
+
lengthOrField.serialize(value.length, {
|
|
174
|
+
buffer: result,
|
|
175
|
+
index: 0,
|
|
176
|
+
littleEndian,
|
|
177
|
+
});
|
|
178
|
+
result.set(value, lengthOrField.size);
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
function* (then, reader, context) {
|
|
183
|
+
const length = yield* then(
|
|
184
|
+
lengthOrField.deserialize(reader, context),
|
|
185
|
+
);
|
|
186
|
+
const array = yield* then(reader.readExactly(length));
|
|
187
|
+
return converter.convert(array);
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
init(value) {
|
|
191
|
+
return converter.back(value);
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return field(
|
|
198
|
+
lengthOrField.size,
|
|
199
|
+
"default",
|
|
200
|
+
(value, { littleEndian }) => {
|
|
201
|
+
if (lengthOrField.type === "default") {
|
|
202
|
+
const lengthBuffer = lengthOrField.serialize(value.length, {
|
|
203
|
+
littleEndian,
|
|
204
|
+
});
|
|
205
|
+
const result = new Uint8Array(
|
|
206
|
+
lengthBuffer.length + value.length,
|
|
207
|
+
);
|
|
208
|
+
result.set(lengthBuffer, 0);
|
|
209
|
+
result.set(value, lengthBuffer.length);
|
|
210
|
+
return result;
|
|
211
|
+
} else {
|
|
212
|
+
const result = new Uint8Array(
|
|
213
|
+
lengthOrField.size + value.length,
|
|
214
|
+
);
|
|
215
|
+
lengthOrField.serialize(value.length, {
|
|
216
|
+
buffer: result,
|
|
217
|
+
index: 0,
|
|
218
|
+
littleEndian,
|
|
219
|
+
});
|
|
220
|
+
result.set(value, lengthOrField.size);
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
function* (then, reader, context) {
|
|
225
|
+
const length = yield* then(
|
|
226
|
+
lengthOrField.deserialize(reader, context),
|
|
227
|
+
);
|
|
228
|
+
return yield* then(reader.readExactly(length));
|
|
229
|
+
},
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Reference exiting length field
|
|
234
|
+
if (typeof lengthOrField === "string") {
|
|
235
|
+
if (converter) {
|
|
236
|
+
return field(
|
|
237
|
+
0,
|
|
238
|
+
"default",
|
|
239
|
+
(source) => source,
|
|
240
|
+
// eslint-disable-next-line require-yield
|
|
241
|
+
function* (_then, reader, { dependencies }) {
|
|
242
|
+
const length = dependencies[lengthOrField] as number;
|
|
243
|
+
if (length === 0) {
|
|
244
|
+
return EmptyUint8Array;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return reader.readExactly(length);
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
init(value, dependencies) {
|
|
251
|
+
const array = converter.back(value);
|
|
252
|
+
dependencies[lengthOrField] = array.length;
|
|
253
|
+
return array;
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return field(
|
|
260
|
+
0,
|
|
261
|
+
"default",
|
|
262
|
+
(source) => source,
|
|
263
|
+
// eslint-disable-next-line require-yield
|
|
264
|
+
function* (_then, reader, { dependencies }) {
|
|
265
|
+
const length = dependencies[lengthOrField] as number;
|
|
266
|
+
if (length === 0) {
|
|
267
|
+
return EmptyUint8Array;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return reader.readExactly(length);
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
init(value, dependencies) {
|
|
274
|
+
dependencies[lengthOrField] = (value as Uint8Array).length;
|
|
275
|
+
return undefined;
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Reference existing length field + converter
|
|
282
|
+
if (converter) {
|
|
283
|
+
return field(
|
|
284
|
+
0,
|
|
285
|
+
"default",
|
|
286
|
+
(source) => source,
|
|
287
|
+
// eslint-disable-next-line require-yield
|
|
288
|
+
function* (_then, reader, { dependencies }) {
|
|
289
|
+
const rawLength = dependencies[lengthOrField.field];
|
|
290
|
+
const length = lengthOrField.convert(rawLength);
|
|
291
|
+
if (length === 0) {
|
|
292
|
+
return EmptyUint8Array;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return reader.readExactly(length);
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
init(value, dependencies) {
|
|
299
|
+
const array = converter.back(value);
|
|
300
|
+
dependencies[lengthOrField.field] = lengthOrField.back(
|
|
301
|
+
array.length,
|
|
302
|
+
);
|
|
303
|
+
return array;
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return field(
|
|
310
|
+
0,
|
|
311
|
+
"default",
|
|
312
|
+
(source) => source,
|
|
313
|
+
// eslint-disable-next-line require-yield
|
|
314
|
+
function* (_then, reader, { dependencies }) {
|
|
315
|
+
const rawLength = dependencies[lengthOrField.field];
|
|
316
|
+
const length = lengthOrField.convert(rawLength);
|
|
317
|
+
if (length === 0) {
|
|
318
|
+
return EmptyUint8Array;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return reader.readExactly(length);
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
init(value, dependencies) {
|
|
325
|
+
dependencies[lengthOrField.field] = lengthOrField.back(
|
|
326
|
+
(value as Uint8Array).length,
|
|
327
|
+
);
|
|
328
|
+
return undefined;
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export const buffer = _buffer;
|
package/src/concat.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { FieldsValue, Struct, StructFields } from "./struct.js";
|
|
2
|
+
import { struct } from "./struct.js";
|
|
3
|
+
|
|
4
|
+
type UnionToIntersection<U> = (
|
|
5
|
+
U extends unknown ? (x: U) => void : never
|
|
6
|
+
) extends (x: infer I) => void
|
|
7
|
+
? I
|
|
8
|
+
: never;
|
|
9
|
+
|
|
10
|
+
type As<T, U> = T extends infer V extends U ? V : never;
|
|
11
|
+
|
|
12
|
+
export type ConcatFields<
|
|
13
|
+
T extends Struct<
|
|
14
|
+
StructFields,
|
|
15
|
+
Record<PropertyKey, unknown> | undefined,
|
|
16
|
+
unknown
|
|
17
|
+
>[],
|
|
18
|
+
> = As<UnionToIntersection<T[number]["fields"]>, StructFields>;
|
|
19
|
+
|
|
20
|
+
type ConcatFieldValues<
|
|
21
|
+
T extends Struct<
|
|
22
|
+
StructFields,
|
|
23
|
+
Record<PropertyKey, unknown> | undefined,
|
|
24
|
+
unknown
|
|
25
|
+
>[],
|
|
26
|
+
> = FieldsValue<ConcatFields<T>>;
|
|
27
|
+
|
|
28
|
+
type ExtraToUnion<Extra extends Record<PropertyKey, unknown> | undefined> =
|
|
29
|
+
Extra extends undefined ? never : Extra;
|
|
30
|
+
|
|
31
|
+
export type ConcatExtras<
|
|
32
|
+
T extends Struct<
|
|
33
|
+
StructFields,
|
|
34
|
+
Record<PropertyKey, unknown> | undefined,
|
|
35
|
+
unknown
|
|
36
|
+
>[],
|
|
37
|
+
> = As<
|
|
38
|
+
UnionToIntersection<ExtraToUnion<T[number]["extra"]>>,
|
|
39
|
+
Record<PropertyKey, unknown>
|
|
40
|
+
>;
|
|
41
|
+
|
|
42
|
+
/* #__NO_SIDE_EFFECTS__ */
|
|
43
|
+
export function concat<
|
|
44
|
+
T extends Struct<
|
|
45
|
+
StructFields,
|
|
46
|
+
Record<PropertyKey, unknown> | undefined,
|
|
47
|
+
unknown
|
|
48
|
+
>[],
|
|
49
|
+
PostDeserialize = ConcatFieldValues<T> & ConcatExtras<T>,
|
|
50
|
+
>(
|
|
51
|
+
options: {
|
|
52
|
+
littleEndian: boolean;
|
|
53
|
+
postDeserialize?: (
|
|
54
|
+
this: ConcatFieldValues<T> & ConcatExtras<T>,
|
|
55
|
+
value: ConcatFieldValues<T> & ConcatExtras<T>,
|
|
56
|
+
) => PostDeserialize;
|
|
57
|
+
},
|
|
58
|
+
...structs: T
|
|
59
|
+
): Struct<ConcatFields<T>, ConcatExtras<T>, PostDeserialize> {
|
|
60
|
+
return struct(
|
|
61
|
+
structs.reduce(
|
|
62
|
+
(fields, struct) => Object.assign(fields, struct.fields),
|
|
63
|
+
{},
|
|
64
|
+
) as never,
|
|
65
|
+
{
|
|
66
|
+
littleEndian: options.littleEndian,
|
|
67
|
+
postDeserialize: options.postDeserialize,
|
|
68
|
+
extra: structs.reduce(
|
|
69
|
+
(extras, struct) =>
|
|
70
|
+
Object.defineProperties(
|
|
71
|
+
extras,
|
|
72
|
+
Object.getOwnPropertyDescriptors(struct.extra),
|
|
73
|
+
),
|
|
74
|
+
{},
|
|
75
|
+
) as never,
|
|
76
|
+
},
|
|
77
|
+
) as never;
|
|
78
|
+
}
|
package/src/extend.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtraToIntersection,
|
|
3
|
+
FieldsValue,
|
|
4
|
+
Struct,
|
|
5
|
+
StructFields,
|
|
6
|
+
} from "./struct.js";
|
|
7
|
+
import { struct } from "./struct.js";
|
|
8
|
+
|
|
9
|
+
/* #__NO_SIDE_EFFECTS__ */
|
|
10
|
+
export function extend<
|
|
11
|
+
Base extends Struct<
|
|
12
|
+
StructFields,
|
|
13
|
+
Record<PropertyKey, unknown> | undefined,
|
|
14
|
+
unknown
|
|
15
|
+
>,
|
|
16
|
+
Fields extends StructFields,
|
|
17
|
+
PostDeserialize = FieldsValue<Base["fields"] & Fields> &
|
|
18
|
+
ExtraToIntersection<Base["extra"]>,
|
|
19
|
+
>(
|
|
20
|
+
base: Base,
|
|
21
|
+
fields: Fields,
|
|
22
|
+
options?: {
|
|
23
|
+
littleEndian?: boolean | undefined;
|
|
24
|
+
postDeserialize?: (
|
|
25
|
+
this: FieldsValue<Base["fields"] & Fields> &
|
|
26
|
+
ExtraToIntersection<Base["extra"]>,
|
|
27
|
+
value: FieldsValue<Base["fields"] & Fields> &
|
|
28
|
+
ExtraToIntersection<Base["extra"]>,
|
|
29
|
+
) => PostDeserialize;
|
|
30
|
+
},
|
|
31
|
+
): Struct<Base["fields"] & Fields, Base["extra"], PostDeserialize> {
|
|
32
|
+
return struct(Object.assign({}, base.fields, fields), {
|
|
33
|
+
littleEndian: options?.littleEndian ?? base.littleEndian,
|
|
34
|
+
extra: base.extra as never,
|
|
35
|
+
postDeserialize: options?.postDeserialize,
|
|
36
|
+
}) as never;
|
|
37
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { BipedalGenerator } from "../bipedal.js";
|
|
2
|
+
import { bipedal } from "../bipedal.js";
|
|
3
|
+
import type { AsyncExactReadable } from "../readable.js";
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
ByobFieldSerializer,
|
|
7
|
+
DefaultFieldSerializer,
|
|
8
|
+
} from "./serialize.js";
|
|
9
|
+
import { byobFieldSerializer, defaultFieldSerializer } from "./serialize.js";
|
|
10
|
+
import type { Field, FieldDeserializeContext, FieldOptions } from "./types.js";
|
|
11
|
+
|
|
12
|
+
export type BipedalFieldDeserializer<T, D> = BipedalGenerator<
|
|
13
|
+
undefined,
|
|
14
|
+
T,
|
|
15
|
+
[reader: AsyncExactReadable, context: FieldDeserializeContext<D>]
|
|
16
|
+
>;
|
|
17
|
+
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
19
|
+
function _field<T, OmitInit extends string, D, Raw = T>(
|
|
20
|
+
size: number,
|
|
21
|
+
type: "default",
|
|
22
|
+
serialize: DefaultFieldSerializer<Raw>,
|
|
23
|
+
deserialize: BipedalFieldDeserializer<T, D>,
|
|
24
|
+
options?: FieldOptions<T, OmitInit, D, Raw>,
|
|
25
|
+
): Field<T, OmitInit, D, Raw>;
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
27
|
+
function _field<T, OmitInit extends string, D, Raw = T>(
|
|
28
|
+
size: number,
|
|
29
|
+
type: "byob",
|
|
30
|
+
serialize: ByobFieldSerializer<Raw>,
|
|
31
|
+
deserialize: BipedalFieldDeserializer<T, D>,
|
|
32
|
+
options?: FieldOptions<T, OmitInit, D, Raw>,
|
|
33
|
+
): Field<T, OmitInit, D, Raw>;
|
|
34
|
+
/* #__NO_SIDE_EFFECTS__ */
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
36
|
+
function _field<T, OmitInit extends string, D, Raw = T>(
|
|
37
|
+
size: number,
|
|
38
|
+
type: "default" | "byob",
|
|
39
|
+
serialize: DefaultFieldSerializer<Raw> | ByobFieldSerializer<Raw>,
|
|
40
|
+
deserialize: BipedalFieldDeserializer<T, D>,
|
|
41
|
+
options?: FieldOptions<T, OmitInit, D, Raw>,
|
|
42
|
+
): Field<T, OmitInit, D, Raw> {
|
|
43
|
+
const field: Field<T, OmitInit, D, Raw> = {
|
|
44
|
+
size,
|
|
45
|
+
type: type,
|
|
46
|
+
serialize:
|
|
47
|
+
type === "default"
|
|
48
|
+
? defaultFieldSerializer(
|
|
49
|
+
serialize as DefaultFieldSerializer<Raw>,
|
|
50
|
+
)
|
|
51
|
+
: byobFieldSerializer(
|
|
52
|
+
size,
|
|
53
|
+
serialize as ByobFieldSerializer<Raw>,
|
|
54
|
+
),
|
|
55
|
+
deserialize: bipedal(deserialize) as never,
|
|
56
|
+
omitInit: options?.omitInit,
|
|
57
|
+
};
|
|
58
|
+
if (options?.init) {
|
|
59
|
+
field.init = options.init;
|
|
60
|
+
}
|
|
61
|
+
return field;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const field = _field;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FieldByobSerializeContext,
|
|
3
|
+
FieldDefaultSerializeContext,
|
|
4
|
+
FieldSerializer,
|
|
5
|
+
} from "./types.js";
|
|
6
|
+
|
|
7
|
+
export type DefaultFieldSerializer<T> = (
|
|
8
|
+
source: T,
|
|
9
|
+
context: FieldDefaultSerializeContext,
|
|
10
|
+
) => Uint8Array;
|
|
11
|
+
|
|
12
|
+
/* Adapt default field serializer to universal field serializer */
|
|
13
|
+
export function defaultFieldSerializer<T>(
|
|
14
|
+
serializer: DefaultFieldSerializer<T>,
|
|
15
|
+
): FieldSerializer<T>["serialize"] {
|
|
16
|
+
return (
|
|
17
|
+
source,
|
|
18
|
+
context: FieldDefaultSerializeContext | FieldByobSerializeContext,
|
|
19
|
+
): never => {
|
|
20
|
+
if ("buffer" in context) {
|
|
21
|
+
const buffer = serializer(source, context);
|
|
22
|
+
context.buffer.set(buffer, context.index);
|
|
23
|
+
return buffer.length as never;
|
|
24
|
+
} else {
|
|
25
|
+
return serializer(source, context) as never;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type ByobFieldSerializer<T> = (
|
|
31
|
+
source: T,
|
|
32
|
+
context: FieldByobSerializeContext & { index: number },
|
|
33
|
+
) => void;
|
|
34
|
+
|
|
35
|
+
/* Adapt byob field serializer to universal field serializer */
|
|
36
|
+
export function byobFieldSerializer<T>(
|
|
37
|
+
size: number,
|
|
38
|
+
serializer: ByobFieldSerializer<T>,
|
|
39
|
+
): FieldSerializer<T>["serialize"] {
|
|
40
|
+
return (
|
|
41
|
+
source,
|
|
42
|
+
context: FieldDefaultSerializeContext | FieldByobSerializeContext,
|
|
43
|
+
): never => {
|
|
44
|
+
if ("buffer" in context) {
|
|
45
|
+
context.index ??= 0;
|
|
46
|
+
serializer(source, context as never);
|
|
47
|
+
return size as never;
|
|
48
|
+
} else {
|
|
49
|
+
const buffer = new Uint8Array(size);
|
|
50
|
+
serializer(source, {
|
|
51
|
+
buffer,
|
|
52
|
+
index: 0,
|
|
53
|
+
littleEndian: context.littleEndian,
|
|
54
|
+
});
|
|
55
|
+
return buffer as never;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { MaybePromiseLike } from "@yume-chan/async";
|
|
2
|
+
|
|
3
|
+
import type { AsyncExactReadable, ExactReadable } from "../readable.js";
|
|
4
|
+
|
|
5
|
+
export interface FieldDefaultSerializeContext {
|
|
6
|
+
littleEndian: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface FieldByobSerializeContext
|
|
10
|
+
extends FieldDefaultSerializeContext {
|
|
11
|
+
buffer: Uint8Array;
|
|
12
|
+
index?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface FieldSerializer<T> {
|
|
16
|
+
type: "default" | "byob";
|
|
17
|
+
size: number;
|
|
18
|
+
|
|
19
|
+
serialize(source: T, context: FieldDefaultSerializeContext): Uint8Array;
|
|
20
|
+
serialize(source: T, context: FieldByobSerializeContext): number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface Field<T, OmitInit extends string, D, Raw = T>
|
|
24
|
+
extends FieldSerializer<Raw>,
|
|
25
|
+
FieldDeserializer<T, D> {
|
|
26
|
+
omitInit: OmitInit | undefined;
|
|
27
|
+
|
|
28
|
+
init?(value: T, dependencies: D): Raw | undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface FieldDeserializeContext<D> {
|
|
32
|
+
littleEndian: boolean;
|
|
33
|
+
dependencies: D;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface FieldDeserializer<T, D> {
|
|
37
|
+
deserialize(reader: ExactReadable, context: FieldDeserializeContext<D>): T;
|
|
38
|
+
deserialize(
|
|
39
|
+
reader: AsyncExactReadable,
|
|
40
|
+
context: FieldDeserializeContext<D>,
|
|
41
|
+
): MaybePromiseLike<T>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface FieldOptions<T, OmitInit extends string, D, Raw = T> {
|
|
45
|
+
omitInit?: OmitInit;
|
|
46
|
+
dependencies?: D;
|
|
47
|
+
init?: (value: T, dependencies: D) => Raw | undefined;
|
|
48
|
+
}
|