22 DEFAULT_INTEGER_ENCODING = INT32
23 DEFAULT_DECIMAL_ENCODING = DOUBLE
24 DEFAULT_STRING_ENCODING = UTF8
26 TaggedObject = collections.namedtuple('TaggedObject', ['tag', 'value'])
29 int: DEFAULT_INTEGER_ENCODING,
30 float: DEFAULT_DECIMAL_ENCODING,
32 str: DEFAULT_STRING_ENCODING,
35 collections.OrderedDict: DICTIONARY,
39 if isinstance(o, TaggedObject):
43 return TaggedObject(tag = VOID, value = o)
46 return TaggedObject(tag = TRUE, value = o)
49 return TaggedObject(tag = FALSE, value = o)
51 return TaggedObject(tag = _TYPES_TO_TAGS[type(o)], value = o)
53 def _binary_serialize_tag_only_type(o):
56 def _pack_format_string_to_binary_serializer(pfs):
58 return struct.pack(pfs, i)
61 def _encoder_to_binary_serializer(e):
64 return struct.pack('!I', len(encoded)) + encoded
67 def _binary_serialize_list(items):
68 # TODO Enforce that items are all the same type
69 items = [_tag(i) for i in items]
74 item_tag = items[0].tag
76 item_serializer = _BINARY_SERIALIZERS[item_tag]
77 items = [item_serializer(i.value) for i in items]
78 item_length = len(items)
79 items = b''.join(items)
80 byte_length = len(items)
81 return struct.pack('!BII', item_tag, byte_length, item_length) + items
83 def _binary_serialize_dict(d):
87 key_serializer = _BINARY_SERIALIZERS[UTF8]
89 for key, value in d.items():
90 assert isinstance(key, str)
92 serialized += key_serializer(key) + _binary_serialize(value)
94 byte_length = len(serialized)
95 return struct.pack('!II', byte_length, item_length) + serialized
97 _BINARY_SERIALIZERS = {
98 VOID: _binary_serialize_tag_only_type,
99 TRUE: _binary_serialize_tag_only_type,
100 FALSE: _binary_serialize_tag_only_type,
101 INT8: _pack_format_string_to_binary_serializer('!b'),
102 INT16: _pack_format_string_to_binary_serializer('!h'),
103 INT32: _pack_format_string_to_binary_serializer('!i'),
104 FLOAT: _pack_format_string_to_binary_serializer('!f'),
105 DOUBLE: _pack_format_string_to_binary_serializer('!d'),
106 BINARY: _encoder_to_binary_serializer(lambda b: b),
107 UTF8: _encoder_to_binary_serializer(lambda s: s.encode('utf-8')),
108 UTF16: _encoder_to_binary_serializer(lambda s: s.encode('utf-16')),
109 UTF32: _encoder_to_binary_serializer(lambda s: s.encode('utf-32')),
110 LIST: _binary_serialize_list,
111 DICTIONARY: _binary_serialize_dict,
114 def _binary_serialize(o):
116 return struct.pack('!B', o.tag) + _BINARY_SERIALIZERS[o.tag](o.value)
118 ParseResult = collections.namedtuple(
127 _FAILED_PARSE_RESULT = ParseResult(success = False, value = None, remaining = None)
129 _BYTE_SIZES_TO_UNPACK_FORMATS = {
136 def make_integer_parser(size_in_bytes):
137 unpack_format = _BYTE_SIZES_TO_UNPACK_FORMATS[size_in_bytes]
139 def integer_parser(source):
140 value = struct.unpack(unpack_format, source[:size_in_bytes])[0]
141 remaining = source[size_in_bytes:]
143 return ParseResult(success = True, value = value, remaining = remaining)
145 return integer_parser
147 def binary64_parser(source):
150 value = struct.unpack('!d', source[:8])[0],
151 remaining = source[8:],
154 def make_string_parser(decoder):
155 def string_parser(source):
156 length = struct.unpack('!I', source[:4])[0]
160 value = decoder(source[:length]),
161 remaining = source[length:],
166 def _list_parser(source):
168 parser = _TAGS_TO_PARSERS[tag]
171 byte_length, items_length = struct.unpack('!II', source[:8])
174 remaining = source[byte_length:]
175 source = source[:byte_length]
177 def item_iterator(source):
180 while len(source) > 0:
181 parse_result = parser(source)
183 if parse_result.success:
185 yield parse_result.value
186 source = parse_result.remaining
188 assert count == items_length
192 value = item_iterator(source),
193 remaining = remaining,
196 def dictionary_parser(source):
197 key_parser = _TAGS_TO_PARSERS[UTF8]
199 byte_length, item_length = struct.unpack('!II', source[:8])
202 remaining = source[byte_length:]
203 source = source[:byte_length]
205 def kvp_iterator(source):
208 while len(source) > 0:
210 key_parse_result = key_parser(source)
211 key, source = key_parse_result.value, key_parse_result.remaining
212 value_parse_result = _object_parser(source)
213 value, source = value_parse_result.value, value_parse_result.remaining
217 assert count == item_length
221 value = collections.OrderedDict(kvp_iterator(source)),
222 remaining = remaining,
227 VOID: lambda r: ParseResult(True, None, r),
228 TRUE: lambda r: ParseResult(True, True, r),
229 FALSE: lambda r: ParseResult(True, False, r),
230 INT8: make_integer_parser(1),
231 INT16: make_integer_parser(2),
232 INT32: make_integer_parser(4),
233 INT64: make_integer_parser(8),
234 DOUBLE: binary64_parser,
235 BINARY: make_string_parser(lambda b : b),
236 UTF8: make_string_parser(lambda b : b.decode('utf-8')),
237 UTF16: make_string_parser(lambda b : b.decode('utf-16')),
238 UTF32: make_string_parser(lambda b : b.decode('utf-32')),
240 DICTIONARY: dictionary_parser,
243 def _object_parser(source):
244 return _TAGS_TO_PARSERS[source[0]](source[1:])
246 def _parse(parser, source, consume_all = True):
247 result = parser(source)
249 if result.success and result.remaining == b'':
252 raise Exception('Unparsed trailing bytes: {}'.format(result.remaining))
254 def _binary_deserialize(b):
255 return _parse(_object_parser, b)
257 def _integer_size_to_string_serializer(integer_size):
258 minimum = -(2 ** (integer_size - 1))
259 maximum = 2 ** (integer_size - 1) - 1
261 def serializer(integer):
262 assert minimum <= integer and integer <= maximum
263 return '{}i{}'.format(integer, integer_size)
267 def _serialize_float(f):
268 return '{}f'.format(f)
270 def _serialize_double(d):
271 return '{}d'.format(d)
273 def _serialize_binary(b):
274 return '"{}"b'.format(binascii.hexlify(b).decode('ascii'))
276 def _utf_encoding_to_serializer(utf_encoding):
278 return '"{}"{}'.format(s, utf_encoding)
282 def _string_serialize_list(l):
283 return '[{}]'.format(', '.join(map(_string_serialize, l)))
285 def _string_serialize_dictionary(d):
286 def serialize_kvp(kvp):
287 return _string_serialize(kvp[0]) + ': ' + _string_serialize(kvp[1])
288 return '{ ' + ', '.join(map(serialize_kvp, d.items())) + ' }'
290 _STRING_SERIALIZERS = {
291 VOID: lambda o: 'null',
292 TRUE: lambda o: 'true',
293 FALSE: lambda o: 'false',
294 INT8: _integer_size_to_string_serializer(8),
295 INT16: _integer_size_to_string_serializer(16),
296 INT32: _integer_size_to_string_serializer(32),
297 INT64: _integer_size_to_string_serializer(64),
298 FLOAT: _serialize_float,
299 DOUBLE: _serialize_double,
300 BINARY: _serialize_binary,
301 UTF8: _utf_encoding_to_serializer('utf8'),
302 UTF16: _utf_encoding_to_serializer('utf16'),
303 UTF32: _utf_encoding_to_serializer('utf32'),
304 LIST: _string_serialize_list,
305 DICTIONARY: _string_serialize_dictionary,
308 def _string_serialize(o):
311 return _STRING_SERIALIZERS[o.tag](o.value)
313 def _string_deserialize(o):
316 Serializer = collections.namedtuple('Serializer', ['serialize', 'deserialize'])
319 serialize = _binary_serialize,
320 deserialize = _binary_deserialize,
324 serialize = _string_serialize,
325 deserialize = _string_deserialize,
328 def binary_to_string(b):
329 return string.serialize(binary.deserialize(b))
331 def string_to_binary(s):
332 return binary.serialize(string.deserialize(s))