fallback: support packing ExtType

This commit is contained in:
INADA Naoki 2013-10-21 00:59:22 +09:00
parent 37c2ad63af
commit e3fee4db5f
3 changed files with 131 additions and 81 deletions

View file

@ -2,9 +2,31 @@
from msgpack._version import version from msgpack._version import version
from msgpack.exceptions import * 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 import os
if os.environ.get('MSGPACK_PUREPYTHON'): if os.environ.get('MSGPACK_PUREPYTHON'):

View file

@ -37,7 +37,6 @@ cdef extern from "pack.h":
cdef int DEFAULT_RECURSE_LIMIT=511 cdef int DEFAULT_RECURSE_LIMIT=511
cdef class Packer(object): cdef class Packer(object):
""" """
MessagePack Packer MessagePack Packer
@ -185,8 +184,8 @@ cdef class Packer(object):
if ret != 0: break if ret != 0: break
elif isinstance(o, ExtType): elif isinstance(o, ExtType):
# This should be before Tuple because ExtType is namedtuple. # This should be before Tuple because ExtType is namedtuple.
longval = o[0] longval = o.code
rawval = o[1] rawval = o.data
L = len(o[1]) L = len(o[1])
ret = msgpack_pack_ext(&self.pk, longval, L) ret = msgpack_pack_ext(&self.pk, longval, L)
ret = msgpack_pack_raw_body(&self.pk, rawval, L) ret = msgpack_pack_raw_body(&self.pk, rawval, L)

View file

@ -506,6 +506,8 @@ class Packer(object):
self._default = default self._default = default
def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance): def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
default_used = False
while True:
if nest_limit < 0: if nest_limit < 0:
raise PackValueError("recursion limit exceeded") raise PackValueError("recursion limit exceeded")
if obj is None: if obj is None:
@ -570,6 +572,31 @@ class Packer(object):
if self._use_float: if self._use_float:
return self._buffer.write(struct.pack(">Bf", 0xca, obj)) return self._buffer.write(struct.pack(">Bf", 0xca, obj))
return self._buffer.write(struct.pack(">Bd", 0xcb, 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)): if isinstance(obj, (list, tuple)):
n = len(obj) n = len(obj)
self._fb_pack_array_header(n) self._fb_pack_array_header(n)
@ -579,8 +606,10 @@ class Packer(object):
if isinstance(obj, dict): if isinstance(obj, dict):
return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj), return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj),
nest_limit - 1) nest_limit - 1)
if self._default is not None: if not default_used and self._default is not None:
return self._pack(self._default(obj), nest_limit - 1) obj = self._default(obj)
default_used = 1
continue
raise TypeError("Cannot serialize %r" % obj) raise TypeError("Cannot serialize %r" % obj)
def pack(self, obj): def pack(self, obj):