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,82 +506,111 @@ 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):
if nest_limit < 0: default_used = False
raise PackValueError("recursion limit exceeded") while True:
if obj is None: if nest_limit < 0:
return self._buffer.write(b"\xc0") raise PackValueError("recursion limit exceeded")
if isinstance(obj, bool): if obj is None:
if obj: return self._buffer.write(b"\xc0")
return self._buffer.write(b"\xc3") if isinstance(obj, bool):
return self._buffer.write(b"\xc2") if obj:
if isinstance(obj, int_types): return self._buffer.write(b"\xc3")
if 0 <= obj < 0x80: return self._buffer.write(b"\xc2")
return self._buffer.write(struct.pack("B", obj)) if isinstance(obj, int_types):
if -0x20 <= obj < 0: if 0 <= obj < 0x80:
return self._buffer.write(struct.pack("b", obj)) return self._buffer.write(struct.pack("B", obj))
if 0x80 <= obj <= 0xff: if -0x20 <= obj < 0:
return self._buffer.write(struct.pack("BB", 0xcc, obj)) return self._buffer.write(struct.pack("b", obj))
if -0x80 <= obj < 0: if 0x80 <= obj <= 0xff:
return self._buffer.write(struct.pack(">Bb", 0xd0, obj)) return self._buffer.write(struct.pack("BB", 0xcc, obj))
if 0xff < obj <= 0xffff: if -0x80 <= obj < 0:
return self._buffer.write(struct.pack(">BH", 0xcd, obj)) return self._buffer.write(struct.pack(">Bb", 0xd0, obj))
if -0x8000 <= obj < -0x80: if 0xff < obj <= 0xffff:
return self._buffer.write(struct.pack(">Bh", 0xd1, obj)) return self._buffer.write(struct.pack(">BH", 0xcd, obj))
if 0xffff < obj <= 0xffffffff: if -0x8000 <= obj < -0x80:
return self._buffer.write(struct.pack(">BI", 0xce, obj)) return self._buffer.write(struct.pack(">Bh", 0xd1, obj))
if -0x80000000 <= obj < -0x8000: if 0xffff < obj <= 0xffffffff:
return self._buffer.write(struct.pack(">Bi", 0xd2, obj)) return self._buffer.write(struct.pack(">BI", 0xce, obj))
if 0xffffffff < obj <= 0xffffffffffffffff: if -0x80000000 <= obj < -0x8000:
return self._buffer.write(struct.pack(">BQ", 0xcf, obj)) return self._buffer.write(struct.pack(">Bi", 0xd2, obj))
if -0x8000000000000000 <= obj < -0x80000000: if 0xffffffff < obj <= 0xffffffffffffffff:
return self._buffer.write(struct.pack(">Bq", 0xd3, obj)) return self._buffer.write(struct.pack(">BQ", 0xcf, obj))
raise PackValueError("Integer value out of range") if -0x8000000000000000 <= obj < -0x80000000:
if self._use_bin_type and isinstance(obj, bytes): return self._buffer.write(struct.pack(">Bq", 0xd3, obj))
n = len(obj) raise PackValueError("Integer value out of range")
if n <= 0xff: if self._use_bin_type and isinstance(obj, bytes):
self._buffer.write(struct.pack('>BB', 0xc4, n)) n = len(obj)
elif n <= 0xffff: if n <= 0xff:
self._buffer.write(struct.pack(">BH", 0xc5, n)) self._buffer.write(struct.pack('>BB', 0xc4, n))
elif n <= 0xffffffff: elif n <= 0xffff:
self._buffer.write(struct.pack(">BI", 0xc6, n)) self._buffer.write(struct.pack(">BH", 0xc5, n))
else: elif n <= 0xffffffff:
raise PackValueError("Bytes is too large") self._buffer.write(struct.pack(">BI", 0xc6, n))
return self._buffer.write(obj) else:
if isinstance(obj, (Unicode, bytes)): raise PackValueError("Bytes is too large")
if isinstance(obj, Unicode): return self._buffer.write(obj)
if self._encoding is None: if isinstance(obj, (Unicode, bytes)):
raise TypeError( if isinstance(obj, Unicode):
"Can't encode unicode string: " if self._encoding is None:
"no encoding is specified") raise TypeError(
obj = obj.encode(self._encoding, self._unicode_errors) "Can't encode unicode string: "
n = len(obj) "no encoding is specified")
if n <= 0x1f: obj = obj.encode(self._encoding, self._unicode_errors)
self._buffer.write(struct.pack('B', 0xa0 + n)) n = len(obj)
elif self._use_bin_type and n <= 0xff: if n <= 0x1f:
self._buffer.write(struct.pack('>BB', 0xd9, n)) self._buffer.write(struct.pack('B', 0xa0 + n))
elif n <= 0xffff: elif self._use_bin_type and n <= 0xff:
self._buffer.write(struct.pack(">BH", 0xda, n)) self._buffer.write(struct.pack('>BB', 0xd9, n))
elif n <= 0xffffffff: elif n <= 0xffff:
self._buffer.write(struct.pack(">BI", 0xdb, n)) self._buffer.write(struct.pack(">BH", 0xda, n))
else: elif n <= 0xffffffff:
raise PackValueError("String is too large") self._buffer.write(struct.pack(">BI", 0xdb, n))
return self._buffer.write(obj) else:
if isinstance(obj, float): raise PackValueError("String is too large")
if self._use_float: return self._buffer.write(obj)
return self._buffer.write(struct.pack(">Bf", 0xca, obj)) if isinstance(obj, float):
return self._buffer.write(struct.pack(">Bd", 0xcb, obj)) if self._use_float:
if isinstance(obj, (list, tuple)): return self._buffer.write(struct.pack(">Bf", 0xca, obj))
n = len(obj) return self._buffer.write(struct.pack(">Bd", 0xcb, obj))
self._fb_pack_array_header(n) if isinstance(obj, ExtType):
for i in xrange(n): code = obj.code
self._pack(obj[i], nest_limit - 1) data = obj.data
return assert isinstance(code, int)
if isinstance(obj, dict): assert isinstance(data, bytes)
return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj), L = len(data)
nest_limit - 1) if L == 1:
if self._default is not None: self._buffer.write(b'\xd4')
return self._pack(self._default(obj), nest_limit - 1) elif L == 2:
raise TypeError("Cannot serialize %r" % obj) 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): def pack(self, obj):
self._pack(obj) self._pack(obj)