@@ -210,3 +210,156 @@ def repr(self, list_of_items):
210210 if list_of_items is None :
211211 return 'NULL'
212212 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