diff options
author | martinko | 2013-04-18 13:30:35 +0000 |
---|---|---|
committer | martinko | 2013-04-18 13:30:35 +0000 |
commit | 12337937d4abf65bafafbb98aefb8751f807ed97 (patch) | |
tree | 8868e4ad6e19c97fd86eb22f07f053c321967033 /python/skytools/tnetstrings.py | |
parent | 6c216f7aca9e3cfc63ca4c1f339d4565c93b3c45 (diff) |
skytools.skylog: initial implementation of UdpTNetStringsHandler
Diffstat (limited to 'python/skytools/tnetstrings.py')
-rw-r--r-- | python/skytools/tnetstrings.py | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/python/skytools/tnetstrings.py b/python/skytools/tnetstrings.py new file mode 100644 index 00000000..afacc09e --- /dev/null +++ b/python/skytools/tnetstrings.py @@ -0,0 +1,115 @@ +# Note this implementation is more strict than necessary to demonstrate +# minimum restrictions on types allowed in dictionaries. + +def dump(data): + if type(data) is long or type(data) is int: + out = str(data) + return '%d:%s#' % (len(out), out) + elif type(data) is float: + out = '%f' % data + return '%d:%s^' % (len(out), out) + elif type(data) is str: + return '%d:' % len(data) + data + ',' + elif type(data) is dict: + return dump_dict(data) + elif type(data) is list: + return dump_list(data) + elif data == None: + return '0:~' + elif type(data) is bool: + out = repr(data).lower() + return '%d:%s!' % (len(out), out) + else: + assert False, "Can't serialize stuff that's %s." % type(data) + + +def parse(data): + payload, payload_type, remain = parse_payload(data) + + if payload_type == '#': + value = int(payload) + elif payload_type == '}': + value = parse_dict(payload) + elif payload_type == ']': + value = parse_list(payload) + elif payload_type == '!': + value = payload == 'true' + elif payload_type == '^': + value = float(payload) + elif payload_type == '~': + assert len(payload) == 0, "Payload must be 0 length for null." + value = None + elif payload_type == ',': + value = payload + else: + assert False, "Invalid payload type: %r" % payload_type + + return value, remain + +def parse_payload(data): + assert data, "Invalid data to parse, it's empty." + length, extra = data.split(':', 1) + length = int(length) + + payload, extra = extra[:length], extra[length:] + assert extra, "No payload type: %r, %r" % (payload, extra) + payload_type, remain = extra[0], extra[1:] + + assert len(payload) == length, "Data is wrong length %d vs %d" % (length, len(payload)) + return payload, payload_type, remain + +def parse_list(data): + if len(data) == 0: return [] + + result = [] + value, extra = parse(data) + result.append(value) + + while extra: + value, extra = parse(extra) + result.append(value) + + return result + +def parse_pair(data): + key, extra = parse(data) + assert extra, "Unbalanced dictionary store." + value, extra = parse(extra) + + return key, value, extra + +def parse_dict(data): + if len(data) == 0: return {} + + key, value, extra = parse_pair(data) + assert type(key) is str, "Keys can only be strings." + + result = {key: value} + + while extra: + key, value, extra = parse_pair(extra) + result[key] = value + + return result + + + +def dump_dict(data): + result = [] + for k,v in data.items(): + result.append(dump(str(k))) + result.append(dump(v)) + + payload = ''.join(result) + return '%d:' % len(payload) + payload + '}' + + +def dump_list(data): + result = [] + for i in data: + result.append(dump(i)) + + payload = ''.join(result) + return '%d:' % len(payload) + payload + ']' + + |