Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 1 | # Lint as: python3 |
| 2 | # Copyright 2020 Google Inc. All rights reserved. |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | """Implementation of FlexBuffers binary format. |
| 16 | |
| 17 | For more info check https://google.github.io/flatbuffers/flexbuffers.html and |
| 18 | corresponding C++ implementation at |
| 19 | https://github.com/google/flatbuffers/blob/master/include/flatbuffers/flexbuffers.h |
| 20 | """ |
| 21 | |
| 22 | # pylint: disable=invalid-name |
| 23 | # TODO(dkovalev): Add type hints everywhere, so tools like pytypes could work. |
| 24 | |
| 25 | import array |
| 26 | import contextlib |
| 27 | import enum |
| 28 | import struct |
| 29 | |
| 30 | __all__ = ('Type', 'Builder', 'GetRoot', 'Dumps', 'Loads') |
| 31 | |
| 32 | |
| 33 | class BitWidth(enum.IntEnum): |
| 34 | """Supported bit widths of value types. |
| 35 | |
| 36 | These are used in the lower 2 bits of a type field to determine the size of |
| 37 | the elements (and or size field) of the item pointed to (e.g. vector). |
| 38 | """ |
| 39 | W8 = 0 # 2^0 = 1 byte |
| 40 | W16 = 1 # 2^1 = 2 bytes |
| 41 | W32 = 2 # 2^2 = 4 bytes |
| 42 | W64 = 3 # 2^3 = 8 bytes |
| 43 | |
| 44 | @staticmethod |
| 45 | def U(value): |
| 46 | """Returns the minimum `BitWidth` to encode unsigned integer value.""" |
| 47 | assert value >= 0 |
| 48 | |
| 49 | if value < (1 << 8): |
| 50 | return BitWidth.W8 |
| 51 | elif value < (1 << 16): |
| 52 | return BitWidth.W16 |
| 53 | elif value < (1 << 32): |
| 54 | return BitWidth.W32 |
| 55 | elif value < (1 << 64): |
| 56 | return BitWidth.W64 |
| 57 | else: |
| 58 | raise ValueError('value is too big to encode: %s' % value) |
| 59 | |
| 60 | @staticmethod |
| 61 | def I(value): |
| 62 | """Returns the minimum `BitWidth` to encode signed integer value.""" |
| 63 | # -2^(n-1) <= value < 2^(n-1) |
| 64 | # -2^n <= 2 * value < 2^n |
| 65 | # 2 * value < 2^n, when value >= 0 or 2 * (-value) <= 2^n, when value < 0 |
| 66 | # 2 * value < 2^n, when value >= 0 or 2 * (-value) - 1 < 2^n, when value < 0 |
| 67 | # |
| 68 | # if value >= 0: |
| 69 | # return BitWidth.U(2 * value) |
| 70 | # else: |
| 71 | # return BitWidth.U(2 * (-value) - 1) # ~x = -x - 1 |
| 72 | value *= 2 |
| 73 | return BitWidth.U(value if value >= 0 else ~value) |
| 74 | |
| 75 | @staticmethod |
| 76 | def F(value): |
| 77 | """Returns the `BitWidth` to encode floating point value.""" |
| 78 | if struct.unpack('f', struct.pack('f', value))[0] == value: |
| 79 | return BitWidth.W32 |
| 80 | return BitWidth.W64 |
| 81 | |
| 82 | @staticmethod |
| 83 | def B(byte_width): |
| 84 | return { |
| 85 | 1: BitWidth.W8, |
| 86 | 2: BitWidth.W16, |
| 87 | 4: BitWidth.W32, |
| 88 | 8: BitWidth.W64 |
| 89 | }[byte_width] |
| 90 | |
| 91 | |
| 92 | I = {1: 'b', 2: 'h', 4: 'i', 8: 'q'} # Integer formats |
| 93 | U = {1: 'B', 2: 'H', 4: 'I', 8: 'Q'} # Unsigned integer formats |
| 94 | F = {4: 'f', 8: 'd'} # Floating point formats |
| 95 | |
| 96 | |
| 97 | def _Unpack(fmt, buf): |
| 98 | return struct.unpack(fmt[len(buf)], buf)[0] |
| 99 | |
| 100 | |
| 101 | def _UnpackVector(fmt, buf, length): |
| 102 | byte_width = len(buf) // length |
| 103 | return struct.unpack('%d%s' % (length, fmt[byte_width]), buf) |
| 104 | |
| 105 | |
| 106 | def _Pack(fmt, value, byte_width): |
| 107 | return struct.pack(fmt[byte_width], value) |
| 108 | |
| 109 | |
| 110 | def _PackVector(fmt, values, byte_width): |
| 111 | return struct.pack('%d%s' % (len(values), fmt[byte_width]), *values) |
| 112 | |
| 113 | |
| 114 | def _Mutate(fmt, buf, value, byte_width, value_bit_width): |
| 115 | if (1 << value_bit_width) <= byte_width: |
| 116 | buf[:byte_width] = _Pack(fmt, value, byte_width) |
| 117 | return True |
| 118 | return False |
| 119 | |
| 120 | |
| 121 | # Computes how many bytes you'd have to pad to be able to write an |
| 122 | # "scalar_size" scalar if the buffer had grown to "buf_size", |
| 123 | # "scalar_size" is a power of two. |
| 124 | def _PaddingBytes(buf_size, scalar_size): |
| 125 | # ((buf_size + (scalar_size - 1)) // scalar_size) * scalar_size - buf_size |
| 126 | return -buf_size & (scalar_size - 1) |
| 127 | |
| 128 | |
| 129 | def _ShiftSlice(s, offset, length): |
| 130 | start = offset + (0 if s.start is None else s.start) |
| 131 | stop = offset + (length if s.stop is None else s.stop) |
| 132 | return slice(start, stop, s.step) |
| 133 | |
| 134 | |
| 135 | # https://en.cppreference.com/w/cpp/algorithm/lower_bound |
| 136 | def _LowerBound(values, value, pred): |
| 137 | """Implementation of C++ std::lower_bound() algorithm.""" |
| 138 | first, last = 0, len(values) |
| 139 | count = last - first |
| 140 | while count > 0: |
| 141 | i = first |
| 142 | step = count // 2 |
| 143 | i += step |
| 144 | if pred(values[i], value): |
| 145 | i += 1 |
| 146 | first = i |
| 147 | count -= step + 1 |
| 148 | else: |
| 149 | count = step |
| 150 | return first |
| 151 | |
| 152 | |
| 153 | # https://en.cppreference.com/w/cpp/algorithm/binary_search |
| 154 | def _BinarySearch(values, value, pred=lambda x, y: x < y): |
| 155 | """Implementation of C++ std::binary_search() algorithm.""" |
| 156 | index = _LowerBound(values, value, pred) |
| 157 | if index != len(values) and not pred(value, values[index]): |
| 158 | return index |
| 159 | return -1 |
| 160 | |
| 161 | |
| 162 | class Type(enum.IntEnum): |
| 163 | """Supported types of encoded data. |
| 164 | |
| 165 | These are used as the upper 6 bits of a type field to indicate the actual |
| 166 | type. |
| 167 | """ |
| 168 | NULL = 0 |
| 169 | INT = 1 |
| 170 | UINT = 2 |
| 171 | FLOAT = 3 |
| 172 | # Types above stored inline, types below store an offset. |
| 173 | KEY = 4 |
| 174 | STRING = 5 |
| 175 | INDIRECT_INT = 6 |
| 176 | INDIRECT_UINT = 7 |
| 177 | INDIRECT_FLOAT = 8 |
| 178 | MAP = 9 |
| 179 | VECTOR = 10 # Untyped. |
| 180 | |
| 181 | VECTOR_INT = 11 # Typed any size (stores no type table). |
| 182 | VECTOR_UINT = 12 |
| 183 | VECTOR_FLOAT = 13 |
| 184 | VECTOR_KEY = 14 |
| 185 | # DEPRECATED, use VECTOR or VECTOR_KEY instead. |
| 186 | # Read test.cpp/FlexBuffersDeprecatedTest() for details on why. |
| 187 | VECTOR_STRING_DEPRECATED = 15 |
| 188 | |
| 189 | VECTOR_INT2 = 16 # Typed tuple (no type table, no size field). |
| 190 | VECTOR_UINT2 = 17 |
| 191 | VECTOR_FLOAT2 = 18 |
| 192 | VECTOR_INT3 = 19 # Typed triple (no type table, no size field). |
| 193 | VECTOR_UINT3 = 20 |
| 194 | VECTOR_FLOAT3 = 21 |
| 195 | VECTOR_INT4 = 22 # Typed quad (no type table, no size field). |
| 196 | VECTOR_UINT4 = 23 |
| 197 | VECTOR_FLOAT4 = 24 |
| 198 | |
| 199 | BLOB = 25 |
| 200 | BOOL = 26 |
| 201 | VECTOR_BOOL = 36 # To do the same type of conversion of type to vector type |
| 202 | |
| 203 | @staticmethod |
| 204 | def Pack(type_, bit_width): |
| 205 | return (int(type_) << 2) | bit_width |
| 206 | |
| 207 | @staticmethod |
| 208 | def Unpack(packed_type): |
| 209 | return 1 << (packed_type & 0b11), Type(packed_type >> 2) |
| 210 | |
| 211 | @staticmethod |
| 212 | def IsInline(type_): |
| 213 | return type_ <= Type.FLOAT or type_ == Type.BOOL |
| 214 | |
| 215 | @staticmethod |
| 216 | def IsTypedVector(type_): |
| 217 | return Type.VECTOR_INT <= type_ <= Type.VECTOR_STRING_DEPRECATED or \ |
| 218 | type_ == Type.VECTOR_BOOL |
| 219 | |
| 220 | @staticmethod |
| 221 | def IsTypedVectorElementType(type_): |
| 222 | return Type.INT <= type_ <= Type.STRING or type_ == Type.BOOL |
| 223 | |
| 224 | @staticmethod |
| 225 | def ToTypedVectorElementType(type_): |
| 226 | if not Type.IsTypedVector(type_): |
| 227 | raise ValueError('must be typed vector type') |
| 228 | |
| 229 | return Type(type_ - Type.VECTOR_INT + Type.INT) |
| 230 | |
| 231 | @staticmethod |
| 232 | def IsFixedTypedVector(type_): |
| 233 | return Type.VECTOR_INT2 <= type_ <= Type.VECTOR_FLOAT4 |
| 234 | |
| 235 | @staticmethod |
| 236 | def IsFixedTypedVectorElementType(type_): |
| 237 | return Type.INT <= type_ <= Type.FLOAT |
| 238 | |
| 239 | @staticmethod |
| 240 | def ToFixedTypedVectorElementType(type_): |
| 241 | if not Type.IsFixedTypedVector(type_): |
| 242 | raise ValueError('must be fixed typed vector type') |
| 243 | |
| 244 | # 3 types each, starting from length 2. |
| 245 | fixed_type = type_ - Type.VECTOR_INT2 |
| 246 | return Type(fixed_type % 3 + Type.INT), fixed_type // 3 + 2 |
| 247 | |
| 248 | @staticmethod |
| 249 | def ToTypedVector(element_type, fixed_len=0): |
| 250 | """Converts element type to corresponding vector type. |
| 251 | |
| 252 | Args: |
| 253 | element_type: vector element type |
| 254 | fixed_len: number of elements: 0 for typed vector; 2, 3, or 4 for fixed |
| 255 | typed vector. |
| 256 | |
| 257 | Returns: |
| 258 | Typed vector type or fixed typed vector type. |
| 259 | """ |
| 260 | if fixed_len == 0: |
| 261 | if not Type.IsTypedVectorElementType(element_type): |
| 262 | raise ValueError('must be typed vector element type') |
| 263 | else: |
| 264 | if not Type.IsFixedTypedVectorElementType(element_type): |
| 265 | raise ValueError('must be fixed typed vector element type') |
| 266 | |
| 267 | offset = element_type - Type.INT |
| 268 | if fixed_len == 0: |
| 269 | return Type(offset + Type.VECTOR_INT) # TypedVector |
| 270 | elif fixed_len == 2: |
| 271 | return Type(offset + Type.VECTOR_INT2) # FixedTypedVector |
| 272 | elif fixed_len == 3: |
| 273 | return Type(offset + Type.VECTOR_INT3) # FixedTypedVector |
| 274 | elif fixed_len == 4: |
| 275 | return Type(offset + Type.VECTOR_INT4) # FixedTypedVector |
| 276 | else: |
| 277 | raise ValueError('unsupported fixed_len: %s' % fixed_len) |
| 278 | |
| 279 | |
| 280 | class Buf: |
| 281 | """Class to access underlying buffer object starting from the given offset.""" |
| 282 | |
| 283 | def __init__(self, buf, offset): |
| 284 | self._buf = buf |
| 285 | self._offset = offset if offset >= 0 else len(buf) + offset |
| 286 | self._length = len(buf) - self._offset |
| 287 | |
| 288 | def __getitem__(self, key): |
| 289 | if isinstance(key, slice): |
| 290 | return self._buf[_ShiftSlice(key, self._offset, self._length)] |
| 291 | elif isinstance(key, int): |
| 292 | return self._buf[self._offset + key] |
| 293 | else: |
| 294 | raise TypeError('invalid key type') |
| 295 | |
| 296 | def __setitem__(self, key, value): |
| 297 | if isinstance(key, slice): |
| 298 | self._buf[_ShiftSlice(key, self._offset, self._length)] = value |
| 299 | elif isinstance(key, int): |
| 300 | self._buf[self._offset + key] = key |
| 301 | else: |
| 302 | raise TypeError('invalid key type') |
| 303 | |
| 304 | def __repr__(self): |
| 305 | return 'buf[%d:]' % self._offset |
| 306 | |
| 307 | def Find(self, sub): |
| 308 | """Returns the lowest index where the sub subsequence is found.""" |
| 309 | return self._buf[self._offset:].find(sub) |
| 310 | |
| 311 | def Slice(self, offset): |
| 312 | """Returns new `Buf` which starts from the given offset.""" |
| 313 | return Buf(self._buf, self._offset + offset) |
| 314 | |
| 315 | def Indirect(self, offset, byte_width): |
| 316 | """Return new `Buf` based on the encoded offset (indirect encoding).""" |
| 317 | return self.Slice(offset - _Unpack(U, self[offset:offset + byte_width])) |
| 318 | |
| 319 | |
| 320 | class Object: |
| 321 | """Base class for all non-trivial data accessors.""" |
| 322 | __slots__ = '_buf', '_byte_width' |
| 323 | |
| 324 | def __init__(self, buf, byte_width): |
| 325 | self._buf = buf |
| 326 | self._byte_width = byte_width |
| 327 | |
| 328 | @property |
| 329 | def ByteWidth(self): |
| 330 | return self._byte_width |
| 331 | |
| 332 | |
| 333 | class Sized(Object): |
| 334 | """Base class for all data accessors which need to read encoded size.""" |
| 335 | __slots__ = '_size', |
| 336 | |
| 337 | def __init__(self, buf, byte_width, size=0): |
| 338 | super().__init__(buf, byte_width) |
| 339 | if size == 0: |
| 340 | self._size = _Unpack(U, self.SizeBytes) |
| 341 | else: |
| 342 | self._size = size |
| 343 | |
| 344 | @property |
| 345 | def SizeBytes(self): |
| 346 | return self._buf[-self._byte_width:0] |
| 347 | |
| 348 | def __len__(self): |
| 349 | return self._size |
| 350 | |
| 351 | |
| 352 | class Blob(Sized): |
| 353 | """Data accessor for the encoded blob bytes.""" |
| 354 | __slots__ = () |
| 355 | |
| 356 | @property |
| 357 | def Bytes(self): |
| 358 | return self._buf[0:len(self)] |
| 359 | |
| 360 | def __repr__(self): |
| 361 | return 'Blob(%s, size=%d)' % (self._buf, len(self)) |
| 362 | |
| 363 | |
| 364 | class String(Sized): |
| 365 | """Data accessor for the encoded string bytes.""" |
| 366 | __slots__ = () |
| 367 | |
| 368 | @property |
| 369 | def Bytes(self): |
| 370 | return self._buf[0:len(self)] |
| 371 | |
| 372 | def Mutate(self, value): |
| 373 | """Mutates underlying string bytes in place. |
| 374 | |
| 375 | Args: |
| 376 | value: New string to replace the existing one. New string must have less |
| 377 | or equal UTF-8-encoded bytes than the existing one to successfully |
| 378 | mutate underlying byte buffer. |
| 379 | |
| 380 | Returns: |
| 381 | Whether the value was mutated or not. |
| 382 | """ |
| 383 | encoded = value.encode('utf-8') |
| 384 | n = len(encoded) |
| 385 | if n <= len(self): |
| 386 | self._buf[-self._byte_width:0] = _Pack(U, n, self._byte_width) |
| 387 | self._buf[0:n] = encoded |
| 388 | self._buf[n:len(self)] = bytearray(len(self) - n) |
| 389 | return True |
| 390 | return False |
| 391 | |
| 392 | def __str__(self): |
| 393 | return self.Bytes.decode('utf-8') |
| 394 | |
| 395 | def __repr__(self): |
| 396 | return 'String(%s, size=%d)' % (self._buf, len(self)) |
| 397 | |
| 398 | |
| 399 | class Key(Object): |
| 400 | """Data accessor for the encoded key bytes.""" |
| 401 | __slots__ = () |
| 402 | |
| 403 | def __init__(self, buf, byte_width): |
| 404 | assert byte_width == 1 |
| 405 | super().__init__(buf, byte_width) |
| 406 | |
| 407 | @property |
| 408 | def Bytes(self): |
| 409 | return self._buf[0:len(self)] |
| 410 | |
| 411 | def __len__(self): |
| 412 | return self._buf.Find(0) |
| 413 | |
| 414 | def __str__(self): |
| 415 | return self.Bytes.decode('ascii') |
| 416 | |
| 417 | def __repr__(self): |
| 418 | return 'Key(%s, size=%d)' % (self._buf, len(self)) |
| 419 | |
| 420 | |
| 421 | class Vector(Sized): |
| 422 | """Data accessor for the encoded vector bytes.""" |
| 423 | __slots__ = () |
| 424 | |
| 425 | def __getitem__(self, index): |
| 426 | if index < 0 or index >= len(self): |
| 427 | raise IndexError('vector index %s is out of [0, %d) range' % \ |
| 428 | (index, len(self))) |
| 429 | |
| 430 | packed_type = self._buf[len(self) * self._byte_width + index] |
| 431 | buf = self._buf.Slice(index * self._byte_width) |
| 432 | return Ref.PackedType(buf, self._byte_width, packed_type) |
| 433 | |
| 434 | @property |
| 435 | def Value(self): |
| 436 | """Returns the underlying encoded data as a list object.""" |
| 437 | return [e.Value for e in self] |
| 438 | |
| 439 | def __repr__(self): |
| 440 | return 'Vector(%s, byte_width=%d, size=%d)' % \ |
| 441 | (self._buf, self._byte_width, self._size) |
| 442 | |
| 443 | |
| 444 | class TypedVector(Sized): |
| 445 | """Data accessor for the encoded typed vector or fixed typed vector bytes.""" |
| 446 | __slots__ = '_element_type', '_size' |
| 447 | |
| 448 | def __init__(self, buf, byte_width, element_type, size=0): |
| 449 | super().__init__(buf, byte_width, size) |
| 450 | |
| 451 | if element_type == Type.STRING: |
| 452 | # These can't be accessed as strings, since we don't know the bit-width |
| 453 | # of the size field, see the declaration of |
| 454 | # FBT_VECTOR_STRING_DEPRECATED above for details. |
| 455 | # We change the type here to be keys, which are a subtype of strings, |
| 456 | # and will ignore the size field. This will truncate strings with |
| 457 | # embedded nulls. |
| 458 | element_type = Type.KEY |
| 459 | |
| 460 | self._element_type = element_type |
| 461 | |
| 462 | @property |
| 463 | def Bytes(self): |
| 464 | return self._buf[:self._byte_width * len(self)] |
| 465 | |
| 466 | @property |
| 467 | def ElementType(self): |
| 468 | return self._element_type |
| 469 | |
| 470 | def __getitem__(self, index): |
| 471 | if index < 0 or index >= len(self): |
| 472 | raise IndexError('vector index %s is out of [0, %d) range' % \ |
| 473 | (index, len(self))) |
| 474 | |
| 475 | buf = self._buf.Slice(index * self._byte_width) |
| 476 | return Ref(buf, self._byte_width, 1, self._element_type) |
| 477 | |
| 478 | @property |
| 479 | def Value(self): |
| 480 | """Returns underlying data as list object.""" |
| 481 | if not self: |
| 482 | return [] |
| 483 | |
| 484 | if self._element_type is Type.BOOL: |
| 485 | return [bool(e) for e in _UnpackVector(U, self.Bytes, len(self))] |
| 486 | elif self._element_type is Type.INT: |
| 487 | return list(_UnpackVector(I, self.Bytes, len(self))) |
| 488 | elif self._element_type is Type.UINT: |
| 489 | return list(_UnpackVector(U, self.Bytes, len(self))) |
| 490 | elif self._element_type is Type.FLOAT: |
| 491 | return list(_UnpackVector(F, self.Bytes, len(self))) |
| 492 | elif self._element_type is Type.KEY: |
| 493 | return [e.AsKey for e in self] |
| 494 | elif self._element_type is Type.STRING: |
| 495 | return [e.AsString for e in self] |
| 496 | else: |
| 497 | raise TypeError('unsupported element_type: %s' % self._element_type) |
| 498 | |
| 499 | def __repr__(self): |
| 500 | return 'TypedVector(%s, byte_width=%d, element_type=%s, size=%d)' % \ |
| 501 | (self._buf, self._byte_width, self._element_type, self._size) |
| 502 | |
| 503 | |
| 504 | class Map(Vector): |
| 505 | """Data accessor for the encoded map bytes.""" |
| 506 | |
| 507 | @staticmethod |
| 508 | def CompareKeys(a, b): |
| 509 | if isinstance(a, Ref): |
| 510 | a = a.AsKeyBytes |
| 511 | if isinstance(b, Ref): |
| 512 | b = b.AsKeyBytes |
| 513 | return a < b |
| 514 | |
| 515 | def __getitem__(self, key): |
| 516 | if isinstance(key, int): |
| 517 | return super().__getitem__(key) |
| 518 | |
| 519 | index = _BinarySearch(self.Keys, key.encode('ascii'), self.CompareKeys) |
| 520 | if index != -1: |
| 521 | return super().__getitem__(index) |
| 522 | |
| 523 | raise KeyError(key) |
| 524 | |
| 525 | @property |
| 526 | def Keys(self): |
| 527 | byte_width = _Unpack(U, self._buf[-2 * self._byte_width:-self._byte_width]) |
| 528 | buf = self._buf.Indirect(-3 * self._byte_width, self._byte_width) |
| 529 | return TypedVector(buf, byte_width, Type.KEY) |
| 530 | |
| 531 | @property |
| 532 | def Values(self): |
| 533 | return Vector(self._buf, self._byte_width) |
| 534 | |
| 535 | @property |
| 536 | def Value(self): |
| 537 | return {k.Value: v.Value for k, v in zip(self.Keys, self.Values)} |
| 538 | |
| 539 | def __repr__(self): |
| 540 | return 'Map(%s, size=%d)' % (self._buf, len(self)) |
| 541 | |
| 542 | |
| 543 | class Ref: |
| 544 | """Data accessor for the encoded data bytes.""" |
| 545 | __slots__ = '_buf', '_parent_width', '_byte_width', '_type' |
| 546 | |
| 547 | @staticmethod |
| 548 | def PackedType(buf, parent_width, packed_type): |
| 549 | byte_width, type_ = Type.Unpack(packed_type) |
| 550 | return Ref(buf, parent_width, byte_width, type_) |
| 551 | |
| 552 | def __init__(self, buf, parent_width, byte_width, type_): |
| 553 | self._buf = buf |
| 554 | self._parent_width = parent_width |
| 555 | self._byte_width = byte_width |
| 556 | self._type = type_ |
| 557 | |
| 558 | def __repr__(self): |
| 559 | return 'Ref(%s, parent_width=%d, byte_width=%d, type_=%s)' % \ |
| 560 | (self._buf, self._parent_width, self._byte_width, self._type) |
| 561 | |
| 562 | @property |
| 563 | def _Bytes(self): |
| 564 | return self._buf[:self._parent_width] |
| 565 | |
| 566 | def _ConvertError(self, target_type): |
| 567 | raise TypeError('cannot convert %s to %s' % (self._type, target_type)) |
| 568 | |
| 569 | def _Indirect(self): |
| 570 | return self._buf.Indirect(0, self._parent_width) |
| 571 | |
| 572 | @property |
| 573 | def IsNull(self): |
| 574 | return self._type is Type.NULL |
| 575 | |
| 576 | @property |
| 577 | def IsBool(self): |
| 578 | return self._type is Type.BOOL |
| 579 | |
| 580 | @property |
| 581 | def AsBool(self): |
| 582 | if self._type is Type.BOOL: |
| 583 | return bool(_Unpack(U, self._Bytes)) |
| 584 | else: |
| 585 | return self.AsInt != 0 |
| 586 | |
| 587 | def MutateBool(self, value): |
| 588 | """Mutates underlying boolean value bytes in place. |
| 589 | |
| 590 | Args: |
| 591 | value: New boolean value. |
| 592 | |
| 593 | Returns: |
| 594 | Whether the value was mutated or not. |
| 595 | """ |
| 596 | return self.IsBool and \ |
| 597 | _Mutate(U, self._buf, value, self._parent_width, BitWidth.W8) |
| 598 | |
| 599 | @property |
| 600 | def IsNumeric(self): |
| 601 | return self.IsInt or self.IsFloat |
| 602 | |
| 603 | @property |
| 604 | def IsInt(self): |
| 605 | return self._type in (Type.INT, Type.INDIRECT_INT, Type.UINT, |
| 606 | Type.INDIRECT_UINT) |
| 607 | |
| 608 | @property |
| 609 | def AsInt(self): |
| 610 | """Returns current reference as integer value.""" |
| 611 | if self.IsNull: |
| 612 | return 0 |
| 613 | elif self.IsBool: |
| 614 | return int(self.AsBool) |
| 615 | elif self._type is Type.INT: |
| 616 | return _Unpack(I, self._Bytes) |
| 617 | elif self._type is Type.INDIRECT_INT: |
| 618 | return _Unpack(I, self._Indirect()[:self._byte_width]) |
| 619 | if self._type is Type.UINT: |
| 620 | return _Unpack(U, self._Bytes) |
| 621 | elif self._type is Type.INDIRECT_UINT: |
| 622 | return _Unpack(U, self._Indirect()[:self._byte_width]) |
| 623 | elif self.IsString: |
| 624 | return len(self.AsString) |
| 625 | elif self.IsKey: |
| 626 | return len(self.AsKey) |
| 627 | elif self.IsBlob: |
| 628 | return len(self.AsBlob) |
| 629 | elif self.IsVector: |
| 630 | return len(self.AsVector) |
| 631 | elif self.IsTypedVector: |
| 632 | return len(self.AsTypedVector) |
| 633 | elif self.IsFixedTypedVector: |
| 634 | return len(self.AsFixedTypedVector) |
| 635 | else: |
| 636 | raise self._ConvertError(Type.INT) |
| 637 | |
| 638 | def MutateInt(self, value): |
| 639 | """Mutates underlying integer value bytes in place. |
| 640 | |
| 641 | Args: |
| 642 | value: New integer value. It must fit to the byte size of the existing |
| 643 | encoded value. |
| 644 | |
| 645 | Returns: |
| 646 | Whether the value was mutated or not. |
| 647 | """ |
| 648 | if self._type is Type.INT: |
| 649 | return _Mutate(I, self._buf, value, self._parent_width, BitWidth.I(value)) |
| 650 | elif self._type is Type.INDIRECT_INT: |
| 651 | return _Mutate(I, self._Indirect(), value, self._byte_width, |
| 652 | BitWidth.I(value)) |
| 653 | elif self._type is Type.UINT: |
| 654 | return _Mutate(U, self._buf, value, self._parent_width, BitWidth.U(value)) |
| 655 | elif self._type is Type.INDIRECT_UINT: |
| 656 | return _Mutate(U, self._Indirect(), value, self._byte_width, |
| 657 | BitWidth.U(value)) |
| 658 | else: |
| 659 | return False |
| 660 | |
| 661 | @property |
| 662 | def IsFloat(self): |
| 663 | return self._type in (Type.FLOAT, Type.INDIRECT_FLOAT) |
| 664 | |
| 665 | @property |
| 666 | def AsFloat(self): |
| 667 | """Returns current reference as floating point value.""" |
| 668 | if self.IsNull: |
| 669 | return 0.0 |
| 670 | elif self.IsBool: |
| 671 | return float(self.AsBool) |
| 672 | elif self.IsInt: |
| 673 | return float(self.AsInt) |
| 674 | elif self._type is Type.FLOAT: |
| 675 | return _Unpack(F, self._Bytes) |
| 676 | elif self._type is Type.INDIRECT_FLOAT: |
| 677 | return _Unpack(F, self._Indirect()[:self._byte_width]) |
| 678 | elif self.IsString: |
| 679 | return float(self.AsString) |
| 680 | elif self.IsVector: |
| 681 | return float(len(self.AsVector)) |
| 682 | elif self.IsTypedVector(): |
| 683 | return float(len(self.AsTypedVector)) |
| 684 | elif self.IsFixedTypedVector(): |
| 685 | return float(len(self.FixedTypedVector)) |
| 686 | else: |
| 687 | raise self._ConvertError(Type.FLOAT) |
| 688 | |
| 689 | def MutateFloat(self, value): |
| 690 | """Mutates underlying floating point value bytes in place. |
| 691 | |
| 692 | Args: |
| 693 | value: New float value. It must fit to the byte size of the existing |
| 694 | encoded value. |
| 695 | |
| 696 | Returns: |
| 697 | Whether the value was mutated or not. |
| 698 | """ |
| 699 | if self._type is Type.FLOAT: |
| 700 | return _Mutate(F, self._buf, value, self._parent_width, |
| 701 | BitWidth.B(self._parent_width)) |
| 702 | elif self._type is Type.INDIRECT_FLOAT: |
| 703 | return _Mutate(F, self._Indirect(), value, self._byte_width, |
| 704 | BitWidth.B(self._byte_width)) |
| 705 | else: |
| 706 | return False |
| 707 | |
| 708 | @property |
| 709 | def IsKey(self): |
| 710 | return self._type is Type.KEY |
| 711 | |
| 712 | @property |
| 713 | def AsKeyBytes(self): |
| 714 | if self.IsKey: |
| 715 | return Key(self._Indirect(), self._byte_width).Bytes |
| 716 | else: |
| 717 | raise self._ConvertError(Type.KEY) |
| 718 | |
| 719 | @property |
| 720 | def AsKey(self): |
| 721 | if self.IsKey: |
| 722 | return str(Key(self._Indirect(), self._byte_width)) |
| 723 | else: |
| 724 | raise self._ConvertError(Type.KEY) |
| 725 | |
| 726 | @property |
| 727 | def IsString(self): |
| 728 | return self._type is Type.STRING |
| 729 | |
| 730 | @property |
| 731 | def AsString(self): |
| 732 | if self.IsString: |
| 733 | return str(String(self._Indirect(), self._byte_width)) |
| 734 | elif self.IsKey: |
| 735 | return self.AsKey |
| 736 | else: |
| 737 | raise self._ConvertError(Type.STRING) |
| 738 | |
| 739 | def MutateString(self, value): |
| 740 | return String(self._Indirect(), self._byte_width).Mutate(value) |
| 741 | |
| 742 | @property |
| 743 | def IsBlob(self): |
| 744 | return self._type is Type.BLOB |
| 745 | |
| 746 | @property |
| 747 | def AsBlob(self): |
| 748 | if self.IsBlob: |
| 749 | return Blob(self._Indirect(), self._byte_width).Bytes |
| 750 | else: |
| 751 | raise self._ConvertError(Type.BLOB) |
| 752 | |
| 753 | @property |
| 754 | def IsAnyVector(self): |
| 755 | return self.IsVector or self.IsTypedVector or self.IsFixedTypedVector() |
| 756 | |
| 757 | @property |
| 758 | def IsVector(self): |
| 759 | return self._type in (Type.VECTOR, Type.MAP) |
| 760 | |
| 761 | @property |
| 762 | def AsVector(self): |
| 763 | if self.IsVector: |
| 764 | return Vector(self._Indirect(), self._byte_width) |
| 765 | else: |
| 766 | raise self._ConvertError(Type.VECTOR) |
| 767 | |
| 768 | @property |
| 769 | def IsTypedVector(self): |
| 770 | return Type.IsTypedVector(self._type) |
| 771 | |
| 772 | @property |
| 773 | def AsTypedVector(self): |
| 774 | if self.IsTypedVector: |
| 775 | return TypedVector(self._Indirect(), self._byte_width, |
| 776 | Type.ToTypedVectorElementType(self._type)) |
| 777 | else: |
| 778 | raise self._ConvertError('TYPED_VECTOR') |
| 779 | |
| 780 | @property |
| 781 | def IsFixedTypedVector(self): |
| 782 | return Type.IsFixedTypedVector(self._type) |
| 783 | |
| 784 | @property |
| 785 | def AsFixedTypedVector(self): |
| 786 | if self.IsFixedTypedVector: |
| 787 | element_type, size = Type.ToFixedTypedVectorElementType(self._type) |
| 788 | return TypedVector(self._Indirect(), self._byte_width, element_type, size) |
| 789 | else: |
| 790 | raise self._ConvertError('FIXED_TYPED_VECTOR') |
| 791 | |
| 792 | @property |
| 793 | def IsMap(self): |
| 794 | return self._type is Type.MAP |
| 795 | |
| 796 | @property |
| 797 | def AsMap(self): |
| 798 | if self.IsMap: |
| 799 | return Map(self._Indirect(), self._byte_width) |
| 800 | else: |
| 801 | raise self._ConvertError(Type.MAP) |
| 802 | |
| 803 | @property |
| 804 | def Value(self): |
| 805 | """Converts current reference to value of corresponding type. |
| 806 | |
| 807 | This is equivalent to calling `AsInt` for integer values, `AsFloat` for |
| 808 | floating point values, etc. |
| 809 | |
| 810 | Returns: |
| 811 | Value of corresponding type. |
| 812 | """ |
| 813 | if self.IsNull: |
| 814 | return None |
| 815 | elif self.IsBool: |
| 816 | return self.AsBool |
| 817 | elif self.IsInt: |
| 818 | return self.AsInt |
| 819 | elif self.IsFloat: |
| 820 | return self.AsFloat |
| 821 | elif self.IsString: |
| 822 | return self.AsString |
| 823 | elif self.IsKey: |
| 824 | return self.AsKey |
| 825 | elif self.IsBlob: |
| 826 | return self.AsBlob |
| 827 | elif self.IsMap: |
| 828 | return self.AsMap.Value |
| 829 | elif self.IsVector: |
| 830 | return self.AsVector.Value |
| 831 | elif self.IsTypedVector: |
| 832 | return self.AsTypedVector.Value |
| 833 | elif self.IsFixedTypedVector: |
| 834 | return self.AsFixedTypedVector.Value |
| 835 | else: |
| 836 | raise TypeError('cannot convert %r to value' % self) |
| 837 | |
| 838 | |
| 839 | def _IsIterable(obj): |
| 840 | try: |
| 841 | iter(obj) |
| 842 | return True |
| 843 | except TypeError: |
| 844 | return False |
| 845 | |
| 846 | |
| 847 | class Value: |
| 848 | """Class to represent given value during the encoding process.""" |
| 849 | |
| 850 | @staticmethod |
| 851 | def Null(): |
| 852 | return Value(0, Type.NULL, BitWidth.W8) |
| 853 | |
| 854 | @staticmethod |
| 855 | def Bool(value): |
| 856 | return Value(value, Type.BOOL, BitWidth.W8) |
| 857 | |
| 858 | @staticmethod |
| 859 | def Int(value, bit_width): |
| 860 | return Value(value, Type.INT, bit_width) |
| 861 | |
| 862 | @staticmethod |
| 863 | def UInt(value, bit_width): |
| 864 | return Value(value, Type.UINT, bit_width) |
| 865 | |
| 866 | @staticmethod |
| 867 | def Float(value, bit_width): |
| 868 | return Value(value, Type.FLOAT, bit_width) |
| 869 | |
| 870 | @staticmethod |
| 871 | def Key(offset): |
| 872 | return Value(offset, Type.KEY, BitWidth.W8) |
| 873 | |
| 874 | def __init__(self, value, type_, min_bit_width): |
| 875 | self._value = value |
| 876 | self._type = type_ |
| 877 | |
| 878 | # For scalars: of itself, for vector: of its elements, for string: length. |
| 879 | self._min_bit_width = min_bit_width |
| 880 | |
| 881 | @property |
| 882 | def Value(self): |
| 883 | return self._value |
| 884 | |
| 885 | @property |
| 886 | def Type(self): |
| 887 | return self._type |
| 888 | |
| 889 | @property |
| 890 | def MinBitWidth(self): |
| 891 | return self._min_bit_width |
| 892 | |
| 893 | def StoredPackedType(self, parent_bit_width=BitWidth.W8): |
| 894 | return Type.Pack(self._type, self.StoredWidth(parent_bit_width)) |
| 895 | |
| 896 | # We have an absolute offset, but want to store a relative offset |
| 897 | # elem_index elements beyond the current buffer end. Since whether |
| 898 | # the relative offset fits in a certain byte_width depends on |
| 899 | # the size of the elements before it (and their alignment), we have |
| 900 | # to test for each size in turn. |
| 901 | def ElemWidth(self, buf_size, elem_index=0): |
| 902 | if Type.IsInline(self._type): |
| 903 | return self._min_bit_width |
| 904 | for byte_width in 1, 2, 4, 8: |
| 905 | offset_loc = buf_size + _PaddingBytes(buf_size, byte_width) + \ |
| 906 | elem_index * byte_width |
| 907 | bit_width = BitWidth.U(offset_loc - self._value) |
| 908 | if byte_width == (1 << bit_width): |
| 909 | return bit_width |
| 910 | raise ValueError('relative offset is too big') |
| 911 | |
| 912 | def StoredWidth(self, parent_bit_width=BitWidth.W8): |
| 913 | if Type.IsInline(self._type): |
| 914 | return max(self._min_bit_width, parent_bit_width) |
| 915 | return self._min_bit_width |
| 916 | |
| 917 | def __repr__(self): |
| 918 | return 'Value(%s, %s, %s)' % (self._value, self._type, self._min_bit_width) |
| 919 | |
| 920 | def __str__(self): |
| 921 | return str(self._value) |
| 922 | |
| 923 | |
| 924 | def InMap(func): |
| 925 | def wrapper(self, *args, **kwargs): |
| 926 | if isinstance(args[0], str): |
| 927 | self.Key(args[0]) |
| 928 | func(self, *args[1:], **kwargs) |
| 929 | else: |
| 930 | func(self, *args, **kwargs) |
| 931 | return wrapper |
| 932 | |
| 933 | |
| 934 | def InMapForString(func): |
| 935 | def wrapper(self, *args): |
| 936 | if len(args) == 1: |
| 937 | func(self, args[0]) |
| 938 | elif len(args) == 2: |
| 939 | self.Key(args[0]) |
| 940 | func(self, args[1]) |
| 941 | else: |
| 942 | raise ValueError('invalid number of arguments') |
| 943 | return wrapper |
| 944 | |
| 945 | |
| 946 | class Pool: |
| 947 | """Collection of (data, offset) pairs sorted by data for quick access.""" |
| 948 | |
| 949 | def __init__(self): |
| 950 | self._pool = [] # sorted list of (data, offset) tuples |
| 951 | |
| 952 | def FindOrInsert(self, data, offset): |
| 953 | do = data, offset |
| 954 | index = _BinarySearch(self._pool, do, lambda a, b: a[0] < b[0]) |
| 955 | if index != -1: |
| 956 | _, offset = self._pool[index] |
| 957 | return offset |
| 958 | self._pool.insert(index, do) |
| 959 | return None |
| 960 | |
| 961 | def Clear(self): |
| 962 | self._pool = [] |
| 963 | |
| 964 | @property |
| 965 | def Elements(self): |
| 966 | return [data for data, _ in self._pool] |
| 967 | |
| 968 | |
| 969 | class Builder: |
| 970 | """Helper class to encode structural data into flexbuffers format.""" |
| 971 | |
| 972 | def __init__(self, |
| 973 | share_strings=False, |
| 974 | share_keys=True, |
| 975 | force_min_bit_width=BitWidth.W8): |
| 976 | self._share_strings = share_strings |
| 977 | self._share_keys = share_keys |
| 978 | self._force_min_bit_width = force_min_bit_width |
| 979 | |
| 980 | self._string_pool = Pool() |
| 981 | self._key_pool = Pool() |
| 982 | |
| 983 | self._finished = False |
| 984 | self._buf = bytearray() |
| 985 | self._stack = [] |
| 986 | |
| 987 | def __len__(self): |
| 988 | return len(self._buf) |
| 989 | |
| 990 | @property |
| 991 | def StringPool(self): |
| 992 | return self._string_pool |
| 993 | |
| 994 | @property |
| 995 | def KeyPool(self): |
| 996 | return self._key_pool |
| 997 | |
| 998 | def Clear(self): |
| 999 | self._string_pool.Clear() |
| 1000 | self._key_pool.Clear() |
| 1001 | self._finished = False |
| 1002 | self._buf = bytearray() |
| 1003 | self._stack = [] |
| 1004 | |
| 1005 | def Finish(self): |
| 1006 | """Finishes encoding process and returns underlying buffer.""" |
| 1007 | if self._finished: |
| 1008 | raise RuntimeError('builder has been already finished') |
| 1009 | |
| 1010 | # If you hit this exception, you likely have objects that were never |
| 1011 | # included in a parent. You need to have exactly one root to finish a |
| 1012 | # buffer. Check your Start/End calls are matched, and all objects are inside |
| 1013 | # some other object. |
| 1014 | if len(self._stack) != 1: |
| 1015 | raise RuntimeError('internal stack size must be one') |
| 1016 | |
| 1017 | value = self._stack[0] |
| 1018 | byte_width = self._Align(value.ElemWidth(len(self._buf))) |
| 1019 | self._WriteAny(value, byte_width=byte_width) # Root value |
| 1020 | self._Write(U, value.StoredPackedType(), byte_width=1) # Root type |
| 1021 | self._Write(U, byte_width, byte_width=1) # Root size |
| 1022 | |
| 1023 | self.finished = True |
| 1024 | return self._buf |
| 1025 | |
| 1026 | def _ReadKey(self, offset): |
| 1027 | key = self._buf[offset:] |
| 1028 | return key[:key.find(0)] |
| 1029 | |
| 1030 | def _Align(self, alignment): |
| 1031 | byte_width = 1 << alignment |
| 1032 | self._buf.extend(b'\x00' * _PaddingBytes(len(self._buf), byte_width)) |
| 1033 | return byte_width |
| 1034 | |
| 1035 | def _Write(self, fmt, value, byte_width): |
| 1036 | self._buf.extend(_Pack(fmt, value, byte_width)) |
| 1037 | |
| 1038 | def _WriteVector(self, fmt, values, byte_width): |
| 1039 | self._buf.extend(_PackVector(fmt, values, byte_width)) |
| 1040 | |
| 1041 | def _WriteOffset(self, offset, byte_width): |
| 1042 | relative_offset = len(self._buf) - offset |
| 1043 | assert byte_width == 8 or relative_offset < (1 << (8 * byte_width)) |
| 1044 | self._Write(U, relative_offset, byte_width) |
| 1045 | |
| 1046 | def _WriteAny(self, value, byte_width): |
| 1047 | fmt = { |
| 1048 | Type.NULL: U, Type.BOOL: U, Type.INT: I, Type.UINT: U, Type.FLOAT: F |
| 1049 | }.get(value.Type) |
| 1050 | if fmt: |
| 1051 | self._Write(fmt, value.Value, byte_width) |
| 1052 | else: |
| 1053 | self._WriteOffset(value.Value, byte_width) |
| 1054 | |
| 1055 | def _WriteBlob(self, data, append_zero, type_): |
| 1056 | bit_width = BitWidth.U(len(data)) |
| 1057 | byte_width = self._Align(bit_width) |
| 1058 | self._Write(U, len(data), byte_width) |
| 1059 | loc = len(self._buf) |
| 1060 | self._buf.extend(data) |
| 1061 | if append_zero: |
| 1062 | self._buf.append(0) |
| 1063 | self._stack.append(Value(loc, type_, bit_width)) |
| 1064 | return loc |
| 1065 | |
| 1066 | def _WriteScalarVector(self, element_type, byte_width, elements, fixed): |
| 1067 | """Writes scalar vector elements to the underlying buffer.""" |
| 1068 | bit_width = BitWidth.B(byte_width) |
| 1069 | # If you get this exception, you're trying to write a vector with a size |
| 1070 | # field that is bigger than the scalars you're trying to write (e.g. a |
| 1071 | # byte vector > 255 elements). For such types, write a "blob" instead. |
| 1072 | if BitWidth.U(len(elements)) > bit_width: |
| 1073 | raise ValueError('too many elements for the given byte_width') |
| 1074 | |
| 1075 | self._Align(bit_width) |
| 1076 | if not fixed: |
| 1077 | self._Write(U, len(elements), byte_width) |
| 1078 | |
| 1079 | loc = len(self._buf) |
| 1080 | |
| 1081 | fmt = {Type.INT: I, Type.UINT: U, Type.FLOAT: F}.get(element_type) |
| 1082 | if not fmt: |
| 1083 | raise TypeError('unsupported element_type') |
| 1084 | self._WriteVector(fmt, elements, byte_width) |
| 1085 | |
| 1086 | type_ = Type.ToTypedVector(element_type, len(elements) if fixed else 0) |
| 1087 | self._stack.append(Value(loc, type_, bit_width)) |
| 1088 | return loc |
| 1089 | |
| 1090 | def _CreateVector(self, elements, typed, fixed, keys=None): |
| 1091 | """Writes vector elements to the underlying buffer.""" |
| 1092 | length = len(elements) |
| 1093 | |
| 1094 | if fixed and not typed: |
| 1095 | raise ValueError('fixed vector must be typed') |
| 1096 | |
| 1097 | # Figure out smallest bit width we can store this vector with. |
| 1098 | bit_width = max(self._force_min_bit_width, BitWidth.U(length)) |
| 1099 | prefix_elems = 1 # Vector size |
| 1100 | if keys: |
| 1101 | bit_width = max(bit_width, keys.ElemWidth(len(self._buf))) |
| 1102 | prefix_elems += 2 # Offset to the keys vector and its byte width. |
| 1103 | |
| 1104 | vector_type = Type.KEY |
| 1105 | # Check bit widths and types for all elements. |
| 1106 | for i, e in enumerate(elements): |
| 1107 | bit_width = max(bit_width, e.ElemWidth(len(self._buf), prefix_elems + i)) |
| 1108 | |
| 1109 | if typed: |
| 1110 | if i == 0: |
| 1111 | vector_type = e.Type |
| 1112 | else: |
| 1113 | if vector_type != e.Type: |
| 1114 | raise RuntimeError('typed vector elements must be of the same type') |
| 1115 | |
| 1116 | if fixed and not Type.IsFixedTypedVectorElementType(vector_type): |
| 1117 | raise RuntimeError('must be fixed typed vector element type') |
| 1118 | |
| 1119 | byte_width = self._Align(bit_width) |
| 1120 | # Write vector. First the keys width/offset if available, and size. |
| 1121 | if keys: |
| 1122 | self._WriteOffset(keys.Value, byte_width) |
| 1123 | self._Write(U, 1 << keys.MinBitWidth, byte_width) |
| 1124 | |
| 1125 | if not fixed: |
| 1126 | self._Write(U, length, byte_width) |
| 1127 | |
| 1128 | # Then the actual data. |
| 1129 | loc = len(self._buf) |
| 1130 | for e in elements: |
| 1131 | self._WriteAny(e, byte_width) |
| 1132 | |
| 1133 | # Then the types. |
| 1134 | if not typed: |
| 1135 | for e in elements: |
| 1136 | self._buf.append(e.StoredPackedType(bit_width)) |
| 1137 | |
| 1138 | if keys: |
| 1139 | type_ = Type.MAP |
| 1140 | else: |
| 1141 | if typed: |
| 1142 | type_ = Type.ToTypedVector(vector_type, length if fixed else 0) |
| 1143 | else: |
| 1144 | type_ = Type.VECTOR |
| 1145 | |
| 1146 | return Value(loc, type_, bit_width) |
| 1147 | |
| 1148 | def _PushIndirect(self, value, type_, bit_width): |
| 1149 | byte_width = self._Align(bit_width) |
| 1150 | loc = len(self._buf) |
| 1151 | fmt = { |
| 1152 | Type.INDIRECT_INT: I, |
| 1153 | Type.INDIRECT_UINT: U, |
| 1154 | Type.INDIRECT_FLOAT: F |
| 1155 | }[type_] |
| 1156 | self._Write(fmt, value, byte_width) |
| 1157 | self._stack.append(Value(loc, type_, bit_width)) |
| 1158 | |
| 1159 | @InMapForString |
| 1160 | def String(self, value): |
| 1161 | """Encodes string value.""" |
| 1162 | reset_to = len(self._buf) |
| 1163 | encoded = value.encode('utf-8') |
| 1164 | loc = self._WriteBlob(encoded, append_zero=True, type_=Type.STRING) |
| 1165 | if self._share_strings: |
| 1166 | prev_loc = self._string_pool.FindOrInsert(encoded, loc) |
| 1167 | if prev_loc is not None: |
| 1168 | del self._buf[reset_to:] |
| 1169 | self._stack[-1]._value = loc = prev_loc # pylint: disable=protected-access |
| 1170 | |
| 1171 | return loc |
| 1172 | |
| 1173 | @InMap |
| 1174 | def Blob(self, value): |
| 1175 | """Encodes binary blob value. |
| 1176 | |
| 1177 | Args: |
| 1178 | value: A byte/bytearray value to encode |
| 1179 | |
| 1180 | Returns: |
| 1181 | Offset of the encoded value in underlying the byte buffer. |
| 1182 | """ |
| 1183 | return self._WriteBlob(value, append_zero=False, type_=Type.BLOB) |
| 1184 | |
| 1185 | def Key(self, value): |
| 1186 | """Encodes key value. |
| 1187 | |
| 1188 | Args: |
| 1189 | value: A byte/bytearray/str value to encode. Byte object must not contain |
| 1190 | zero bytes. String object must be convertible to ASCII. |
| 1191 | |
| 1192 | Returns: |
| 1193 | Offset of the encoded value in the underlying byte buffer. |
| 1194 | """ |
| 1195 | if isinstance(value, (bytes, bytearray)): |
| 1196 | encoded = value |
| 1197 | else: |
| 1198 | encoded = value.encode('ascii') |
| 1199 | |
| 1200 | if 0 in encoded: |
| 1201 | raise ValueError('key contains zero byte') |
| 1202 | |
| 1203 | loc = len(self._buf) |
| 1204 | self._buf.extend(encoded) |
| 1205 | self._buf.append(0) |
| 1206 | if self._share_keys: |
| 1207 | prev_loc = self._key_pool.FindOrInsert(encoded, loc) |
| 1208 | if prev_loc is not None: |
| 1209 | del self._buf[loc:] |
| 1210 | loc = prev_loc |
| 1211 | |
| 1212 | self._stack.append(Value.Key(loc)) |
| 1213 | return loc |
| 1214 | |
| 1215 | def Null(self, key=None): |
| 1216 | """Encodes None value.""" |
| 1217 | if key: |
| 1218 | self.Key(key) |
| 1219 | self._stack.append(Value.Null()) |
| 1220 | |
| 1221 | @InMap |
| 1222 | def Bool(self, value): |
| 1223 | """Encodes boolean value. |
| 1224 | |
| 1225 | Args: |
| 1226 | value: A boolean value. |
| 1227 | """ |
| 1228 | self._stack.append(Value.Bool(value)) |
| 1229 | |
| 1230 | @InMap |
| 1231 | def Int(self, value, byte_width=0): |
| 1232 | """Encodes signed integer value. |
| 1233 | |
| 1234 | Args: |
| 1235 | value: A signed integer value. |
| 1236 | byte_width: Number of bytes to use: 1, 2, 4, or 8. |
| 1237 | """ |
| 1238 | bit_width = BitWidth.I(value) if byte_width == 0 else BitWidth.B(byte_width) |
| 1239 | self._stack.append(Value.Int(value, bit_width)) |
| 1240 | |
| 1241 | @InMap |
| 1242 | def IndirectInt(self, value, byte_width=0): |
| 1243 | """Encodes signed integer value indirectly. |
| 1244 | |
| 1245 | Args: |
| 1246 | value: A signed integer value. |
| 1247 | byte_width: Number of bytes to use: 1, 2, 4, or 8. |
| 1248 | """ |
| 1249 | bit_width = BitWidth.I(value) if byte_width == 0 else BitWidth.B(byte_width) |
| 1250 | self._PushIndirect(value, Type.INDIRECT_INT, bit_width) |
| 1251 | |
| 1252 | @InMap |
| 1253 | def UInt(self, value, byte_width=0): |
| 1254 | """Encodes unsigned integer value. |
| 1255 | |
| 1256 | Args: |
| 1257 | value: An unsigned integer value. |
| 1258 | byte_width: Number of bytes to use: 1, 2, 4, or 8. |
| 1259 | """ |
| 1260 | bit_width = BitWidth.U(value) if byte_width == 0 else BitWidth.B(byte_width) |
| 1261 | self._stack.append(Value.UInt(value, bit_width)) |
| 1262 | |
| 1263 | @InMap |
| 1264 | def IndirectUInt(self, value, byte_width=0): |
| 1265 | """Encodes unsigned integer value indirectly. |
| 1266 | |
| 1267 | Args: |
| 1268 | value: An unsigned integer value. |
| 1269 | byte_width: Number of bytes to use: 1, 2, 4, or 8. |
| 1270 | """ |
| 1271 | bit_width = BitWidth.U(value) if byte_width == 0 else BitWidth.B(byte_width) |
| 1272 | self._PushIndirect(value, Type.INDIRECT_UINT, bit_width) |
| 1273 | |
| 1274 | @InMap |
| 1275 | def Float(self, value, byte_width=0): |
| 1276 | """Encodes floating point value. |
| 1277 | |
| 1278 | Args: |
| 1279 | value: A floating point value. |
| 1280 | byte_width: Number of bytes to use: 4 or 8. |
| 1281 | """ |
| 1282 | bit_width = BitWidth.F(value) if byte_width == 0 else BitWidth.B(byte_width) |
| 1283 | self._stack.append(Value.Float(value, bit_width)) |
| 1284 | |
| 1285 | @InMap |
| 1286 | def IndirectFloat(self, value, byte_width=0): |
| 1287 | """Encodes floating point value indirectly. |
| 1288 | |
| 1289 | Args: |
| 1290 | value: A floating point value. |
| 1291 | byte_width: Number of bytes to use: 4 or 8. |
| 1292 | """ |
| 1293 | bit_width = BitWidth.F(value) if byte_width == 0 else BitWidth.B(byte_width) |
| 1294 | self._PushIndirect(value, Type.INDIRECT_FLOAT, bit_width) |
| 1295 | |
| 1296 | def _StartVector(self): |
| 1297 | """Starts vector construction.""" |
| 1298 | return len(self._stack) |
| 1299 | |
| 1300 | def _EndVector(self, start, typed, fixed): |
| 1301 | """Finishes vector construction by encodung its elements.""" |
| 1302 | vec = self._CreateVector(self._stack[start:], typed, fixed) |
| 1303 | del self._stack[start:] |
| 1304 | self._stack.append(vec) |
| 1305 | return vec.Value |
| 1306 | |
| 1307 | @contextlib.contextmanager |
| 1308 | def Vector(self, key=None): |
| 1309 | if key: |
| 1310 | self.Key(key) |
| 1311 | |
| 1312 | try: |
| 1313 | start = self._StartVector() |
| 1314 | yield self |
| 1315 | finally: |
| 1316 | self._EndVector(start, typed=False, fixed=False) |
| 1317 | |
| 1318 | @InMap |
| 1319 | def VectorFromElements(self, elements): |
| 1320 | """Encodes sequence of any elements as a vector. |
| 1321 | |
| 1322 | Args: |
| 1323 | elements: sequence of elements, they may have different types. |
| 1324 | """ |
| 1325 | with self.Vector(): |
| 1326 | for e in elements: |
| 1327 | self.Add(e) |
| 1328 | |
| 1329 | @contextlib.contextmanager |
| 1330 | def TypedVector(self, key=None): |
| 1331 | if key: |
| 1332 | self.Key(key) |
| 1333 | |
| 1334 | try: |
| 1335 | start = self._StartVector() |
| 1336 | yield self |
| 1337 | finally: |
| 1338 | self._EndVector(start, typed=True, fixed=False) |
| 1339 | |
| 1340 | @InMap |
| 1341 | def TypedVectorFromElements(self, elements, element_type=None): |
| 1342 | """Encodes sequence of elements of the same type as typed vector. |
| 1343 | |
| 1344 | Args: |
| 1345 | elements: Sequence of elements, they must be of the same type. |
| 1346 | element_type: Suggested element type. Setting it to None means determining |
| 1347 | correct value automatically based on the given elements. |
| 1348 | """ |
| 1349 | if isinstance(elements, array.array): |
| 1350 | if elements.typecode == 'f': |
| 1351 | self._WriteScalarVector(Type.FLOAT, 4, elements, fixed=False) |
| 1352 | elif elements.typecode == 'd': |
| 1353 | self._WriteScalarVector(Type.FLOAT, 8, elements, fixed=False) |
| 1354 | elif elements.typecode in ('b', 'h', 'i', 'l', 'q'): |
| 1355 | self._WriteScalarVector( |
| 1356 | Type.INT, elements.itemsize, elements, fixed=False) |
| 1357 | elif elements.typecode in ('B', 'H', 'I', 'L', 'Q'): |
| 1358 | self._WriteScalarVector( |
| 1359 | Type.UINT, elements.itemsize, elements, fixed=False) |
| 1360 | else: |
| 1361 | raise ValueError('unsupported array typecode: %s' % elements.typecode) |
| 1362 | else: |
| 1363 | add = self.Add if element_type is None else self.Adder(element_type) |
| 1364 | with self.TypedVector(): |
| 1365 | for e in elements: |
| 1366 | add(e) |
| 1367 | |
| 1368 | @InMap |
| 1369 | def FixedTypedVectorFromElements(self, |
| 1370 | elements, |
| 1371 | element_type=None, |
| 1372 | byte_width=0): |
| 1373 | """Encodes sequence of elements of the same type as fixed typed vector. |
| 1374 | |
| 1375 | Args: |
| 1376 | elements: Sequence of elements, they must be of the same type. Allowed |
| 1377 | types are `Type.INT`, `Type.UINT`, `Type.FLOAT`. Allowed number of |
| 1378 | elements are 2, 3, or 4. |
| 1379 | element_type: Suggested element type. Setting it to None means determining |
| 1380 | correct value automatically based on the given elements. |
| 1381 | byte_width: Number of bytes to use per element. For `Type.INT` and |
| 1382 | `Type.UINT`: 1, 2, 4, or 8. For `Type.FLOAT`: 4 or 8. Setting it to 0 |
| 1383 | means determining correct value automatically based on the given |
| 1384 | elements. |
| 1385 | """ |
| 1386 | if not 2 <= len(elements) <= 4: |
| 1387 | raise ValueError('only 2, 3, or 4 elements are supported') |
| 1388 | |
| 1389 | types = {type(e) for e in elements} |
| 1390 | if len(types) != 1: |
| 1391 | raise TypeError('all elements must be of the same type') |
| 1392 | |
| 1393 | type_, = types |
| 1394 | |
| 1395 | if element_type is None: |
| 1396 | element_type = {int: Type.INT, float: Type.FLOAT}.get(type_) |
| 1397 | if not element_type: |
| 1398 | raise TypeError('unsupported element_type: %s' % type_) |
| 1399 | |
| 1400 | if byte_width == 0: |
| 1401 | width = { |
| 1402 | Type.UINT: BitWidth.U, |
| 1403 | Type.INT: BitWidth.I, |
| 1404 | Type.FLOAT: BitWidth.F |
| 1405 | }[element_type] |
| 1406 | byte_width = 1 << max(width(e) for e in elements) |
| 1407 | |
| 1408 | self._WriteScalarVector(element_type, byte_width, elements, fixed=True) |
| 1409 | |
| 1410 | def _StartMap(self): |
| 1411 | """Starts map construction.""" |
| 1412 | return len(self._stack) |
| 1413 | |
| 1414 | def _EndMap(self, start): |
| 1415 | """Finishes map construction by encodung its elements.""" |
| 1416 | # Interleaved keys and values on the stack. |
| 1417 | stack = self._stack[start:] |
| 1418 | |
| 1419 | if len(stack) % 2 != 0: |
| 1420 | raise RuntimeError('must be even number of keys and values') |
| 1421 | |
| 1422 | for key in stack[::2]: |
| 1423 | if key.Type is not Type.KEY: |
| 1424 | raise RuntimeError('all map keys must be of %s type' % Type.KEY) |
| 1425 | |
| 1426 | pairs = zip(stack[::2], stack[1::2]) # [(key, value), ...] |
| 1427 | pairs = sorted(pairs, key=lambda pair: self._ReadKey(pair[0].Value)) |
| 1428 | |
| 1429 | del self._stack[start:] |
| 1430 | for pair in pairs: |
| 1431 | self._stack.extend(pair) |
| 1432 | |
| 1433 | keys = self._CreateVector(self._stack[start::2], typed=True, fixed=False) |
| 1434 | values = self._CreateVector( |
| 1435 | self._stack[start + 1::2], typed=False, fixed=False, keys=keys) |
| 1436 | |
| 1437 | del self._stack[start:] |
| 1438 | self._stack.append(values) |
| 1439 | return values.Value |
| 1440 | |
| 1441 | @contextlib.contextmanager |
| 1442 | def Map(self, key=None): |
| 1443 | if key: |
| 1444 | self.Key(key) |
| 1445 | |
| 1446 | try: |
| 1447 | start = self._StartMap() |
| 1448 | yield self |
| 1449 | finally: |
| 1450 | self._EndMap(start) |
| 1451 | |
| 1452 | def MapFromElements(self, elements): |
| 1453 | start = self._StartMap() |
| 1454 | for k, v in elements.items(): |
| 1455 | self.Key(k) |
| 1456 | self.Add(v) |
| 1457 | self._EndMap(start) |
| 1458 | |
| 1459 | def Adder(self, type_): |
| 1460 | return { |
| 1461 | Type.BOOL: self.Bool, |
| 1462 | Type.INT: self.Int, |
| 1463 | Type.INDIRECT_INT: self.IndirectInt, |
| 1464 | Type.UINT: self.UInt, |
| 1465 | Type.INDIRECT_UINT: self.IndirectUInt, |
| 1466 | Type.FLOAT: self.Float, |
| 1467 | Type.INDIRECT_FLOAT: self.IndirectFloat, |
| 1468 | Type.KEY: self.Key, |
| 1469 | Type.BLOB: self.Blob, |
| 1470 | Type.STRING: self.String, |
| 1471 | }[type_] |
| 1472 | |
| 1473 | @InMapForString |
| 1474 | def Add(self, value): |
| 1475 | """Encodes value of any supported type.""" |
| 1476 | if value is None: |
| 1477 | self.Null() |
| 1478 | elif isinstance(value, bool): |
| 1479 | self.Bool(value) |
| 1480 | elif isinstance(value, int): |
| 1481 | self.Int(value) |
| 1482 | elif isinstance(value, float): |
| 1483 | self.Float(value) |
| 1484 | elif isinstance(value, str): |
| 1485 | self.String(value) |
| 1486 | elif isinstance(value, (bytes, bytearray)): |
| 1487 | self.Blob(value) |
| 1488 | elif isinstance(value, dict): |
| 1489 | with self.Map(): |
| 1490 | for k, v in value.items(): |
| 1491 | self.Key(k) |
| 1492 | self.Add(v) |
| 1493 | elif isinstance(value, array.array): |
| 1494 | self.TypedVectorFromElements(value) |
| 1495 | elif _IsIterable(value): |
| 1496 | self.VectorFromElements(value) |
| 1497 | else: |
| 1498 | raise TypeError('unsupported python type: %s' % type(value)) |
| 1499 | |
| 1500 | @property |
| 1501 | def LastValue(self): |
| 1502 | return self._stack[-1] |
| 1503 | |
| 1504 | @InMap |
| 1505 | def ReuseValue(self, value): |
| 1506 | self._stack.append(value) |
| 1507 | |
| 1508 | |
| 1509 | def GetRoot(buf): |
| 1510 | """Returns root `Ref` object for the given buffer.""" |
| 1511 | if len(buf) < 3: |
| 1512 | raise ValueError('buffer is too small') |
| 1513 | byte_width = buf[-1] |
| 1514 | return Ref.PackedType( |
| 1515 | Buf(buf, -(2 + byte_width)), byte_width, packed_type=buf[-2]) |
| 1516 | |
| 1517 | |
| 1518 | def Dumps(obj): |
| 1519 | """Returns bytearray with the encoded python object.""" |
| 1520 | fbb = Builder() |
| 1521 | fbb.Add(obj) |
| 1522 | return fbb.Finish() |
| 1523 | |
| 1524 | |
| 1525 | def Loads(buf): |
| 1526 | """Returns python object decoded from the buffer.""" |
| 1527 | return GetRoot(buf).Value |