@@ -18,13 +18,19 @@ import {
18
18
19
19
export type CodecLike < Encodable , Decoded = Encodable > = {
20
20
readonly encode : ( encodable : Encodable ) => Bytes ;
21
- readonly decode : ( decodable : BytesLike ) => Decoded ;
21
+ readonly decode : (
22
+ decodable : BytesLike ,
23
+ config ?: { compatible ?: boolean } ,
24
+ ) => Decoded ;
22
25
readonly byteLength ?: number ;
23
26
} ;
24
27
export class Codec < Encodable , Decoded = Encodable > {
25
28
constructor (
26
29
public readonly encode : ( encodable : Encodable ) => Bytes ,
27
- public readonly decode : ( decodable : BytesLike ) => Decoded ,
30
+ public readonly decode : (
31
+ decodable : BytesLike ,
32
+ config ?: { compatible ?: boolean } ,
33
+ ) => Decoded ,
28
34
public readonly byteLength ?: number , // if provided, treat codec as fixed length
29
35
) { }
30
36
@@ -43,7 +49,7 @@ export class Codec<Encodable, Decoded = Encodable> {
43
49
}
44
50
return encoded ;
45
51
} ,
46
- ( decodable ) => {
52
+ ( decodable , config = { compatible : false } ) => {
47
53
const decodableBytes = bytesFrom ( decodable ) ;
48
54
if (
49
55
byteLength !== undefined &&
@@ -53,7 +59,7 @@ export class Codec<Encodable, Decoded = Encodable> {
53
59
`Codec.decode: expected byte length ${ byteLength } , got ${ decodableBytes . byteLength } ` ,
54
60
) ;
55
61
}
56
- return decode ( decodable ) ;
62
+ return decode ( decodable , config ) ;
57
63
} ,
58
64
byteLength ,
59
65
) ;
@@ -69,10 +75,10 @@ export class Codec<Encodable, Decoded = Encodable> {
69
75
return new Codec (
70
76
( encodable ) =>
71
77
this . encode ( ( inMap ? inMap ( encodable ) : encodable ) as Encodable ) ,
72
- ( buffer ) =>
78
+ ( buffer , config = { compatible : false } ) =>
73
79
( outMap
74
- ? outMap ( this . decode ( buffer ) )
75
- : this . decode ( buffer ) ) as NewDecoded ,
80
+ ? outMap ( this . decode ( buffer , config ) )
81
+ : this . decode ( buffer , config ) ) as NewDecoded ,
76
82
this . byteLength ,
77
83
) ;
78
84
}
@@ -128,7 +134,7 @@ export function fixedItemVec<Encodable, Decoded>(
128
134
throw new Error ( `fixedItemVec(${ e ?. toString ( ) } )` ) ;
129
135
}
130
136
} ,
131
- decode ( buffer ) {
137
+ decode ( buffer , config ) {
132
138
const value = bytesFrom ( buffer ) ;
133
139
if ( value . byteLength < 4 ) {
134
140
throw new Error (
@@ -147,7 +153,10 @@ export function fixedItemVec<Encodable, Decoded>(
147
153
const decodedArray : Array < Decoded > = [ ] ;
148
154
for ( let offset = 4 ; offset < byteLength ; offset += itemByteLength ) {
149
155
decodedArray . push (
150
- itemCodec . decode ( value . slice ( offset , offset + itemByteLength ) ) ,
156
+ itemCodec . decode (
157
+ value . slice ( offset , offset + itemByteLength ) ,
158
+ config ,
159
+ ) ,
151
160
) ;
152
161
}
153
162
return decodedArray ;
@@ -185,7 +194,7 @@ export function dynItemVec<Encodable, Decoded>(
185
194
throw new Error ( `dynItemVec(${ e ?. toString ( ) } )` ) ;
186
195
}
187
196
} ,
188
- decode ( buffer ) {
197
+ decode ( buffer , config ) {
189
198
const value = bytesFrom ( buffer ) ;
190
199
if ( value . byteLength < 4 ) {
191
200
throw new Error (
@@ -215,7 +224,7 @@ export function dynItemVec<Encodable, Decoded>(
215
224
const start = offsets [ index ] ;
216
225
const end = offsets [ index + 1 ] ;
217
226
const itemBuffer = value . slice ( start , end ) ;
218
- decodedArray . push ( itemCodec . decode ( itemBuffer ) ) ;
227
+ decodedArray . push ( itemCodec . decode ( itemBuffer , config ) ) ;
219
228
}
220
229
return decodedArray ;
221
230
} catch ( e ) {
@@ -259,13 +268,13 @@ export function option<Encodable, Decoded>(
259
268
throw new Error ( `option(${ e ?. toString ( ) } )` ) ;
260
269
}
261
270
} ,
262
- decode ( buffer ) {
271
+ decode ( buffer , config ) {
263
272
const value = bytesFrom ( buffer ) ;
264
273
if ( value . byteLength === 0 ) {
265
274
return undefined ;
266
275
}
267
276
try {
268
- return innerCodec . decode ( buffer ) ;
277
+ return innerCodec . decode ( buffer , config ) ;
269
278
} catch ( e ) {
270
279
throw new Error ( `option(${ e ?. toString ( ) } )` ) ;
271
280
}
@@ -290,7 +299,7 @@ export function byteVec<Encodable, Decoded>(
290
299
throw new Error ( `byteVec(${ e ?. toString ( ) } )` ) ;
291
300
}
292
301
} ,
293
- decode ( buffer ) {
302
+ decode ( buffer , config ) {
294
303
const value = bytesFrom ( buffer ) ;
295
304
if ( value . byteLength < 4 ) {
296
305
throw new Error (
@@ -304,7 +313,7 @@ export function byteVec<Encodable, Decoded>(
304
313
) ;
305
314
}
306
315
try {
307
- return codec . decode ( value . slice ( 4 ) ) ;
316
+ return codec . decode ( value . slice ( 4 ) , config ) ;
308
317
} catch ( e : unknown ) {
309
318
throw new Error ( `byteVec(${ e ?. toString ( ) } )` ) ;
310
319
}
@@ -371,15 +380,15 @@ export function table<
371
380
const packedTotalSize = uint32To ( header . length + body . length + 4 ) ;
372
381
return bytesConcat ( packedTotalSize , header , body ) ;
373
382
} ,
374
- decode ( buffer ) {
383
+ decode ( buffer , config ) {
375
384
const value = bytesFrom ( buffer ) ;
376
385
if ( value . byteLength < 4 ) {
377
386
throw new Error (
378
387
`table: too short buffer, expected at least 4 bytes, but got ${ value . byteLength } ` ,
379
388
) ;
380
389
}
381
390
const byteLength = uint32From ( value . slice ( 0 , 4 ) ) ;
382
- if ( byteLength !== value . byteLength ) {
391
+ if ( byteLength !== value . byteLength && ! config ?. compatible ) {
383
392
throw new Error (
384
393
`table: invalid buffer size, expected ${ byteLength } , but got ${ value . byteLength } ` ,
385
394
) ;
@@ -397,9 +406,13 @@ export function table<
397
406
const payload = value . slice ( start , end ) ;
398
407
try {
399
408
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
400
- Object . assign ( object , { [ field ] : codec . decode ( payload ) } ) ;
401
- } catch ( e : unknown ) {
402
- throw new Error ( `table.${ field } (${ e ?. toString ( ) } )` ) ;
409
+ Object . assign ( object , { [ field ] : codec . decode ( payload , config ) } ) ;
410
+ } catch ( _e : unknown ) {
411
+ if ( config ?. compatible ) {
412
+ Object . assign ( object , { [ field ] : null } ) ;
413
+ } else {
414
+ throw new Error ( `table.${ field } (${ _e ?. toString ( ) } )` ) ;
415
+ }
403
416
}
404
417
}
405
418
return object as Decoded ;
@@ -466,7 +479,7 @@ export function union<T extends Record<string, CodecLike<any, any>>>(
466
479
throw new Error ( `union.(${ typeStr } )(${ e ?. toString ( ) } )` ) ;
467
480
}
468
481
} ,
469
- decode ( buffer ) {
482
+ decode ( buffer , config ) {
470
483
const value = bytesFrom ( buffer ) ;
471
484
const fieldIndex = uint32From ( value . slice ( 0 , 4 ) ) ;
472
485
const keys = Object . keys ( codecLayout ) ;
@@ -496,7 +509,7 @@ export function union<T extends Record<string, CodecLike<any, any>>>(
496
509
return {
497
510
type : field ,
498
511
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
499
- value : codecLayout [ field ] . decode ( value . slice ( 4 ) ) ,
512
+ value : codecLayout [ field ] . decode ( value . slice ( 4 ) , config ) ,
500
513
} as UnionDecoded < T > ;
501
514
} ,
502
515
} ) ;
@@ -535,15 +548,15 @@ export function struct<
535
548
536
549
return bytesFrom ( bytes ) ;
537
550
} ,
538
- decode ( buffer ) {
551
+ decode ( buffer , config ) {
539
552
const value = bytesFrom ( buffer ) ;
540
553
const object = { } ;
541
554
let offset = 0 ;
542
555
Object . entries ( codecLayout ) . forEach ( ( [ key , codec ] ) => {
543
556
const payload = value . slice ( offset , offset + codec . byteLength ! ) ;
544
557
try {
545
558
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
546
- Object . assign ( object , { [ key ] : codec . decode ( payload ) } ) ;
559
+ Object . assign ( object , { [ key ] : codec . decode ( payload , config ) } ) ;
547
560
} catch ( e : unknown ) {
548
561
throw new Error ( `struct.${ key } (${ ( e as Error ) . toString ( ) } )` ) ;
549
562
}
@@ -583,7 +596,7 @@ export function array<Encodable, Decoded>(
583
596
throw new Error ( `array(${ e ?. toString ( ) } )` ) ;
584
597
}
585
598
} ,
586
- decode ( buffer ) {
599
+ decode ( buffer , config ) {
587
600
const value = bytesFrom ( buffer ) ;
588
601
if ( value . byteLength != byteLength ) {
589
602
throw new Error (
@@ -594,7 +607,7 @@ export function array<Encodable, Decoded>(
594
607
const result : Array < Decoded > = [ ] ;
595
608
for ( let i = 0 ; i < value . byteLength ; i += itemCodec . byteLength ! ) {
596
609
result . push (
597
- itemCodec . decode ( value . slice ( i , i + itemCodec . byteLength ! ) ) ,
610
+ itemCodec . decode ( value . slice ( i , i + itemCodec . byteLength ! ) , config ) ,
598
611
) ;
599
612
}
600
613
return result ;
0 commit comments