@@ -210,3 +210,156 @@ def repr(self, list_of_items):
210
210
if list_of_items is None :
211
211
return 'NULL'
212
212
return '[' + ', ' .join ([self .array_of .repr (item ) for item in list_of_items ]) + ']'
213
+
214
+
215
+ class UnsignedVarInt32 (AbstractType ):
216
+ @classmethod
217
+ def decode (cls , data ):
218
+ value , i = 0 , 0
219
+ while True :
220
+ b , = struct .unpack ('B' , data .read (1 ))
221
+ if not (b & 0x80 ):
222
+ break
223
+ value |= (b & 0x7f ) << i
224
+ i += 7
225
+ if i > 28 :
226
+ raise ValueError ('Invalid value {}' .format (value ))
227
+ value |= b << i
228
+ return value
229
+
230
+ @classmethod
231
+ def encode (cls , value ):
232
+ value &= 0xffffffff
233
+ ret = b''
234
+ while (value & 0xffffff80 ) != 0 :
235
+ b = (value & 0x7f ) | 0x80
236
+ ret += struct .pack ('B' , b )
237
+ value >>= 7
238
+ ret += struct .pack ('B' , value )
239
+ return ret
240
+
241
+
242
+ class VarInt32 (AbstractType ):
243
+ @classmethod
244
+ def decode (cls , data ):
245
+ value = UnsignedVarInt32 .decode (data )
246
+ return (value >> 1 ) ^ - (value & 1 )
247
+
248
+ @classmethod
249
+ def encode (cls , value ):
250
+ # bring it in line with the java binary repr
251
+ value &= 0xffffffff
252
+ return UnsignedVarInt32 .encode ((value << 1 ) ^ (value >> 31 ))
253
+
254
+
255
+ class VarInt64 (AbstractType ):
256
+ @classmethod
257
+ def decode (cls , data ):
258
+ value , i = 0 , 0
259
+ while True :
260
+ b = data .read (1 )
261
+ if not (b & 0x80 ):
262
+ break
263
+ value |= (b & 0x7f ) << i
264
+ i += 7
265
+ if i > 63 :
266
+ raise ValueError ('Invalid value {}' .format (value ))
267
+ value |= b << i
268
+ return (value >> 1 ) ^ - (value & 1 )
269
+
270
+ @classmethod
271
+ def encode (cls , value ):
272
+ # bring it in line with the java binary repr
273
+ value &= 0xffffffffffffffff
274
+ v = (value << 1 ) ^ (value >> 63 )
275
+ ret = b''
276
+ while (v & 0xffffffffffffff80 ) != 0 :
277
+ b = (value & 0x7f ) | 0x80
278
+ ret += struct .pack ('B' , b )
279
+ v >>= 7
280
+ ret += struct .pack ('B' , v )
281
+ return ret
282
+
283
+
284
+ class CompactString (String ):
285
+ def decode (self , data ):
286
+ length = UnsignedVarInt32 .decode (data ) - 1
287
+ if length < 0 :
288
+ return None
289
+ value = data .read (length )
290
+ if len (value ) != length :
291
+ raise ValueError ('Buffer underrun decoding string' )
292
+ return value .decode (self .encoding )
293
+
294
+ def encode (self , value ):
295
+ if value is None :
296
+ return UnsignedVarInt32 .encode (0 )
297
+ value = str (value ).encode (self .encoding )
298
+ return UnsignedVarInt32 .encode (len (value ) + 1 ) + value
299
+
300
+
301
+ class TaggedFields (AbstractType ):
302
+ @classmethod
303
+ def decode (cls , data ):
304
+ num_fields = UnsignedVarInt32 .decode (data )
305
+ ret = {}
306
+ if not num_fields :
307
+ return ret
308
+ prev_tag = - 1
309
+ for i in range (num_fields ):
310
+ tag = UnsignedVarInt32 .decode (data )
311
+ if tag <= prev_tag :
312
+ raise ValueError ('Invalid or out-of-order tag {}' .format (tag ))
313
+ prev_tag = tag
314
+ size = UnsignedVarInt32 .decode (data )
315
+ val = data .read (size )
316
+ ret [tag ] = val
317
+ return ret
318
+
319
+ @classmethod
320
+ def encode (cls , value ):
321
+ ret = UnsignedVarInt32 .encode (len (value ))
322
+ for k , v in value .items ():
323
+ # do we allow for other data types ?? It could get complicated really fast
324
+ assert isinstance (v , bytes ), 'Value {} is not a byte array' .format (v )
325
+ assert isinstance (k , int ) and k > 0 , 'Key {} is not a positive integer' .format (k )
326
+ ret += UnsignedVarInt32 .encode (k )
327
+ ret += v
328
+ return ret
329
+
330
+
331
+ class CompactBytes (AbstractType ):
332
+ @classmethod
333
+ def decode (cls , data ):
334
+ length = UnsignedVarInt32 .decode (data ) - 1
335
+ if length < 0 :
336
+ return None
337
+ value = data .read (length )
338
+ if len (value ) != length :
339
+ raise ValueError ('Buffer underrun decoding Bytes' )
340
+ return value
341
+
342
+ @classmethod
343
+ def encode (cls , value ):
344
+ if value is None :
345
+ return UnsignedVarInt32 .encode (0 )
346
+ else :
347
+ return UnsignedVarInt32 .encode (len (value ) + 1 ) + value
348
+
349
+
350
+ class CompactArray (Array ):
351
+
352
+ def encode (self , items ):
353
+ if items is None :
354
+ return UnsignedVarInt32 .encode (0 )
355
+ return b'' .join (
356
+ [UnsignedVarInt32 .encode (len (items ) + 1 )] +
357
+ [self .array_of .encode (item ) for item in items ]
358
+ )
359
+
360
+ def decode (self , data ):
361
+ length = UnsignedVarInt32 .decode (data ) - 1
362
+ if length == - 1 :
363
+ return None
364
+ return [self .array_of .decode (data ) for _ in range (length )]
365
+
0 commit comments