1
1
import { prettyByte } from "./utils/prettyByte" ;
2
2
import { ExtensionCodec , ExtensionCodecType } from "./ExtensionCodec" ;
3
- import { getInt64 , getUint64 , UINT32_MAX } from "./utils/int" ;
3
+ import { IntMode , getInt64 , getUint64 , convertSafeIntegerToMode , UINT32_MAX } from "./utils/int" ;
4
4
import { utf8Decode } from "./utils/utf8" ;
5
5
import { createDataView , ensureUint8Array } from "./utils/typedArrays" ;
6
6
import { CachedKeyDecoder , KeyDecoder } from "./CachedKeyDecoder" ;
@@ -16,10 +16,17 @@ export type DecoderOptions<ContextType = undefined> = Readonly<
16
16
* Depends on ES2020's {@link DataView#getBigInt64} and
17
17
* {@link DataView#getBigUint64}.
18
18
*
19
- * Defaults to false.
19
+ * Defaults to false. If true, equivalent to intMode: IntMode.AS_ENCODED.
20
20
*/
21
21
useBigInt64 : boolean ;
22
22
23
+ /**
24
+ * Allows for more fine-grained control of BigInt handling, overrides useBigInt64.
25
+ *
26
+ * Defaults to IntMode.AS_ENCODED if useBigInt64 is true or IntMode.UNSAFE_NUMBER otherwise.
27
+ */
28
+ intMode ?: IntMode ;
29
+
23
30
/**
24
31
* Maximum string length.
25
32
*
@@ -194,7 +201,7 @@ const sharedCachedKeyDecoder = new CachedKeyDecoder();
194
201
export class Decoder < ContextType = undefined > {
195
202
private readonly extensionCodec : ExtensionCodecType < ContextType > ;
196
203
private readonly context : ContextType ;
197
- private readonly useBigInt64 : boolean ;
204
+ private readonly intMode : IntMode ;
198
205
private readonly maxStrLength : number ;
199
206
private readonly maxBinLength : number ;
200
207
private readonly maxArrayLength : number ;
@@ -214,7 +221,7 @@ export class Decoder<ContextType = undefined> {
214
221
this . extensionCodec = options ?. extensionCodec ?? ( ExtensionCodec . defaultCodec as ExtensionCodecType < ContextType > ) ;
215
222
this . context = ( options as { context : ContextType } | undefined ) ?. context as ContextType ; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined
216
223
217
- this . useBigInt64 = options ?. useBigInt64 ?? false ;
224
+ this . intMode = options ?. intMode ?? options ?. useBigInt64 ? IntMode . AS_ENCODED : IntMode . UNSAFE_NUMBER ;
218
225
this . maxStrLength = options ?. maxStrLength ?? UINT32_MAX ;
219
226
this . maxBinLength = options ?. maxBinLength ?? UINT32_MAX ;
220
227
this . maxArrayLength = options ?. maxArrayLength ?? UINT32_MAX ;
@@ -371,11 +378,11 @@ export class Decoder<ContextType = undefined> {
371
378
372
379
if ( headByte >= 0xe0 ) {
373
380
// negative fixint (111x xxxx) 0xe0 - 0xff
374
- object = headByte - 0x100 ;
381
+ object = this . convertNumber ( headByte - 0x100 ) ;
375
382
} else if ( headByte < 0xc0 ) {
376
383
if ( headByte < 0x80 ) {
377
384
// positive fixint (0xxx xxxx) 0x00 - 0x7f
378
- object = headByte ;
385
+ object = this . convertNumber ( headByte ) ;
379
386
} else if ( headByte < 0x90 ) {
380
387
// fixmap (1000 xxxx) 0x80 - 0x8f
381
388
const size = headByte - 0x80 ;
@@ -418,36 +425,28 @@ export class Decoder<ContextType = undefined> {
418
425
object = this . readF64 ( ) ;
419
426
} else if ( headByte === 0xcc ) {
420
427
// uint 8
421
- object = this . readU8 ( ) ;
428
+ object = this . convertNumber ( this . readU8 ( ) ) ;
422
429
} else if ( headByte === 0xcd ) {
423
430
// uint 16
424
- object = this . readU16 ( ) ;
431
+ object = this . convertNumber ( this . readU16 ( ) ) ;
425
432
} else if ( headByte === 0xce ) {
426
433
// uint 32
427
- object = this . readU32 ( ) ;
434
+ object = this . convertNumber ( this . readU32 ( ) ) ;
428
435
} else if ( headByte === 0xcf ) {
429
436
// uint 64
430
- if ( this . useBigInt64 ) {
431
- object = this . readU64AsBigInt ( ) ;
432
- } else {
433
- object = this . readU64 ( ) ;
434
- }
437
+ object = this . readU64 ( ) ;
435
438
} else if ( headByte === 0xd0 ) {
436
439
// int 8
437
- object = this . readI8 ( ) ;
440
+ object = this . convertNumber ( this . readI8 ( ) ) ;
438
441
} else if ( headByte === 0xd1 ) {
439
442
// int 16
440
- object = this . readI16 ( ) ;
443
+ object = this . convertNumber ( this . readI16 ( ) ) ;
441
444
} else if ( headByte === 0xd2 ) {
442
445
// int 32
443
- object = this . readI32 ( ) ;
446
+ object = this . convertNumber ( this . readI32 ( ) ) ;
444
447
} else if ( headByte === 0xd3 ) {
445
448
// int 64
446
- if ( this . useBigInt64 ) {
447
- object = this . readI64AsBigInt ( ) ;
448
- } else {
449
- object = this . readI64 ( ) ;
450
- }
449
+ object = this . readI64 ( ) ;
451
450
} else if ( headByte === 0xd9 ) {
452
451
// str 8
453
452
const byteLength = this . lookU8 ( ) ;
@@ -692,6 +691,10 @@ export class Decoder<ContextType = undefined> {
692
691
return this . extensionCodec . decode ( data , extType , this . context ) ;
693
692
}
694
693
694
+ private convertNumber ( value : number ) : number | bigint {
695
+ return convertSafeIntegerToMode ( value , this . intMode ) ;
696
+ }
697
+
695
698
private lookU8 ( ) {
696
699
return this . view . getUint8 ( this . pos ) ;
697
700
}
@@ -740,26 +743,14 @@ export class Decoder<ContextType = undefined> {
740
743
return value ;
741
744
}
742
745
743
- private readU64 ( ) : number {
744
- const value = getUint64 ( this . view , this . pos ) ;
745
- this . pos += 8 ;
746
- return value ;
747
- }
748
-
749
- private readI64 ( ) : number {
750
- const value = getInt64 ( this . view , this . pos ) ;
751
- this . pos += 8 ;
752
- return value ;
753
- }
754
-
755
- private readU64AsBigInt ( ) : bigint {
756
- const value = this . view . getBigUint64 ( this . pos ) ;
746
+ private readU64 ( ) : number | bigint {
747
+ const value = getUint64 ( this . view , this . pos , this . intMode ) ;
757
748
this . pos += 8 ;
758
749
return value ;
759
750
}
760
751
761
- private readI64AsBigInt ( ) : bigint {
762
- const value = this . view . getBigInt64 ( this . pos ) ;
752
+ private readI64 ( ) : number | bigint {
753
+ const value = getInt64 ( this . view , this . pos , this . intMode ) ;
763
754
this . pos += 8 ;
764
755
return value ;
765
756
}
0 commit comments