return struct.pack(fmt, tags.LIST, list_tag, len(payload)) + payload
+def _serialize_object(to):
+ raise Exception('Not implemented')
+
_TAGS_TO_SERIALIZERS = {
tags.NULL: _make_tag_only_serializer(tags.NULL, None),
tags.TRUE: _make_tag_only_serializer(tags.TRUE, True),
tags.UTF32: _make_string_serializer(lambda s: s.encode('utf-32')),
tags.TUPLE: _serialize_tuple,
tags.LIST: _serialize_list,
+ tags.OBJECT: _serialize_object,
}
def serialize(to):
# TODO Return tags = (tags.LIST, list_tag) to function like a generic type
return bytes_read, tags.TaggedObject(tag = tags.LIST, instance = instance)
+def _deserialize_object(b):
+ raise Exception('Not implemented')
+
_TAGS_TO_PARSERS = {
tags.NULL: _make_tag_only_parser(tags.NULL, None),
tags.TRUE: _make_tag_only_parser(tags.TRUE, True),
tags.UTF32: _make_string_deserializer(tags.UTF32, lambda b: b.decode('utf-32')),
tags.TUPLE: _deserialize_tuple,
tags.LIST: _deserialize_list,
+ tags.OBJECT: _deserialize_object,
}
def _deserialize_partial(b):
return '[\n' + _indent(',\n'.join(serialize(i) for i in to.instance)) + '\n]'
+def _serialize_key_value_pair(kvp):
+ assert isinstance(kvp, tuple)
+ key, value = kvp
+
+ assert key.tag in [tags.UTF8, tags.UTF16, tags.UTF32]
+
+ return '{}: {}'.format(serialize(key), serialize(value))
+
+def _serialize_object(to):
+ assert isinstance(to.instance, list)
+
+ return '{\n' + _indent(',\n'.join(_serialize_key_value_pair(kvp) for kvp in to.instance)) + '\n}'
+ raise Exception('Not implemented')
+
_SERIALIZERS = {
tags.NULL: _make_literal_serializer(None, 'null'),
tags.TRUE: _make_literal_serializer(True, 'true'),
tags.UTF16: _make_string_serializer('utf16'),
tags.UTF32: _make_string_serializer('utf32'),
tags.LIST: _serialize_list,
+ tags.OBJECT: _serialize_object,
}
def serialize(to):
return deserializer
def _deserialize_list(s):
- s = s.lstrip()
-
if not s.startswith('['):
return False, None, None
assert s.startswith(']')
return True, tags.TaggedObject(tag = tags.LIST, instance = instance), s[1:]
+def _deserialize_object(s):
+ if not s.startswith('{'):
+ return False, None, None
+
+ instance = []
+
+ s = s[1:].lstrip()
+
+ # TODO Handle empty objects
+
+ succeeded, key, s = _deserialize_one(s)
+
+ assert succeeded
+ assert key.tag in [tags.UTF8, tags.UTF16, tags.UTF32]
+
+ s = s.lstrip()
+ assert s.startswith(':')
+
+ s = s[1:].lstrip()
+
+ succeeded, value, s = _deserialize_one(s)
+
+ assert succeeded
+ instance.append((key, value))
+
+ s = s.lstrip()
+
+ while s.startswith(','):
+ succeeded, key, s = _deserialize_one(s)
+
+ assert succeeded
+ assert key.tag in [tags.UTF8, tags.UTF16, tags.UTF32]
+
+ s = s.lstrip()
+ assert s.startswith(':')
+
+ s = s[1:].lstrip()
+
+ succeeded, value, s = _deserialize_one(s)
+
+ assert succeeded
+ instance.append((key, value))
+
+ s = s.lstrip()
+
+ assert s.startswith('}')
+ return True, tags.TaggedObject(tag = tags.LIST, instance = instance), s[1:]
+
_DESERIALIZERS = [
_make_literal_deserializer(tags.NULL, None, 'null'),
_make_literal_deserializer(tags.TRUE, True, 'true'),
_make_string_deserializer(tags.UTF16, 'utf16'),
_make_string_deserializer(tags.UTF32, 'utf32'),
_deserialize_list,
+ _deserialize_object,
]
def _deserialize_one(s):
+ s = s.lstrip()
+
for deserializer in _DESERIALIZERS:
succeeded, result, remaining = deserializer(s)
),
b'\x31\x03\x00\x00\x00\x03\x09\x16\x24',
),
+ (
+ tags.TaggedObject(
+ tag = tags.OBJECT,
+ instance = [
+ (
+ tags.TaggedObject(tag = tags.UTF8, instance = 'foo'),
+ tags.TaggedObject(tag = tags.UTF8, instance = 'bar'),
+ ),
+ (
+ tags.TaggedObject(tag = tags.UTF8, instance = 'baz'),
+ tags.TaggedObject(tag = tags.UINT8, instance = 42),
+ ),
+ ],
+ ),
+ b'\x32\x21\x00\x00\x00\x03foo\x21\x00\x00\x00\x03bar\x00\x00\x00\x03baz\x03\x2a',
+ ),
]
class BinarySerializeTests(unittest.TestCase):
),
'[\n 9u8,\n 22u8,\n 36u8\n]'
),
+ (
+ tags.TaggedObject(
+ tag = tags.OBJECT,
+ instance = [
+ (
+ tags.TaggedObject(tag = tags.UTF8, instance = 'foo'),
+ tags.TaggedObject(tag = tags.UTF8, instance = 'bar'),
+ ),
+ (
+ tags.TaggedObject(tag = tags.UTF8, instance = 'baz'),
+ tags.TaggedObject(tag = tags.UINT8, instance = 42),
+ ),
+ ],
+ ),
+ '{\n utf8"foo": utf8"bar",\n utf8"baz": 42u8\n}',
+ ),
]
class TextSerializeTests(unittest.TestCase):