@@ -16,7 +16,7 @@ const TIMESTAMP32_MAX_SEC = 0x100000000; // 32-bit signed int
1616const TIMESTAMP64_MAX_SEC = 0x400000000 ; // 34-bit unsigned int
1717
1818export function encodeTimestampFromTimeSpec ( { sec, nsec } : TimeSpec ) : ReadonlyArray < number > {
19- if ( sec >= 0 && sec < TIMESTAMP64_MAX_SEC ) {
19+ if ( sec >= 0 && nsec >= 0 && sec < TIMESTAMP64_MAX_SEC ) {
2020 // Here sec >= 0 && nsec >= 0
2121 if ( nsec === 0 && sec < TIMESTAMP32_MAX_SEC ) {
2222 // timestamp 32 = { sec32 (unsigned) }
@@ -28,7 +28,7 @@ export function encodeTimestampFromTimeSpec({ sec, nsec }: TimeSpec): ReadonlyAr
2828 const secHigh = sec / 0x100000000 ;
2929 const secLow = sec & 0xffffffff ;
3030 const rv : Array < number > = [ ] ;
31- // nsec30 + secHigh2
31+ // nsec30 | secHigh2
3232 encodeUint32 ( rv , ( nsec << 2 ) | ( secHigh & 0x3 ) ) ;
3333 // secLow32
3434 encodeUint32 ( rv , secLow ) ;
@@ -67,7 +67,7 @@ export const decodeTimestampExtension: ExtensionDecoderType = (data: BufferType)
6767 // timestamp 64 = { nsec30, sec34 }
6868 const nsec30AndSecHigh2 = decodeUint32 ( data [ 0 ] , data [ 1 ] , data [ 2 ] , data [ 3 ] ) ;
6969 const secLow32 = decodeUint32 ( data [ 4 ] , data [ 5 ] , data [ 6 ] , data [ 7 ] ) ;
70- const nsec = nsec30AndSecHigh2 >> 2 ;
70+ const nsec = nsec30AndSecHigh2 >>> 2 ;
7171 const sec = ( nsec30AndSecHigh2 & 0x3 ) * 0x100000000 + secLow32 ;
7272 return new Date ( sec * 1000 + nsec / 1e6 ) ;
7373 }
@@ -86,18 +86,38 @@ export const decodeTimestampExtension: ExtensionDecoderType = (data: BufferType)
8686// extensionType is signed 8-bit integer
8787export type ExtensionDecoderType = ( data : BufferType , extensionType : number ) => any ;
8888
89- export type ExtensionEncoderType = ( input : unknown ) => ReadonlyArray < number > | null ;
89+ export type ExtensionEncoderType = ( input : unknown ) => BufferType | null ;
9090
9191// immutable interfce to ExtensionCodec
9292export type ExtensionCodecType = {
93- tryToEncode ( object : unknown ) : { type : number ; data : ReadonlyArray < number > } | null ;
93+ tryToEncode ( object : unknown ) : ExtDataType | null ;
9494 decode ( data : BufferType , extType : number ) : any ;
9595} ;
9696
97+ const $Extension = Symbol ( "MessagePack.extension" ) ;
98+
99+ export type ExtDataType = {
100+ [ $Extension ] : true ;
101+ type : number ;
102+ data : BufferType ;
103+ } ;
104+
97105export class ExtensionCodec implements ExtensionCodecType {
98106 public static readonly defaultCodec : ExtensionCodecType = new ExtensionCodec ( ) ;
99107
100- public static readonly Extension = Symbol ( "MessagePack.extension" ) ;
108+ public static readonly Extension = $Extension ;
109+
110+ public static createExtData ( type : number , data : BufferType ) : ExtDataType {
111+ return {
112+ [ $Extension ] : true ,
113+ type,
114+ data,
115+ } ;
116+ }
117+
118+ public static isExtData ( object : any ) : object is ExtDataType {
119+ return object != null && ! ! object [ ExtensionCodec . Extension ] ;
120+ }
101121
102122 // built-in extensions
103123 private readonly builtInEncoders : Array < ExtensionEncoderType > = [ ] ;
@@ -136,18 +156,15 @@ export class ExtensionCodec implements ExtensionCodecType {
136156 }
137157 }
138158
139- public tryToEncode ( object : unknown ) : { type : number ; data : ReadonlyArray < number > } | null {
159+ public tryToEncode ( object : unknown ) : ExtDataType | null {
140160 // built-in extensions
141161 for ( let i = 0 ; i < this . builtInEncoders . length ; i ++ ) {
142162 const encoder = this . builtInEncoders [ i ] ;
143163 if ( encoder != null ) {
144164 const data = encoder ( object ) ;
145165 if ( data != null ) {
146166 const type = - 1 - i ;
147- return {
148- type,
149- data,
150- } ;
167+ return ExtensionCodec . createExtData ( type , data ) ;
151168 }
152169 }
153170 }
@@ -159,26 +176,25 @@ export class ExtensionCodec implements ExtensionCodecType {
159176 const data = encoder ( object ) ;
160177 if ( data != null ) {
161178 const type = i ;
162- return {
163- type,
164- data,
165- } ;
179+ return ExtensionCodec . createExtData ( type , data ) ;
166180 }
167181 }
168182 }
183+
184+ if ( ExtensionCodec . isExtData ( object ) ) {
185+ // to keep ExtData as is
186+ return object ;
187+ }
169188 return null ;
170189 }
171190
172- public decode ( data : BufferType , type : number ) : any {
191+ public decode ( data : BufferType , type : number ) : unknown {
173192 const decoder = type < 0 ? this . builtInDecoders [ - 1 - type ] : this . decoders [ type ] ;
174193 if ( decoder ) {
175194 return decoder ( data , type ) ;
176195 } else {
177- return {
178- [ ExtensionCodec . Extension ] : true ,
179- type,
180- data,
181- } ;
196+ // decode() does not fail, returns ExtData instead.
197+ return ExtensionCodec . createExtData ( type , Array . from ( data ) ) ;
182198 }
183199 }
184200}
0 commit comments