zlmdb 25.10.1__cp313-cp313-macosx_15_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of zlmdb might be problematic. Click here for more details.

Files changed (87) hide show
  1. flatbuffers/__init__.py +19 -0
  2. flatbuffers/_version.py +17 -0
  3. flatbuffers/builder.py +776 -0
  4. flatbuffers/compat.py +86 -0
  5. flatbuffers/encode.py +42 -0
  6. flatbuffers/flexbuffers.py +1527 -0
  7. flatbuffers/number_types.py +181 -0
  8. flatbuffers/packer.py +42 -0
  9. flatbuffers/reflection/AdvancedFeatures.py +10 -0
  10. flatbuffers/reflection/BaseType.py +24 -0
  11. flatbuffers/reflection/Enum.py +169 -0
  12. flatbuffers/reflection/EnumVal.py +96 -0
  13. flatbuffers/reflection/Field.py +208 -0
  14. flatbuffers/reflection/KeyValue.py +56 -0
  15. flatbuffers/reflection/Object.py +175 -0
  16. flatbuffers/reflection/RPCCall.py +131 -0
  17. flatbuffers/reflection/Schema.py +206 -0
  18. flatbuffers/reflection/SchemaFile.py +77 -0
  19. flatbuffers/reflection/Service.py +145 -0
  20. flatbuffers/reflection/Type.py +98 -0
  21. flatbuffers/reflection/__init__.py +0 -0
  22. flatbuffers/table.py +129 -0
  23. flatbuffers/util.py +43 -0
  24. zlmdb/__init__.py +312 -0
  25. zlmdb/_database.py +990 -0
  26. zlmdb/_errors.py +31 -0
  27. zlmdb/_meta.py +27 -0
  28. zlmdb/_pmap.py +1667 -0
  29. zlmdb/_schema.py +137 -0
  30. zlmdb/_transaction.py +181 -0
  31. zlmdb/_types.py +1596 -0
  32. zlmdb/_version.py +27 -0
  33. zlmdb/cli.py +41 -0
  34. zlmdb/flatbuffers/__init__.py +5 -0
  35. zlmdb/flatbuffers/reflection/AdvancedFeatures.py +10 -0
  36. zlmdb/flatbuffers/reflection/BaseType.py +25 -0
  37. zlmdb/flatbuffers/reflection/Enum.py +252 -0
  38. zlmdb/flatbuffers/reflection/EnumVal.py +144 -0
  39. zlmdb/flatbuffers/reflection/Field.py +325 -0
  40. zlmdb/flatbuffers/reflection/KeyValue.py +84 -0
  41. zlmdb/flatbuffers/reflection/Object.py +260 -0
  42. zlmdb/flatbuffers/reflection/RPCCall.py +195 -0
  43. zlmdb/flatbuffers/reflection/Schema.py +301 -0
  44. zlmdb/flatbuffers/reflection/SchemaFile.py +112 -0
  45. zlmdb/flatbuffers/reflection/Service.py +213 -0
  46. zlmdb/flatbuffers/reflection/Type.py +148 -0
  47. zlmdb/flatbuffers/reflection/__init__.py +0 -0
  48. zlmdb/flatbuffers/reflection.fbs +152 -0
  49. zlmdb/lmdb/__init__.py +37 -0
  50. zlmdb/lmdb/__main__.py +25 -0
  51. zlmdb/lmdb/_config.py +10 -0
  52. zlmdb/lmdb/_lmdb_cffi.cpython-313-darwin.so +0 -0
  53. zlmdb/lmdb/cffi.py +2606 -0
  54. zlmdb/lmdb/tool.py +670 -0
  55. zlmdb/tests/lmdb/__init__.py +0 -0
  56. zlmdb/tests/lmdb/address_book.py +287 -0
  57. zlmdb/tests/lmdb/crash_test.py +339 -0
  58. zlmdb/tests/lmdb/cursor_test.py +333 -0
  59. zlmdb/tests/lmdb/env_test.py +919 -0
  60. zlmdb/tests/lmdb/getmulti_test.py +92 -0
  61. zlmdb/tests/lmdb/iteration_test.py +258 -0
  62. zlmdb/tests/lmdb/package_test.py +70 -0
  63. zlmdb/tests/lmdb/test_lmdb.py +188 -0
  64. zlmdb/tests/lmdb/testlib.py +185 -0
  65. zlmdb/tests/lmdb/tool_test.py +60 -0
  66. zlmdb/tests/lmdb/txn_test.py +575 -0
  67. zlmdb/tests/orm/MNodeLog.py +853 -0
  68. zlmdb/tests/orm/__init__.py +0 -0
  69. zlmdb/tests/orm/_schema_fbs.py +215 -0
  70. zlmdb/tests/orm/_schema_mnode_log.py +1201 -0
  71. zlmdb/tests/orm/_schema_py2.py +250 -0
  72. zlmdb/tests/orm/_schema_py3.py +307 -0
  73. zlmdb/tests/orm/_test_flatbuffers.py +144 -0
  74. zlmdb/tests/orm/_test_serialization.py +144 -0
  75. zlmdb/tests/orm/test_basic.py +217 -0
  76. zlmdb/tests/orm/test_etcd.py +275 -0
  77. zlmdb/tests/orm/test_pmap_indexes.py +466 -0
  78. zlmdb/tests/orm/test_pmap_types.py +90 -0
  79. zlmdb/tests/orm/test_pmaps.py +295 -0
  80. zlmdb/tests/orm/test_select.py +619 -0
  81. zlmdb-25.10.1.dist-info/METADATA +264 -0
  82. zlmdb-25.10.1.dist-info/RECORD +87 -0
  83. zlmdb-25.10.1.dist-info/WHEEL +5 -0
  84. zlmdb-25.10.1.dist-info/entry_points.txt +2 -0
  85. zlmdb-25.10.1.dist-info/licenses/LICENSE +137 -0
  86. zlmdb-25.10.1.dist-info/licenses/NOTICE +41 -0
  87. zlmdb-25.10.1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,1527 @@
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