xref: /aosp_15_r20/external/angle/third_party/logdog/logdog/varint.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1# Copyright 2016 The LUCI Authors. All rights reserved.
2# Use of this source code is governed under the Apache License, Version 2.0
3# that can be found in the LICENSE file.
4
5import os
6import struct
7import sys
8
9
10def write_uvarint(w, val):
11    """Writes a varint value to the supplied file-like object.
12
13  Args:
14    w (object): A file-like object to write to. Must implement write.
15    val (number): The value to write. Must be >= 0.
16
17  Returns (int): The number of bytes that were written.
18
19  Raises:
20    ValueError if 'val' is < 0.
21  """
22    if val < 0:
23        raise ValueError('Cannot encode negative value, %d' % (val,))
24
25    count = 0
26    while val > 0 or count == 0:
27        byte = (val & 0b01111111)
28        val >>= 7
29        if val > 0:
30            byte |= 0b10000000
31
32        w.write(struct.pack('B', byte))
33        count += 1
34    return count
35
36
37def read_uvarint(r):
38    """Reads a uvarint from a stream.
39
40  This is targeted towards testing, and will not be used in production code.
41
42  Args:
43    r (object): A file-like object to read from. Must implement read.
44
45  Returns: (value, count)
46    value (int): The decoded varint number.
47    count (int): The number of bytes that were read from 'r'.
48
49  Raises:
50    ValueError if the encoded varint is not terminated.
51  """
52    count = 0
53    result = 0
54    while True:
55        byte = r.read(1)
56        if len(byte) == 0:
57            raise ValueError('UVarint was not terminated')
58
59        byte = struct.unpack('B', byte)[0]
60        result |= ((byte & 0b01111111) << (7 * count))
61        count += 1
62        if byte & 0b10000000 == 0:
63            break
64    return result, count
65