summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorINADA Naoki <inada-n@klab.com>2013-10-21 00:59:22 +0900
committerINADA Naoki <inada-n@klab.com>2013-10-21 00:59:22 +0900
commite3fee4db5fbf1ead4a98fff6c8843574480c3c2a (patch)
tree1cff58d64577660b7d632806a67b798716c37854
parent37c2ad63af8a6e5cb6944f80d931fedbc6b49e7d (diff)
downloadmsgpack-python-e3fee4db5fbf1ead4a98fff6c8843574480c3c2a.tar.gz
fallback: support packing ExtType
-rw-r--r--msgpack/__init__.py26
-rw-r--r--msgpack/_packer.pyx5
-rw-r--r--msgpack/fallback.py181
3 files changed, 131 insertions, 81 deletions
diff --git a/msgpack/__init__.py b/msgpack/__init__.py
index a7b47b1..56a0b36 100644
--- a/msgpack/__init__.py
+++ b/msgpack/__init__.py
@@ -2,9 +2,31 @@
from msgpack._version import version
from msgpack.exceptions import *
-from collections import namedtuple
-ExtType = namedtuple('ExtType', 'code data')
+class ExtType(object):
+ __slots__ = ('code', 'data')
+
+ def __init__(self, code, data):
+ if not isinstance(code, int):
+ raise TypeError("code must be int")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes")
+ if not 0 <= code <= 127:
+ raise ValueError("code must be 0~127")
+ self.code = code
+ self.data = data
+
+ def __eq__(self, other):
+ if not isinstance(other, ExtType):
+ return NotImplemented
+ return self.code == other.code and self.data == other.data
+
+ def __hash__(self):
+ return self.code ^ hash(self.data)
+
+ def __repr__(self):
+ return "msgpack.ExtType(%r, %r)" % (self.code, self.data)
+
import os
if os.environ.get('MSGPACK_PUREPYTHON'):
diff --git a/msgpack/_packer.pyx b/msgpack/_packer.pyx
index f63667c..f2d058e 100644
--- a/msgpack/_packer.pyx
+++ b/msgpack/_packer.pyx
@@ -37,7 +37,6 @@ cdef extern from "pack.h":
cdef int DEFAULT_RECURSE_LIMIT=511
-
cdef class Packer(object):
"""
MessagePack Packer
@@ -185,8 +184,8 @@ cdef class Packer(object):
if ret != 0: break
elif isinstance(o, ExtType):
# This should be before Tuple because ExtType is namedtuple.
- longval = o[0]
- rawval = o[1]
+ longval = o.code
+ rawval = o.data
L = len(o[1])
ret = msgpack_pack_ext(&self.pk, longval, L)
ret = msgpack_pack_raw_body(&self.pk, rawval, L)
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)