Skip to content

Commit a21af53

Browse files
committed
Add iterator nodes; use int32 for other values
1 parent 7329f5f commit a21af53

File tree

4 files changed

+141
-78
lines changed

4 files changed

+141
-78
lines changed

packages/seroval/src/binary/deserializer.ts

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import {
2020
SerovalMalformedBinaryError,
2121
SerovalMissingPluginError,
2222
} from '../core/errors';
23-
import { createSequence, type Sequence } from '../core/sequence';
24-
import { createStream, type Stream } from '../core/stream';
23+
import { createSequence, sequenceToIterator, type Sequence } from '../core/sequence';
24+
import { createStream, streamToAsyncIterable, type Stream } from '../core/stream';
2525
import {
2626
SYM_ASYNC_ITERATOR,
2727
SYM_IS_CONCAT_SPREADABLE,
@@ -30,9 +30,10 @@ import {
3030
} from '../core/symbols';
3131
import {
3232
decodeBigint,
33-
decodeInteger,
33+
decodeInt,
3434
decodeNumber,
3535
decodeString,
36+
decodeUint,
3637
} from './encoder';
3738
import { SerovalEndianness, SerovalNodeType } from './nodes';
3839
import type { Plugin } from './plugin';
@@ -134,9 +135,14 @@ async function deserializeByte(ctx: DeserializerContext): Promise<number> {
134135
return bytes[0];
135136
}
136137

137-
async function deserializeInteger(ctx: DeserializerContext): Promise<number> {
138+
async function deserializeUint(ctx: DeserializerContext): Promise<number> {
138139
const bytes = await ensureChunk(ctx, 4);
139-
return decodeInteger(bytes, ctx.endianness === SerovalEndianness.LE);
140+
return decodeUint(bytes, ctx.endianness === SerovalEndianness.LE);
141+
}
142+
143+
async function deserializeInt(ctx: DeserializerContext): Promise<number> {
144+
const bytes = await ensureChunk(ctx, 4);
145+
return decodeInt(bytes, ctx.endianness === SerovalEndianness.LE);
140146
}
141147

142148
async function deserializeNumberValue(
@@ -155,14 +161,14 @@ async function deserializeId(
155161
type: SerovalNodeType,
156162
): Promise<number> {
157163
// parse ID
158-
const id = await deserializeInteger(ctx);
164+
const id = await deserializeUint(ctx);
159165
// Mark id
160166
ctx.marker.set(id, type);
161167
return id;
162168
}
163169

164170
async function deserializeRef(ctx: DeserializerContext) {
165-
const ref = await deserializeInteger(ctx);
171+
const ref = await deserializeUint(ctx);
166172
if (ctx.refs.has(ref)) {
167173
return ctx.refs.get(ref)!;
168174
}
@@ -183,7 +189,7 @@ async function deserializeNumber(ctx: DeserializerContext) {
183189
async function deserializeString(ctx: DeserializerContext) {
184190
const id = await deserializeId(ctx, SerovalNodeType.String);
185191
// First, ensure that there's an encoded length
186-
const length = await deserializeInteger(ctx);
192+
const length = await deserializeUint(ctx);
187193
// Ensure the next chunk is based on encoded length
188194
const encodedData = await ensureChunk(ctx, length);
189195
upsert(ctx, id, decodeString(encodedData));
@@ -264,7 +270,7 @@ async function deserializeObjectAssign(ctx: DeserializerContext) {
264270

265271
async function deserializeArrayAssign(ctx: DeserializerContext) {
266272
const object = (await deserializeRef(ctx)).value as unknown[];
267-
const key = (await deserializeInteger(ctx)) as number;
273+
const key = (await deserializeUint(ctx)) as number;
268274
const value = (await deserializeRef(ctx)).value;
269275

270276
object[key] = value;
@@ -289,7 +295,7 @@ async function deserializeObjectFlag(ctx: DeserializerContext) {
289295

290296
async function deserializeArray(ctx: DeserializerContext) {
291297
const id = await deserializeId(ctx, SerovalNodeType.Array);
292-
const length = await deserializeInteger(ctx);
298+
const length = await deserializeUint(ctx);
293299
upsert(ctx, id, new Array(length));
294300
}
295301

@@ -318,8 +324,8 @@ async function deserializeStreamReturn(ctx: DeserializerContext) {
318324

319325
async function deserializeSequence(ctx: DeserializerContext) {
320326
const id = await deserializeId(ctx, SerovalNodeType.Sequence);
321-
const throwAt = await deserializeNumberValue(ctx);
322-
const doneAt = await deserializeNumberValue(ctx);
327+
const throwAt = await deserializeInt(ctx);
328+
const doneAt = await deserializeInt(ctx);
323329
upsert(ctx, id, createSequence([], throwAt, doneAt));
324330
}
325331

@@ -341,7 +347,7 @@ async function deserializeNullConstructor(ctx: DeserializerContext) {
341347

342348
async function deserializeDate(ctx: DeserializerContext) {
343349
const id = await deserializeId(ctx, SerovalNodeType.Date);
344-
const timestamp = await deserializeInteger(ctx);
350+
const timestamp = await deserializeUint(ctx);
345351
upsert(ctx, id, new Date(timestamp));
346352
}
347353

@@ -364,7 +370,7 @@ async function deserializeBoxed(ctx: DeserializerContext) {
364370

365371
async function deserializeArrayBuffer(ctx: DeserializerContext) {
366372
const id = await deserializeId(ctx, SerovalNodeType.ArrayBuffer);
367-
const length = await deserializeInteger(ctx);
373+
const length = await deserializeUint(ctx);
368374
const bytes = await ensureChunk(ctx, length);
369375
upsert(ctx, id, bytes.buffer);
370376
}
@@ -375,8 +381,8 @@ async function deserializeTypedArray(ctx: DeserializerContext) {
375381
TYPED_ARRAY_CONSTRUCTOR,
376382
(await deserializeByte(ctx)) as TypedArrayTag,
377383
);
378-
const offset = await deserializeInteger(ctx);
379-
const length = await deserializeInteger(ctx);
384+
const offset = await deserializeUint(ctx);
385+
const length = await deserializeUint(ctx);
380386
const buffer = (await deserializeRef(ctx)).value as ArrayBuffer;
381387
upsert(ctx, id, new construct(buffer, offset, length));
382388
}
@@ -387,16 +393,16 @@ async function deserializeBigIntTypedArray(ctx: DeserializerContext) {
387393
BIG_INT_TYPED_ARRAY_CONSTRUCTOR,
388394
(await deserializeByte(ctx)) as BigIntTypedArrayTag,
389395
);
390-
const offset = await deserializeInteger(ctx);
391-
const length = await deserializeInteger(ctx);
396+
const offset = await deserializeUint(ctx);
397+
const length = await deserializeUint(ctx);
392398
const buffer = (await deserializeRef(ctx)).value as ArrayBuffer;
393399
upsert(ctx, id, new construct(buffer, offset, length));
394400
}
395401

396402
async function deserializeDataView(ctx: DeserializerContext) {
397403
const id = await deserializeId(ctx, SerovalNodeType.DataView);
398-
const offset = await deserializeInteger(ctx);
399-
const length = await deserializeInteger(ctx);
404+
const offset = await deserializeUint(ctx);
405+
const length = await deserializeUint(ctx);
400406
const buffer = (await deserializeRef(ctx)).value as ArrayBuffer;
401407
upsert(ctx, id, new DataView(buffer, offset, length));
402408
}
@@ -433,7 +439,7 @@ async function deserializePromise(ctx: DeserializerContext) {
433439
}
434440

435441
async function deserializePromiseSuccess(ctx: DeserializerContext) {
436-
const resolverIndex = await deserializeInteger(ctx);
442+
const resolverIndex = await deserializeUint(ctx);
437443
const currentResolver = ctx.resolvers.get(resolverIndex);
438444
if (currentResolver == null) {
439445
throw new SerovalMalformedBinaryError();
@@ -443,7 +449,7 @@ async function deserializePromiseSuccess(ctx: DeserializerContext) {
443449
}
444450

445451
async function deserializePromiseFailure(ctx: DeserializerContext) {
446-
const resolverIndex = await deserializeInteger(ctx);
452+
const resolverIndex = await deserializeUint(ctx);
447453
const currentResolver = ctx.resolvers.get(resolverIndex);
448454
if (currentResolver == null) {
449455
throw new SerovalMalformedBinaryError();
@@ -493,6 +499,18 @@ async function deserializeRoot(ctx: DeserializerContext) {
493499
ctx.root.s(reference);
494500
}
495501

502+
async function deserializeIterator(ctx: DeserializerContext) {
503+
const id = await deserializeId(ctx, SerovalNodeType.Iterator);
504+
const sequence = (await deserializeRef(ctx)).value as Sequence;
505+
upsert(ctx, id, sequenceToIterator(sequence));
506+
}
507+
508+
async function deserializeAsyncIterator(ctx: DeserializerContext) {
509+
const id = await deserializeId(ctx, SerovalNodeType.AsyncIterator);
510+
const stream = (await deserializeRef(ctx)).value as Stream<unknown>;
511+
upsert(ctx, id, streamToAsyncIterable(stream));
512+
}
513+
496514
async function deserializeChunk(ctx: DeserializerContext) {
497515
// Read first byte
498516
const firstByte = (await deserializeByte(ctx)) as SerovalNodeType;
@@ -606,6 +624,12 @@ async function deserializeChunk(ctx: DeserializerContext) {
606624
case SerovalNodeType.Root:
607625
await deserializeRoot(ctx);
608626
break;
627+
case SerovalNodeType.Iterator:
628+
await deserializeIterator(ctx);
629+
break;
630+
case SerovalNodeType.AsyncIterator:
631+
await deserializeAsyncIterator(ctx);
632+
break;
609633
default:
610634
throw new SerovalMalformedBinaryError();
611635
}

packages/seroval/src/binary/encoder.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ export function mergeBytes(bytes: (number | Uint8Array)[]) {
2929

3030
return newArr;
3131
}
32+
export function encodeInt(value: number): Uint8Array {
33+
const buffer = new ArrayBuffer(4);
34+
const uint = new Int32Array(buffer);
35+
uint[0] = value;
36+
return new Uint8Array(buffer);
37+
}
3238

33-
export function encodeInteger(value: number): Uint8Array {
39+
export function encodeUint(value: number): Uint8Array {
3440
const buffer = new ArrayBuffer(4);
3541
const uint = new Uint32Array(buffer);
3642
uint[0] = value;
@@ -54,7 +60,12 @@ export function decodeNumber(value: Uint8Array, littleEndian: boolean): number {
5460
return view.getFloat64(0, littleEndian);
5561
}
5662

57-
export function decodeInteger(value: Uint8Array, littleEndian: boolean): number {
63+
export function decodeInt(value: Uint8Array, littleEndian: boolean): number {
64+
const view = new DataView(value.buffer, value.byteOffset, value.byteLength);
65+
return view.getInt32(0, littleEndian);
66+
}
67+
68+
export function decodeUint(value: Uint8Array, littleEndian: boolean): number {
5869
const view = new DataView(value.buffer, value.byteOffset, value.byteLength);
5970
return view.getUint32(0, littleEndian);
6071
}

packages/seroval/src/binary/nodes.ts

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,43 @@ import type {
99

1010
export const enum SerovalNodeType {
1111
Preamble = 0,
12-
Root = 1 ,
13-
Constant = 2 ,
14-
Number = 3 ,
15-
String = 4 ,
16-
BigInt = 5 ,
17-
WKSymbol = 6 ,
18-
ObjectAssign = 7 ,
19-
ArrayAssign = 8 ,
20-
ObjectFlag = 9 ,
21-
Array = 10 ,
22-
Stream = 11 ,
23-
StreamNext = 12 ,
24-
StreamThrow = 13 ,
25-
StreamReturn = 14 ,
26-
Sequence = 15 ,
27-
SequencePush = 16 ,
28-
Plugin = 17 ,
29-
Object = 18 ,
30-
NullConstructor = 19 ,
31-
Date = 20 ,
32-
Error = 21 ,
33-
Boxed = 22 ,
34-
ArrayBuffer = 23 ,
35-
TypedArray = 24 ,
36-
BigIntTypedArray = 25 ,
37-
DataView = 26 ,
38-
Map = 27 ,
39-
MapSet = 28 ,
40-
Set = 29 ,
41-
SetAdd = 30 ,
42-
Promise = 31 ,
43-
PromiseSuccess = 32 ,
44-
PromiseFailure = 33 ,
45-
RegExp = 34 ,
46-
AggregateError = 35 ,
12+
Root = 1,
13+
Constant = 2,
14+
Number = 3,
15+
String = 4,
16+
BigInt = 5,
17+
WKSymbol = 6,
18+
ObjectAssign = 7,
19+
ArrayAssign = 8,
20+
ObjectFlag = 9,
21+
Array = 10,
22+
Stream = 11,
23+
StreamNext = 12,
24+
StreamThrow = 13,
25+
StreamReturn = 14,
26+
Sequence = 15,
27+
SequencePush = 16,
28+
Plugin = 17,
29+
Object = 18,
30+
NullConstructor = 19,
31+
Date = 20,
32+
Error = 21,
33+
Boxed = 22,
34+
ArrayBuffer = 23,
35+
TypedArray = 24,
36+
BigIntTypedArray = 25,
37+
DataView = 26,
38+
Map = 27,
39+
MapSet = 28,
40+
Set = 29,
41+
SetAdd = 30,
42+
Promise = 31,
43+
PromiseSuccess = 32,
44+
PromiseFailure = 33,
45+
RegExp = 34,
46+
AggregateError = 35,
47+
Iterator = 36,
48+
AsyncIterator = 37,
4749
}
4850

4951
export const enum SerovalEndianness {
@@ -272,6 +274,17 @@ export type SerovalPluginNode = [
272274

273275
export type SerovalRootNode = [type: SerovalNodeType.Root, id: Uint8Array];
274276

277+
export type SerovalIteratorNode = [
278+
type: SerovalNodeType.Iterator,
279+
id: Uint8Array,
280+
sequence: Uint8Array,
281+
];
282+
export type SerovalAsyncIteratorNode = [
283+
type: SerovalNodeType.AsyncIterator,
284+
id: Uint8Array,
285+
stream: Uint8Array,
286+
];
287+
275288
export type SerovalNode =
276289
| SerovalPreambleNode
277290
| SerovalConstantNode
@@ -308,4 +321,6 @@ export type SerovalNode =
308321
| SerovalRegExpNode
309322
| SerovalAggregateErrorNode
310323
| SerovalPluginNode
311-
| SerovalRootNode;
324+
| SerovalRootNode
325+
| SerovalIteratorNode
326+
| SerovalAsyncIteratorNode;

0 commit comments

Comments
 (0)