@@ -26,7 +26,6 @@ export type WrapperOfCase<T extends { $: string }, K = T["$"]> = T extends { $:
2626
2727export interface Reader {
2828 readString ( ) : string
29- readBytes ( ) : Uint8Array
3029 readBool ( ) : boolean
3130 readUnit ( ) : null
3231 readChar ( ) : string
@@ -52,7 +51,6 @@ export interface Reader {
5251
5352export interface Writer {
5453 writeString ( value : string ) : void
55- writeBytes ( value : Uint8Array ) : void
5654 writeBool ( value : boolean ) : void
5755 writeUnit ( value : null ) : void
5856 writeChar ( value : string ) : void
@@ -76,135 +74,119 @@ export interface Writer {
7674 sortMapEntries ( offsets : number [ ] ) : void
7775}
7876
77+ const BIG_32 = 32n
78+ const BIG_64 = 64n
79+ const BIG_32Fs = 429967295n
80+ const BIG_64Fs = 18446744073709551615n
81+
7982export abstract class BinaryWriter implements Writer {
80- public static readonly BIG_32 = 32n
81- public static readonly BIG_64 = 64n
82- public static readonly BIG_32Fs = 429967295n
83- public static readonly BIG_64Fs = 18446744073709551615n
8483 public static readonly TEXT_ENCODER = new TextEncoder ( )
8584
86- public buffer = new ArrayBuffer ( 8 )
85+ public view = new DataView ( new ArrayBuffer ( 128 ) )
8786 public offset = 0
8887
89- private ensureBufferWillHandleSize ( bytes : number ) {
90- const wishSize = this . offset + bytes
91- if ( wishSize > this . buffer . byteLength ) {
92- let newBufferLength = this . buffer . byteLength
93- while ( newBufferLength < wishSize ) newBufferLength *= 2
88+ private alloc ( allocLength : number ) {
89+ const wishSize = this . offset + allocLength
90+
91+ const currentLength = this . view . buffer . byteLength
92+ if ( wishSize > currentLength ) {
93+ let newBufferLength = currentLength
94+ while ( newBufferLength <= wishSize ) newBufferLength = newBufferLength << 1
9495
9596 // TODO: there is new API for resizing buffer, but in Node it seems to be slower then allocating new
9697 // this.buffer.resize(newBufferLength)
9798
9899 const newBuffer = new Uint8Array ( newBufferLength )
99- newBuffer . set ( new Uint8Array ( this . buffer ) )
100- this . buffer = newBuffer . buffer
100+ newBuffer . set ( new Uint8Array ( this . view . buffer ) )
101+
102+ this . view = new DataView ( newBuffer . buffer )
101103 }
102104 }
103105
104- protected write ( values : Uint8Array ) {
105- this . ensureBufferWillHandleSize ( values . length )
106- new Uint8Array ( this . buffer , this . offset ) . set ( values )
107- this . offset += values . length
108- }
109-
110106 abstract writeLength ( value : number ) : void
111107 abstract writeVariantIndex ( value : number ) : void
112108 abstract sortMapEntries ( offsets : number [ ] ) : void
113109
114110 public writeString ( value : string ) {
115111 const bytes = value . length * 3 + 8
116- this . ensureBufferWillHandleSize ( bytes )
112+ this . alloc ( bytes )
117113 // TODO: check this for correctness
118- const { written } = BinaryWriter . TEXT_ENCODER . encodeInto ( value , new Uint8Array ( this . buffer , this . offset + 8 ) )
114+ const { written } = BinaryWriter . TEXT_ENCODER . encodeInto ( value , new Uint8Array ( this . view . buffer , this . offset + 8 ) )
119115 this . writeU64 ( written )
120116 this . offset += written
121117 }
122118
123- public writeBytes ( value : Uint8Array ) {
124- this . writeLength ( value . length )
125- this . write ( value )
126- }
127-
128119 public writeBool ( value : boolean ) {
129- const byteValue = value ? 1 : 0
130- this . write ( new Uint8Array ( [ byteValue ] ) )
120+ this . writeU8 ( value ? 1 : 0 )
131121 }
132122
133123 // eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/explicit-module-boundary-types
134124 public writeUnit ( _value : null ) {
135125 return
136126 }
137127
138- private writeWithFunction ( fn : ( byteOffset : number , value : number , littleEndian : boolean ) => void , bytesLength : number , value : number ) {
139- this . ensureBufferWillHandleSize ( bytesLength )
140- const dv = new DataView ( this . buffer , this . offset )
141- fn . apply ( dv , [ 0 , value , true ] )
142- this . offset += bytesLength
143- }
144-
145128 public writeU8 ( value : number ) {
146- this . write ( new Uint8Array ( [ value ] ) )
129+ this . alloc ( 1 )
130+ this . view . setUint8 ( this . offset , value )
131+ this . offset += 1
147132 }
148133
149134 public writeU16 ( value : number ) {
150- this . writeWithFunction ( DataView . prototype . setUint16 , 2 , value )
135+ this . alloc ( 2 )
136+ this . view . setUint16 ( this . offset , value , true )
137+ this . offset += 2
151138 }
152139
153140 public writeU32 ( value : number ) {
154- this . writeWithFunction ( DataView . prototype . setUint32 , 4 , value )
141+ this . alloc ( 4 )
142+ this . view . setUint32 ( this . offset , value , true )
143+ this . offset += 4
155144 }
156145
157146 public writeU64 ( value : bigint | number ) {
158- const low = BigInt ( value ) & BinaryWriter . BIG_32Fs ,
159- high = BigInt ( value ) >> BinaryWriter . BIG_32
147+ const low = BigInt ( value ) & BIG_32Fs , high = BigInt ( value ) >> BIG_32
160148
161149 // write little endian number
162150 this . writeU32 ( Number ( low ) )
163151 this . writeU32 ( Number ( high ) )
164152 }
165153
166154 public writeU128 ( value : bigint | number ) {
167- const low = BigInt ( value ) & BinaryWriter . BIG_64Fs ,
168- high = BigInt ( value ) >> BinaryWriter . BIG_64
155+ const low = BigInt ( value ) & BIG_64Fs , high = BigInt ( value ) >> BIG_64
169156
170157 // write little endian number
171158 this . writeU64 ( low )
172159 this . writeU64 ( high )
173160 }
174161
175162 public writeI8 ( value : number ) {
176- const bytes = 1
177- this . ensureBufferWillHandleSize ( bytes )
178- new DataView ( this . buffer , this . offset ) . setInt8 ( 0 , value )
179- this . offset += bytes
163+ this . alloc ( 1 )
164+ this . view . setInt8 ( this . offset , value )
165+ this . offset += 1
180166 }
181167
182168 public writeI16 ( value : number ) {
183- const bytes = 2
184- this . ensureBufferWillHandleSize ( bytes )
185- new DataView ( this . buffer , this . offset ) . setInt16 ( 0 , value , true )
186- this . offset += bytes
169+ this . alloc ( 2 )
170+ this . view . setInt16 ( this . offset , value , true )
171+ this . offset += 2
187172 }
188173
189174 public writeI32 ( value : number ) {
190- const bytes = 4
191- this . ensureBufferWillHandleSize ( bytes )
192- new DataView ( this . buffer , this . offset ) . setInt32 ( 0 , value , true )
193- this . offset += bytes
175+ this . alloc ( 4 )
176+ this . view . setInt32 ( this . offset , value , true )
177+ this . offset += 4
194178 }
195179
196180 public writeI64 ( value : bigint | number ) {
197- const low = BigInt ( value ) & BinaryWriter . BIG_32Fs ,
198- high = BigInt ( value ) >> BinaryWriter . BIG_32
181+ const low = BigInt ( value ) & BIG_32Fs , high = BigInt ( value ) >> BIG_32
199182
200183 // write little endian number
201184 this . writeI32 ( Number ( low ) )
202185 this . writeI32 ( Number ( high ) )
203186 }
204187
205188 public writeI128 ( value : bigint | number ) {
206- const low = BigInt ( value ) & BinaryWriter . BIG_64Fs ,
207- high = BigInt ( value ) >> BinaryWriter . BIG_64
189+ const low = BigInt ( value ) & BIG_64Fs , high = BigInt ( value ) >> BIG_64
208190
209191 // write little endian number
210192 this . writeI64 ( low )
@@ -227,116 +209,116 @@ export abstract class BinaryWriter implements Writer {
227209 }
228210
229211 public writeF32 ( value : number ) {
230- const bytes = 4
231- this . ensureBufferWillHandleSize ( bytes )
232- new DataView ( this . buffer , this . offset ) . setFloat32 ( 0 , value , true )
233- this . offset += bytes
212+ this . alloc ( 4 )
213+ this . view . setFloat32 ( this . offset , value , true )
214+ this . offset += 4
234215 }
235216
236217 public writeF64 ( value : number ) {
237- const bytes = 8
238- this . ensureBufferWillHandleSize ( bytes )
239- new DataView ( this . buffer , this . offset ) . setFloat64 ( 0 , value , true )
240- this . offset += bytes
218+ this . alloc ( 8 )
219+ this . view . setFloat64 ( this . offset , value , true )
220+ this . offset += 8
241221 }
242222
243223 public writeChar ( _value : string ) {
244224 throw new Error ( "Method serializeChar not implemented." )
245225 }
246226
247227 public getBytes ( ) {
248- return new Uint8Array ( this . buffer . slice ( 0 , this . offset ) )
228+ return new Uint8Array ( this . view . buffer ) . slice ( 0 , this . offset )
249229 }
250230}
251231
252232export abstract class BinaryReader implements Reader {
253- private static readonly BIG_32 = 32n
254- private static readonly BIG_64 = 64n
255233 private static readonly TEXT_DECODER = new TextDecoder ( )
256234
257- public buffer : ArrayBuffer
258235 public offset = 0
236+ public view : DataView
259237
260238 constructor ( data : Uint8Array ) {
261239 // copies data to prevent outside mutation of buffer.
262- this . buffer = new ArrayBuffer ( data . length )
263- new Uint8Array ( this . buffer ) . set ( data , 0 )
264- }
265-
266- private read ( length : number ) {
267- return this . buffer . slice ( this . offset , ( this . offset = this . offset + length ) )
240+ const buffer = new ArrayBuffer ( data . length )
241+ new Uint8Array ( buffer ) . set ( data , 0 )
242+ this . view = new DataView ( buffer )
268243 }
269244
270245 abstract readLength ( ) : number
271246 abstract readVariantIndex ( ) : number
272247 abstract checkThatKeySlicesAreIncreasing ( key1 : [ number , number ] , key2 : [ number , number ] ) : void
273248
274249 public readString ( ) {
275- return BinaryReader . TEXT_DECODER . decode ( this . readBytes ( ) )
276- }
277-
278- public readBytes ( ) {
279- const len = this . readLength ( )
280- if ( len < 0 ) {
281- throw new Error ( "Length of a bytes array can't be negative" )
282- }
283- return new Uint8Array ( this . read ( len ) )
250+ const length = this . readLength ( )
251+ const decoded = BinaryReader . TEXT_DECODER . decode ( new Uint8Array ( this . view . buffer , this . offset , length ) )
252+ this . offset += length
253+ return decoded
284254 }
285255
286256 public readBool ( ) {
287- return new Uint8Array ( this . read ( 1 ) ) [ 0 ] === 1
257+ return this . readU8 ( ) === 1
288258 }
289259
290260 public readUnit ( ) {
291261 return null
292262 }
293263
294264 public readU8 ( ) {
295- return new DataView ( this . read ( 1 ) ) . getUint8 ( 0 )
265+ const value = this . view . getUint8 ( this . offset )
266+ this . offset += 1
267+ return value
296268 }
297269
298270 public readU16 ( ) {
299- return new DataView ( this . read ( 2 ) ) . getUint16 ( 0 , true )
271+ const value = this . view . getUint16 ( this . offset , true )
272+ this . offset += 2
273+ return value
300274 }
301275
302276 public readU32 ( ) {
303- return new DataView ( this . read ( 4 ) ) . getUint32 ( 0 , true )
277+ const value = this . view . getUint32 ( this . offset , true )
278+ this . offset += 4
279+ return value
304280 }
305281
306282 public readU64 ( ) {
307283 const low = this . readU32 ( ) , high = this . readU32 ( )
308284 // combine the two 32-bit values and return (little endian)
309- return ( BigInt ( high ) << BinaryReader . BIG_32 ) | BigInt ( low )
285+ return ( BigInt ( high ) << BIG_32 ) | BigInt ( low )
310286 }
311287
312288 public readU128 ( ) {
313289 const low = this . readU64 ( ) , high = this . readU64 ( )
314290 // combine the two 64-bit values and return (little endian)
315- return ( high << BinaryReader . BIG_64 ) | low
291+ return ( high << BIG_64 ) | low
316292 }
317293
318294 public readI8 ( ) {
319- return new DataView ( this . read ( 1 ) ) . getInt8 ( 0 )
295+ const value = this . view . getInt8 ( this . offset )
296+ this . offset += 1
297+ return value
320298 }
321299
322300 public readI16 ( ) {
323- return new DataView ( this . read ( 2 ) ) . getInt16 ( 0 , true )
301+ const value = this . view . getInt16 ( this . offset , true )
302+ this . offset += 2
303+ return value
324304 }
325305
326306 public readI32 ( ) {
327- return new DataView ( this . read ( 4 ) ) . getInt32 ( 0 , true )
307+ const value = this . view . getInt32 ( this . offset , true )
308+ this . offset += 4
309+ return value
328310 }
329311
330312 public readI64 ( ) {
331313 const low = this . readI32 ( ) , high = this . readI32 ( )
332314 // combine the two 32-bit values and return (little endian)
333- return ( BigInt ( high ) << BinaryReader . BIG_32 ) | BigInt ( low )
315+ return ( BigInt ( high ) << BIG_32 ) | BigInt ( low )
334316 }
335317
336318 public readI128 ( ) {
337319 const low = this . readI64 ( ) , high = this . readI64 ( )
338320 // combine the two 64-bit values and return (little endian)
339- return ( high << BinaryReader . BIG_64 ) | low
321+ return ( high << BIG_64 ) | low
340322 }
341323
342324 public readOptionTag = this . readBool
@@ -367,10 +349,14 @@ export abstract class BinaryReader implements Reader {
367349 }
368350
369351 public readF32 ( ) {
370- return new DataView ( this . read ( 4 ) ) . getFloat32 ( 0 , true )
352+ const value = this . view . getFloat32 ( this . offset , true )
353+ this . offset += 4
354+ return value
371355 }
372356
373357 public readF64 ( ) {
374- return new DataView ( this . read ( 8 ) ) . getFloat64 ( 0 , true )
358+ const value = this . view . getFloat64 ( this . offset , true )
359+ this . offset += 8
360+ return value
375361 }
376362}
0 commit comments