11import { prettyByte } from "./utils/prettyByte" ;
22import { ExtensionCodec , ExtensionCodecType } from "./ExtensionCodec" ;
3- import { getInt64 , getUint64 , UINT32_MAX } from "./utils/int" ;
3+ import { IntMode , getInt64 , getUint64 , convertSafeIntegerToMode , UINT32_MAX } from "./utils/int" ;
44import { utf8Decode } from "./utils/utf8" ;
55import { createDataView , ensureUint8Array } from "./utils/typedArrays" ;
66import { CachedKeyDecoder , KeyDecoder } from "./CachedKeyDecoder" ;
@@ -16,10 +16,17 @@ export type DecoderOptions<ContextType = undefined> = Readonly<
1616 * Depends on ES2020's {@link DataView#getBigInt64} and
1717 * {@link DataView#getBigUint64}.
1818 *
19- * Defaults to false.
19+ * Defaults to false. If true, equivalent to intMode: IntMode.AS_ENCODED.
2020 */
2121 useBigInt64 : boolean ;
2222
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+
2330 /**
2431 * Maximum string length.
2532 *
@@ -194,7 +201,7 @@ const sharedCachedKeyDecoder = new CachedKeyDecoder();
194201export class Decoder < ContextType = undefined > {
195202 private readonly extensionCodec : ExtensionCodecType < ContextType > ;
196203 private readonly context : ContextType ;
197- private readonly useBigInt64 : boolean ;
204+ private readonly intMode : IntMode ;
198205 private readonly maxStrLength : number ;
199206 private readonly maxBinLength : number ;
200207 private readonly maxArrayLength : number ;
@@ -214,7 +221,7 @@ export class Decoder<ContextType = undefined> {
214221 this . extensionCodec = options ?. extensionCodec ?? ( ExtensionCodec . defaultCodec as ExtensionCodecType < ContextType > ) ;
215222 this . context = ( options as { context : ContextType } | undefined ) ?. context as ContextType ; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined
216223
217- this . useBigInt64 = options ?. useBigInt64 ?? false ;
224+ this . intMode = options ?. intMode ?? ( options ?. useBigInt64 ? IntMode . AS_ENCODED : IntMode . UNSAFE_NUMBER ) ;
218225 this . maxStrLength = options ?. maxStrLength ?? UINT32_MAX ;
219226 this . maxBinLength = options ?. maxBinLength ?? UINT32_MAX ;
220227 this . maxArrayLength = options ?. maxArrayLength ?? UINT32_MAX ;
@@ -371,11 +378,11 @@ export class Decoder<ContextType = undefined> {
371378
372379 if ( headByte >= 0xe0 ) {
373380 // negative fixint (111x xxxx) 0xe0 - 0xff
374- object = headByte - 0x100 ;
381+ object = this . convertNumber ( headByte - 0x100 ) ;
375382 } else if ( headByte < 0xc0 ) {
376383 if ( headByte < 0x80 ) {
377384 // positive fixint (0xxx xxxx) 0x00 - 0x7f
378- object = headByte ;
385+ object = this . convertNumber ( headByte ) ;
379386 } else if ( headByte < 0x90 ) {
380387 // fixmap (1000 xxxx) 0x80 - 0x8f
381388 const size = headByte - 0x80 ;
@@ -418,36 +425,28 @@ export class Decoder<ContextType = undefined> {
418425 object = this . readF64 ( ) ;
419426 } else if ( headByte === 0xcc ) {
420427 // uint 8
421- object = this . readU8 ( ) ;
428+ object = this . convertNumber ( this . readU8 ( ) ) ;
422429 } else if ( headByte === 0xcd ) {
423430 // uint 16
424- object = this . readU16 ( ) ;
431+ object = this . convertNumber ( this . readU16 ( ) ) ;
425432 } else if ( headByte === 0xce ) {
426433 // uint 32
427- object = this . readU32 ( ) ;
434+ object = this . convertNumber ( this . readU32 ( ) ) ;
428435 } else if ( headByte === 0xcf ) {
429436 // uint 64
430- if ( this . useBigInt64 ) {
431- object = this . readU64AsBigInt ( ) ;
432- } else {
433- object = this . readU64 ( ) ;
434- }
437+ object = this . readU64 ( ) ;
435438 } else if ( headByte === 0xd0 ) {
436439 // int 8
437- object = this . readI8 ( ) ;
440+ object = this . convertNumber ( this . readI8 ( ) ) ;
438441 } else if ( headByte === 0xd1 ) {
439442 // int 16
440- object = this . readI16 ( ) ;
443+ object = this . convertNumber ( this . readI16 ( ) ) ;
441444 } else if ( headByte === 0xd2 ) {
442445 // int 32
443- object = this . readI32 ( ) ;
446+ object = this . convertNumber ( this . readI32 ( ) ) ;
444447 } else if ( headByte === 0xd3 ) {
445448 // int 64
446- if ( this . useBigInt64 ) {
447- object = this . readI64AsBigInt ( ) ;
448- } else {
449- object = this . readI64 ( ) ;
450- }
449+ object = this . readI64 ( ) ;
451450 } else if ( headByte === 0xd9 ) {
452451 // str 8
453452 const byteLength = this . lookU8 ( ) ;
@@ -692,6 +691,10 @@ export class Decoder<ContextType = undefined> {
692691 return this . extensionCodec . decode ( data , extType , this . context ) ;
693692 }
694693
694+ private convertNumber ( value : number ) : number | bigint {
695+ return convertSafeIntegerToMode ( value , this . intMode ) ;
696+ }
697+
695698 private lookU8 ( ) {
696699 return this . view . getUint8 ( this . pos ) ;
697700 }
@@ -740,26 +743,14 @@ export class Decoder<ContextType = undefined> {
740743 return value ;
741744 }
742745
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 ) ;
757748 this . pos += 8 ;
758749 return value ;
759750 }
760751
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 ) ;
763754 this . pos += 8 ;
764755 return value ;
765756 }
0 commit comments