From d61097511a1caa0e3bc5a70c1d2d92f448bd5025 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Tue, 15 Oct 2013 16:59:43 +0200 Subject: add support for extended types: you can now pack/unpack custom python objects by subclassing Packer and Unpacker --- msgpack/fallback.py | 131 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 47 deletions(-) (limited to 'msgpack/fallback.py') diff --git a/msgpack/fallback.py b/msgpack/fallback.py index 8f9d646..b7f455b 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -58,54 +58,9 @@ TYPE_ARRAY = 1 TYPE_MAP = 2 TYPE_RAW = 3 -DEFAULT_RECURSE_LIMIT=511 - -def pack(o, stream, **kwargs): - """ - Pack object `o` and write it to `stream` - - See :class:`Packer` for options. - """ - packer = Packer(**kwargs) - stream.write(packer.pack(o)) - -def packb(o, **kwargs): - """ - Pack object `o` and return packed bytes +EXTENDED_TYPE = 1000 - See :class:`Packer` for options. - """ - return Packer(**kwargs).pack(o) - -def unpack(stream, **kwargs): - """ - Unpack an object from `stream`. - - Raises `ExtraData` when `packed` contains extra bytes. - See :class:`Unpacker` for options. - """ - unpacker = Unpacker(stream, **kwargs) - ret = unpacker._fb_unpack() - if unpacker._fb_got_extradata(): - raise ExtraData(ret, unpacker._fb_get_extradata()) - return ret - -def unpackb(packed, **kwargs): - """ - Unpack an object from `packed`. - - Raises `ExtraData` when `packed` contains extra bytes. - See :class:`Unpacker` for options. - """ - unpacker = Unpacker(None, **kwargs) - unpacker.feed(packed) - try: - ret = unpacker._fb_unpack() - except OutOfData: - raise UnpackValueError("Data is not enough.") - if unpacker._fb_got_extradata(): - raise ExtraData(ret, unpacker._fb_get_extradata()) - return ret +DEFAULT_RECURSE_LIMIT=511 class Unpacker(object): """ @@ -334,6 +289,9 @@ class Unpacker(object): elif b == 0xdf: n = struct.unpack(">I", self._fb_read(4, write_bytes))[0] typ = TYPE_MAP + elif b == 0xc9: + n, typ = struct.unpack(">Ib", self._fb_read(5, write_bytes)) + typ += EXTENDED_TYPE else: raise UnpackValueError("Unknown header: 0x%x" % b) return typ, n, obj @@ -390,6 +348,10 @@ class Unpacker(object): if self._encoding is not None: obj = obj.decode(self._encoding, self._unicode_errors) return obj + if typ >= EXTENDED_TYPE: + typ -= EXTENDED_TYPE + data = self._fb_read(n, write_bytes) + return self.handle_extended_type(typ, data) assert typ == TYPE_IMMEDIATE return obj @@ -411,6 +373,9 @@ class Unpacker(object): self._fb_consume() return ret + def handle_extended_type(self, typecode, data): + raise NotImplementedError("Cannot decode extended type with typecode=%d" % typecode) + def read_array_header(self, write_bytes=None): ret = self._fb_unpack(EX_READ_ARRAY_HEADER, write_bytes) self._fb_consume() @@ -521,10 +486,33 @@ class Packer(object): if isinstance(obj, dict): return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj), nest_limit - 1) + if self.pack_extended_type(obj): + # it means that obj was succesfully handled by + # handle_extended_type, so we are done + return if self._default is not None: return self._pack(self._default(obj), nest_limit - 1) raise TypeError("Cannot serialize %r" % obj) + def pack_extended_type(self, obj): + res = self.handle_extended_type(obj) + if res is None: + return False + fmt, typecode, data = res + # for now we support only this. We should add support for the other + # fixext/ext formats + assert fmt == "ext 32" + assert 0 <= typecode <= 127 + N = len(data) + self._buffer.write(struct.pack('>BIB', 0xc9, N, typecode)) + self._buffer.write(data) + return True + + def handle_extended_type(self, obj): + # by default we don't support any extended type. This can be + # overridden by subclasses + return None + def pack(self, obj): self._pack(obj) ret = self._buffer.getvalue() @@ -590,3 +578,52 @@ class Packer(object): def reset(self): self._buffer = StringIO() + + +def pack(o, stream, Packer=Packer, **kwargs): + """ + Pack object `o` and write it to `stream` + + See :class:`Packer` for options. + """ + packer = Packer(**kwargs) + stream.write(packer.pack(o)) + +def packb(o, Packer=Packer, **kwargs): + """ + Pack object `o` and return packed bytes + + See :class:`Packer` for options. + """ + return Packer(**kwargs).pack(o) + +def unpack(stream, Unpacker=Unpacker, **kwargs): + """ + Unpack an object from `stream`. + + Raises `ExtraData` when `packed` contains extra bytes. + See :class:`Unpacker` for options. + """ + unpacker = Unpacker(stream, **kwargs) + ret = unpacker._fb_unpack() + if unpacker._fb_got_extradata(): + raise ExtraData(ret, unpacker._fb_get_extradata()) + return ret + +def unpackb(packed, Unpacker=Unpacker, **kwargs): + """ + Unpack an object from `packed`. + + Raises `ExtraData` when `packed` contains extra bytes. + See :class:`Unpacker` for options. + """ + unpacker = Unpacker(None, **kwargs) + unpacker.feed(packed) + try: + ret = unpacker._fb_unpack() + except OutOfData: + raise UnpackValueError("Data is not enough.") + if unpacker._fb_got_extradata(): + raise ExtraData(ret, unpacker._fb_get_extradata()) + return ret + -- cgit v1.2.1 From 5529dfe59660f3c2fc5058e6fa42b24fe764a255 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 18 Oct 2013 14:38:52 +0200 Subject: kill some duplicate code from unpack/unpackb and move the logic to Unpacker.unpack_one. By doing this we no longer need to make the module-level pack/unpack parametric on the class, because they contain no logic at all --- msgpack/fallback.py | 95 ++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 48 deletions(-) (limited to 'msgpack/fallback.py') diff --git a/msgpack/fallback.py b/msgpack/fallback.py index b7f455b..2c79482 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -62,6 +62,44 @@ EXTENDED_TYPE = 1000 DEFAULT_RECURSE_LIMIT=511 +def pack(o, stream, **kwargs): + """ + Pack object `o` and write it to `stream` + + See :class:`Packer` for options. + """ + packer = Packer(**kwargs) + stream.write(packer.pack(o)) + +def packb(o, **kwargs): + """ + Pack object `o` and return packed bytes + + See :class:`Packer` for options. + """ + return Packer(**kwargs).pack(o) + +def unpack(stream, **kwargs): + """ + Unpack an object from `stream`. + + Raises `ExtraData` when `packed` contains extra bytes. + See :class:`Unpacker` for options. + """ + unpacker = Unpacker(stream, **kwargs) + return unpacker.unpack_one() + +def unpackb(packed, **kwargs): + """ + Unpack an object from `packed`. + + Raises `ExtraData` when `packed` contains extra bytes. + See :class:`Unpacker` for options. + """ + unpacker = Unpacker(None, **kwargs) + unpacker.feed(packed) + return unpacker.unpack_one() + class Unpacker(object): """ Streaming unpacker. @@ -149,6 +187,15 @@ class Unpacker(object): raise ValueError("object_pairs_hook and object_hook are mutually " "exclusive") + def unpack_one(self): + try: + ret = self._fb_unpack() + except OutOfData: + raise UnpackValueError("Data is not enough.") + if self._fb_got_extradata(): + raise ExtraData(ret, self._fb_get_extradata()) + return ret + def feed(self, next_bytes): if isinstance(next_bytes, array.array): next_bytes = next_bytes.tostring() @@ -579,51 +626,3 @@ class Packer(object): def reset(self): self._buffer = StringIO() - -def pack(o, stream, Packer=Packer, **kwargs): - """ - Pack object `o` and write it to `stream` - - See :class:`Packer` for options. - """ - packer = Packer(**kwargs) - stream.write(packer.pack(o)) - -def packb(o, Packer=Packer, **kwargs): - """ - Pack object `o` and return packed bytes - - See :class:`Packer` for options. - """ - return Packer(**kwargs).pack(o) - -def unpack(stream, Unpacker=Unpacker, **kwargs): - """ - Unpack an object from `stream`. - - Raises `ExtraData` when `packed` contains extra bytes. - See :class:`Unpacker` for options. - """ - unpacker = Unpacker(stream, **kwargs) - ret = unpacker._fb_unpack() - if unpacker._fb_got_extradata(): - raise ExtraData(ret, unpacker._fb_get_extradata()) - return ret - -def unpackb(packed, Unpacker=Unpacker, **kwargs): - """ - Unpack an object from `packed`. - - Raises `ExtraData` when `packed` contains extra bytes. - See :class:`Unpacker` for options. - """ - unpacker = Unpacker(None, **kwargs) - unpacker.feed(packed) - try: - ret = unpacker._fb_unpack() - except OutOfData: - raise UnpackValueError("Data is not enough.") - if unpacker._fb_got_extradata(): - raise ExtraData(ret, unpacker._fb_get_extradata()) - return ret - -- cgit v1.2.1 From 522c4bfc7993c296b78df9c9c91aac5fd40ae8e0 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 18 Oct 2013 15:03:58 +0200 Subject: slightly change to API --- msgpack/fallback.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'msgpack/fallback.py') diff --git a/msgpack/fallback.py b/msgpack/fallback.py index 2c79482..101bd0f 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -398,7 +398,7 @@ class Unpacker(object): if typ >= EXTENDED_TYPE: typ -= EXTENDED_TYPE data = self._fb_read(n, write_bytes) - return self.handle_extended_type(typ, data) + return self.read_extended_type(typ, data) assert typ == TYPE_IMMEDIATE return obj @@ -420,7 +420,7 @@ class Unpacker(object): self._fb_consume() return ret - def handle_extended_type(self, typecode, data): + def read_extended_type(self, typecode, data): raise NotImplementedError("Cannot decode extended type with typecode=%d" % typecode) def read_array_header(self, write_bytes=None): @@ -533,19 +533,19 @@ class Packer(object): if isinstance(obj, dict): return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj), nest_limit - 1) - if self.pack_extended_type(obj): - # it means that obj was succesfully handled by - # handle_extended_type, so we are done + if self.handle_unknown_type(obj): + # it means that obj was succesfully packed, so we are done return if self._default is not None: return self._pack(self._default(obj), nest_limit - 1) raise TypeError("Cannot serialize %r" % obj) - def pack_extended_type(self, obj): - res = self.handle_extended_type(obj) - if res is None: - return False - fmt, typecode, data = res + def handle_unknown_type(self, obj): + # by default we don't support any extended type. This can be + # overridden by subclasses + return None + + def pack_extended_type(self, fmt, typecode, data): # for now we support only this. We should add support for the other # fixext/ext formats assert fmt == "ext 32" @@ -553,12 +553,6 @@ class Packer(object): N = len(data) self._buffer.write(struct.pack('>BIB', 0xc9, N, typecode)) self._buffer.write(data) - return True - - def handle_extended_type(self, obj): - # by default we don't support any extended type. This can be - # overridden by subclasses - return None def pack(self, obj): self._pack(obj) -- cgit v1.2.1 From c727440ba5fe2f77d6cc03171ad7c193a3f481ee Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 18 Oct 2013 15:45:50 +0200 Subject: automatically find the best format to encode extended types --- msgpack/fallback.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'msgpack/fallback.py') diff --git a/msgpack/fallback.py b/msgpack/fallback.py index 101bd0f..f984dcd 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -545,13 +545,29 @@ class Packer(object): # overridden by subclasses return None - def pack_extended_type(self, fmt, typecode, data): - # for now we support only this. We should add support for the other - # fixext/ext formats - assert fmt == "ext 32" + def pack_extended_type(self, typecode, data): assert 0 <= typecode <= 127 - N = len(data) - self._buffer.write(struct.pack('>BIB', 0xc9, N, typecode)) + n = len(data) + if n == 1: + header = struct.pack(">BB", 0xd4, typecode) # fixext 1 + elif n == 2: + header = struct.pack(">BB", 0xd5, typecode) # fixext 2 + elif n == 4: + header = struct.pack(">BB", 0xd6, typecode) # fixext 4 + elif n == 8: + header = struct.pack(">BB", 0xd7, typecode) # fixext 8 + elif n == 16: + header = struct.pack(">BB", 0xd8, typecode) # fixext 16 + elif n <= 2**8-1: + header = struct.pack(">BBB", 0xc7, n, typecode) # ext 8 + elif n <= 2**16-1: + header = struct.pack(">BHB", 0xc8, n, typecode) # ext 16 + elif n <= 2**32-1: + header = struct.pack(">BIB", 0xc9, n, typecode) # ext 32 + else: + raise PackValueError("ext data too large") + # + self._buffer.write(header) self._buffer.write(data) def pack(self, obj): -- cgit v1.2.1 From afa28fb2051cb00f03c83e020745e1eb238ff4ac Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 18 Oct 2013 15:54:12 +0200 Subject: add support to unpack all ext formats --- msgpack/fallback.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'msgpack/fallback.py') diff --git a/msgpack/fallback.py b/msgpack/fallback.py index f984dcd..c272420 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -336,7 +336,33 @@ class Unpacker(object): elif b == 0xdf: n = struct.unpack(">I", self._fb_read(4, write_bytes))[0] typ = TYPE_MAP - elif b == 0xc9: + elif b == 0xd4: # fixext 1 + typ = struct.unpack(">B", self._fb_read(1, write_bytes))[0] + n = 1 + typ += EXTENDED_TYPE + elif b == 0xd5: # fixext 2 + typ = struct.unpack(">B", self._fb_read(1, write_bytes))[0] + n = 2 + typ += EXTENDED_TYPE + elif b == 0xd6: # fixext 4 + typ = struct.unpack(">B", self._fb_read(1, write_bytes))[0] + n = 4 + typ += EXTENDED_TYPE + elif b == 0xd7: # fixext 8 + typ = struct.unpack(">B", self._fb_read(1, write_bytes))[0] + n = 8 + typ += EXTENDED_TYPE + elif b == 0xd8: # fixext 16 + typ = struct.unpack(">B", self._fb_read(1, write_bytes))[0] + n = 16 + typ += EXTENDED_TYPE + elif b == 0xc7: # ext 8 + n, typ = struct.unpack(">Bb", self._fb_read(2, write_bytes)) + typ += EXTENDED_TYPE + elif b == 0xc8: # ext 16 + n, typ = struct.unpack(">Hb", self._fb_read(3, write_bytes)) + typ += EXTENDED_TYPE + elif b == 0xc9: # ext 32 n, typ = struct.unpack(">Ib", self._fb_read(5, write_bytes)) typ += EXTENDED_TYPE else: -- cgit v1.2.1 From aa68c9b8330b130d600b22ec47d5c3841499b536 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Sun, 20 Oct 2013 15:40:20 +0900 Subject: fallback: Support pack_ext_type. --- msgpack/fallback.py | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) (limited to 'msgpack/fallback.py') diff --git a/msgpack/fallback.py b/msgpack/fallback.py index dfaaa54..0b29700 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -42,11 +42,11 @@ else: newlist_hint = lambda size: [] from msgpack.exceptions import ( - BufferFull, - OutOfData, - UnpackValueError, - PackValueError, - ExtraData) + BufferFull, + OutOfData, + UnpackValueError, + PackValueError, + ExtraData) from msgpack import ExtType @@ -65,6 +65,7 @@ TYPE_EXT = 5 DEFAULT_RECURSE_LIMIT = 511 + def unpack(stream, **kwargs): """ Unpack an object from `stream`. @@ -78,6 +79,7 @@ def unpack(stream, **kwargs): raise ExtraData(ret, unpacker._fb_get_extradata()) return ret + def unpackb(packed, **kwargs): """ Unpack an object from `packed`. @@ -95,6 +97,7 @@ def unpackb(packed, **kwargs): raise ExtraData(ret, unpacker._fb_get_extradata()) return ret + class Unpacker(object): """ Streaming unpacker. @@ -548,8 +551,8 @@ class Packer(object): if isinstance(obj, Unicode): if self._encoding is None: raise TypeError( - "Can't encode unicode string: " - "no encoding is specified") + "Can't encode unicode string: " + "no encoding is specified") obj = obj.encode(self._encoding, self._unicode_errors) n = len(obj) if n <= 0x1f: @@ -616,6 +619,35 @@ class Packer(object): self._buffer = StringIO(ret) return ret + def pack_ext_type(self, typecode, data): + if not isinstance(typecode, int): + raise TypeError("typecode must have int type.") + if not 0 <= typecode <= 127: + raise ValueError("typecode should be 0-127") + if not isinstance(data, bytes): + raise TypeError("data must have bytes type") + L = len(data) + if L > 0xffffffff: + raise ValueError("Too large data") + if L == 1: + self._buffer.write(b'\xd4') + elif L == 2: + self._buffer.write(b'\xd5') + elif L == 4: + self._buffer.write(b'\xd6') + elif L == 8: + self._buffer.write(b'\xd7') + elif L == 16: + self._buffer.write(b'\xd8') + elif L <= 0xff: + self._buffer.write(b'\xc7' + struct.pack('B', L)) + elif L <= 0xffff: + self._buffer.write(b'\xc8' + struct.pack('>H', L)) + else: + self._buffer.write(b'\xc9' + struct.pack('>I', L)) + self._buffer.write(struct.pack('B', typecode)) + self._buffer.write(data) + def _fb_pack_array_header(self, n): if n <= 0x0f: return self._buffer.write(struct.pack('B', 0x90 + n)) -- cgit v1.2.1 From e3fee4db5fbf1ead4a98fff6c8843574480c3c2a Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Mon, 21 Oct 2013 00:59:22 +0900 Subject: fallback: support packing ExtType --- msgpack/fallback.py | 181 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 105 insertions(+), 76 deletions(-) (limited to 'msgpack/fallback.py') diff --git a/msgpack/fallback.py b/msgpack/fallback.py index 0b29700..bf5b1c2 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -506,82 +506,111 @@ class Packer(object): self._default = default def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance): - if nest_limit < 0: - raise PackValueError("recursion limit exceeded") - if obj is None: - return self._buffer.write(b"\xc0") - if isinstance(obj, bool): - if obj: - return self._buffer.write(b"\xc3") - return self._buffer.write(b"\xc2") - if isinstance(obj, int_types): - if 0 <= obj < 0x80: - return self._buffer.write(struct.pack("B", obj)) - if -0x20 <= obj < 0: - return self._buffer.write(struct.pack("b", obj)) - if 0x80 <= obj <= 0xff: - return self._buffer.write(struct.pack("BB", 0xcc, obj)) - if -0x80 <= obj < 0: - return self._buffer.write(struct.pack(">Bb", 0xd0, obj)) - if 0xff < obj <= 0xffff: - return self._buffer.write(struct.pack(">BH", 0xcd, obj)) - if -0x8000 <= obj < -0x80: - return self._buffer.write(struct.pack(">Bh", 0xd1, obj)) - if 0xffff < obj <= 0xffffffff: - return self._buffer.write(struct.pack(">BI", 0xce, obj)) - if -0x80000000 <= obj < -0x8000: - return self._buffer.write(struct.pack(">Bi", 0xd2, obj)) - if 0xffffffff < obj <= 0xffffffffffffffff: - return self._buffer.write(struct.pack(">BQ", 0xcf, obj)) - if -0x8000000000000000 <= obj < -0x80000000: - return self._buffer.write(struct.pack(">Bq", 0xd3, obj)) - raise PackValueError("Integer value out of range") - if self._use_bin_type and isinstance(obj, bytes): - n = len(obj) - if n <= 0xff: - self._buffer.write(struct.pack('>BB', 0xc4, n)) - elif n <= 0xffff: - self._buffer.write(struct.pack(">BH", 0xc5, n)) - elif n <= 0xffffffff: - self._buffer.write(struct.pack(">BI", 0xc6, n)) - else: - raise PackValueError("Bytes is too large") - return self._buffer.write(obj) - if isinstance(obj, (Unicode, bytes)): - if isinstance(obj, Unicode): - if self._encoding is None: - raise TypeError( - "Can't encode unicode string: " - "no encoding is specified") - obj = obj.encode(self._encoding, self._unicode_errors) - n = len(obj) - if n <= 0x1f: - self._buffer.write(struct.pack('B', 0xa0 + n)) - elif self._use_bin_type and n <= 0xff: - self._buffer.write(struct.pack('>BB', 0xd9, n)) - elif n <= 0xffff: - self._buffer.write(struct.pack(">BH", 0xda, n)) - elif n <= 0xffffffff: - self._buffer.write(struct.pack(">BI", 0xdb, n)) - else: - raise PackValueError("String is too large") - return self._buffer.write(obj) - if isinstance(obj, float): - if self._use_float: - return self._buffer.write(struct.pack(">Bf", 0xca, obj)) - return self._buffer.write(struct.pack(">Bd", 0xcb, obj)) - if isinstance(obj, (list, tuple)): - n = len(obj) - self._fb_pack_array_header(n) - for i in xrange(n): - self._pack(obj[i], nest_limit - 1) - return - if isinstance(obj, dict): - return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj), - nest_limit - 1) - if self._default is not None: - return self._pack(self._default(obj), nest_limit - 1) - raise TypeError("Cannot serialize %r" % obj) + default_used = False + while True: + if nest_limit < 0: + raise PackValueError("recursion limit exceeded") + if obj is None: + return self._buffer.write(b"\xc0") + if isinstance(obj, bool): + if obj: + return self._buffer.write(b"\xc3") + return self._buffer.write(b"\xc2") + if isinstance(obj, int_types): + if 0 <= obj < 0x80: + return self._buffer.write(struct.pack("B", obj)) + if -0x20 <= obj < 0: + return self._buffer.write(struct.pack("b", obj)) + if 0x80 <= obj <= 0xff: + return self._buffer.write(struct.pack("BB", 0xcc, obj)) + if -0x80 <= obj < 0: + return self._buffer.write(struct.pack(">Bb", 0xd0, obj)) + if 0xff < obj <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xcd, obj)) + if -0x8000 <= obj < -0x80: + return self._buffer.write(struct.pack(">Bh", 0xd1, obj)) + if 0xffff < obj <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xce, obj)) + if -0x80000000 <= obj < -0x8000: + return self._buffer.write(struct.pack(">Bi", 0xd2, obj)) + if 0xffffffff < obj <= 0xffffffffffffffff: + return self._buffer.write(struct.pack(">BQ", 0xcf, obj)) + if -0x8000000000000000 <= obj < -0x80000000: + return self._buffer.write(struct.pack(">Bq", 0xd3, obj)) + raise PackValueError("Integer value out of range") + if self._use_bin_type and isinstance(obj, bytes): + n = len(obj) + if n <= 0xff: + self._buffer.write(struct.pack('>BB', 0xc4, n)) + elif n <= 0xffff: + self._buffer.write(struct.pack(">BH", 0xc5, n)) + elif n <= 0xffffffff: + self._buffer.write(struct.pack(">BI", 0xc6, n)) + else: + raise PackValueError("Bytes is too large") + return self._buffer.write(obj) + if isinstance(obj, (Unicode, bytes)): + if isinstance(obj, Unicode): + if self._encoding is None: + raise TypeError( + "Can't encode unicode string: " + "no encoding is specified") + obj = obj.encode(self._encoding, self._unicode_errors) + n = len(obj) + if n <= 0x1f: + self._buffer.write(struct.pack('B', 0xa0 + n)) + elif self._use_bin_type and n <= 0xff: + self._buffer.write(struct.pack('>BB', 0xd9, n)) + elif n <= 0xffff: + self._buffer.write(struct.pack(">BH", 0xda, n)) + elif n <= 0xffffffff: + self._buffer.write(struct.pack(">BI", 0xdb, n)) + else: + raise PackValueError("String is too large") + return self._buffer.write(obj) + if isinstance(obj, float): + if self._use_float: + return self._buffer.write(struct.pack(">Bf", 0xca, obj)) + return self._buffer.write(struct.pack(">Bd", 0xcb, obj)) + if isinstance(obj, ExtType): + code = obj.code + data = obj.data + assert isinstance(code, int) + assert isinstance(data, bytes) + L = len(data) + if L == 1: + self._buffer.write(b'\xd4') + elif L == 2: + self._buffer.write(b'\xd5') + elif L == 4: + self._buffer.write(b'\xd6') + elif L == 8: + self._buffer.write(b'\xd7') + elif L == 16: + self._buffer.write(b'\xd8') + elif L <= 0xff: + self._buffer.write(struct.pack(">BB", 0xc7, L)) + elif L <= 0xffff: + self._buffer.write(struct.pack(">BH", 0xc8, L)) + else: + self._buffer.write(struct.pack(">BI", 0xc9, L)) + self._buffer.write(struct.pack("b", code)) + self._buffer.write(data) + return + if isinstance(obj, (list, tuple)): + n = len(obj) + self._fb_pack_array_header(n) + for i in xrange(n): + self._pack(obj[i], nest_limit - 1) + return + if isinstance(obj, dict): + return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj), + nest_limit - 1) + if not default_used and self._default is not None: + obj = self._default(obj) + default_used = 1 + continue + raise TypeError("Cannot serialize %r" % obj) def pack(self, obj): self._pack(obj) -- cgit v1.2.1