Skip to content

Commit e3fee4d

Browse files
committed
fallback: support packing ExtType
1 parent 37c2ad6 commit e3fee4d

File tree

3 files changed

+131
-81
lines changed

3 files changed

+131
-81
lines changed

msgpack/__init__.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,31 @@
22
from msgpack._version import version
33
from msgpack.exceptions import *
44

5-
from collections import namedtuple
65

7-
ExtType = namedtuple('ExtType', 'code data')
6+
class ExtType(object):
7+
__slots__ = ('code', 'data')
8+
9+
def __init__(self, code, data):
10+
if not isinstance(code, int):
11+
raise TypeError("code must be int")
12+
if not isinstance(data, bytes):
13+
raise TypeError("data must be bytes")
14+
if not 0 <= code <= 127:
15+
raise ValueError("code must be 0~127")
16+
self.code = code
17+
self.data = data
18+
19+
def __eq__(self, other):
20+
if not isinstance(other, ExtType):
21+
return NotImplemented
22+
return self.code == other.code and self.data == other.data
23+
24+
def __hash__(self):
25+
return self.code ^ hash(self.data)
26+
27+
def __repr__(self):
28+
return "msgpack.ExtType(%r, %r)" % (self.code, self.data)
29+
830

931
import os
1032
if os.environ.get('MSGPACK_PUREPYTHON'):

msgpack/_packer.pyx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ cdef extern from "pack.h":
3737
cdef int DEFAULT_RECURSE_LIMIT=511
3838

3939

40-
4140
cdef class Packer(object):
4241
"""
4342
MessagePack Packer
@@ -185,8 +184,8 @@ cdef class Packer(object):
185184
if ret != 0: break
186185
elif isinstance(o, ExtType):
187186
# This should be before Tuple because ExtType is namedtuple.
188-
longval = o[0]
189-
rawval = o[1]
187+
longval = o.code
188+
rawval = o.data
190189
L = len(o[1])
191190
ret = msgpack_pack_ext(&self.pk, longval, L)
192191
ret = msgpack_pack_raw_body(&self.pk, rawval, L)

msgpack/fallback.py

Lines changed: 105 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -506,82 +506,111 @@ def __init__(self, default=None, encoding='utf-8', unicode_errors='strict',
506506
self._default = default
507507

508508
def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance):
509-
if nest_limit < 0:
510-
raise PackValueError("recursion limit exceeded")
511-
if obj is None:
512-
return self._buffer.write(b"\xc0")
513-
if isinstance(obj, bool):
514-
if obj:
515-
return self._buffer.write(b"\xc3")
516-
return self._buffer.write(b"\xc2")
517-
if isinstance(obj, int_types):
518-
if 0 <= obj < 0x80:
519-
return self._buffer.write(struct.pack("B", obj))
520-
if -0x20 <= obj < 0:
521-
return self._buffer.write(struct.pack("b", obj))
522-
if 0x80 <= obj <= 0xff:
523-
return self._buffer.write(struct.pack("BB", 0xcc, obj))
524-
if -0x80 <= obj < 0:
525-
return self._buffer.write(struct.pack(">Bb", 0xd0, obj))
526-
if 0xff < obj <= 0xffff:
527-
return self._buffer.write(struct.pack(">BH", 0xcd, obj))
528-
if -0x8000 <= obj < -0x80:
529-
return self._buffer.write(struct.pack(">Bh", 0xd1, obj))
530-
if 0xffff < obj <= 0xffffffff:
531-
return self._buffer.write(struct.pack(">BI", 0xce, obj))
532-
if -0x80000000 <= obj < -0x8000:
533-
return self._buffer.write(struct.pack(">Bi", 0xd2, obj))
534-
if 0xffffffff < obj <= 0xffffffffffffffff:
535-
return self._buffer.write(struct.pack(">BQ", 0xcf, obj))
536-
if -0x8000000000000000 <= obj < -0x80000000:
537-
return self._buffer.write(struct.pack(">Bq", 0xd3, obj))
538-
raise PackValueError("Integer value out of range")
539-
if self._use_bin_type and isinstance(obj, bytes):
540-
n = len(obj)
541-
if n <= 0xff:
542-
self._buffer.write(struct.pack('>BB', 0xc4, n))
543-
elif n <= 0xffff:
544-
self._buffer.write(struct.pack(">BH", 0xc5, n))
545-
elif n <= 0xffffffff:
546-
self._buffer.write(struct.pack(">BI", 0xc6, n))
547-
else:
548-
raise PackValueError("Bytes is too large")
549-
return self._buffer.write(obj)
550-
if isinstance(obj, (Unicode, bytes)):
551-
if isinstance(obj, Unicode):
552-
if self._encoding is None:
553-
raise TypeError(
554-
"Can't encode unicode string: "
555-
"no encoding is specified")
556-
obj = obj.encode(self._encoding, self._unicode_errors)
557-
n = len(obj)
558-
if n <= 0x1f:
559-
self._buffer.write(struct.pack('B', 0xa0 + n))
560-
elif self._use_bin_type and n <= 0xff:
561-
self._buffer.write(struct.pack('>BB', 0xd9, n))
562-
elif n <= 0xffff:
563-
self._buffer.write(struct.pack(">BH", 0xda, n))
564-
elif n <= 0xffffffff:
565-
self._buffer.write(struct.pack(">BI", 0xdb, n))
566-
else:
567-
raise PackValueError("String is too large")
568-
return self._buffer.write(obj)
569-
if isinstance(obj, float):
570-
if self._use_float:
571-
return self._buffer.write(struct.pack(">Bf", 0xca, obj))
572-
return self._buffer.write(struct.pack(">Bd", 0xcb, obj))
573-
if isinstance(obj, (list, tuple)):
574-
n = len(obj)
575-
self._fb_pack_array_header(n)
576-
for i in xrange(n):
577-
self._pack(obj[i], nest_limit - 1)
578-
return
579-
if isinstance(obj, dict):
580-
return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj),
581-
nest_limit - 1)
582-
if self._default is not None:
583-
return self._pack(self._default(obj), nest_limit - 1)
584-
raise TypeError("Cannot serialize %r" % obj)
509+
default_used = False
510+
while True:
511+
if nest_limit < 0:
512+
raise PackValueError("recursion limit exceeded")
513+
if obj is None:
514+
return self._buffer.write(b"\xc0")
515+
if isinstance(obj, bool):
516+
if obj:
517+
return self._buffer.write(b"\xc3")
518+
return self._buffer.write(b"\xc2")
519+
if isinstance(obj, int_types):
520+
if 0 <= obj < 0x80:
521+
return self._buffer.write(struct.pack("B", obj))
522+
if -0x20 <= obj < 0:
523+
return self._buffer.write(struct.pack("b", obj))
524+
if 0x80 <= obj <= 0xff:
525+
return self._buffer.write(struct.pack("BB", 0xcc, obj))
526+
if -0x80 <= obj < 0:
527+
return self._buffer.write(struct.pack(">Bb", 0xd0, obj))
528+
if 0xff < obj <= 0xffff:
529+
return self._buffer.write(struct.pack(">BH", 0xcd, obj))
530+
if -0x8000 <= obj < -0x80:
531+
return self._buffer.write(struct.pack(">Bh", 0xd1, obj))
532+
if 0xffff < obj <= 0xffffffff:
533+
return self._buffer.write(struct.pack(">BI", 0xce, obj))
534+
if -0x80000000 <= obj < -0x8000:
535+
return self._buffer.write(struct.pack(">Bi", 0xd2, obj))
536+
if 0xffffffff < obj <= 0xffffffffffffffff:
537+
return self._buffer.write(struct.pack(">BQ", 0xcf, obj))
538+
if -0x8000000000000000 <= obj < -0x80000000:
539+
return self._buffer.write(struct.pack(">Bq", 0xd3, obj))
540+
raise PackValueError("Integer value out of range")
541+
if self._use_bin_type and isinstance(obj, bytes):
542+
n = len(obj)
543+
if n <= 0xff:
544+
self._buffer.write(struct.pack('>BB', 0xc4, n))
545+
elif n <= 0xffff:
546+
self._buffer.write(struct.pack(">BH", 0xc5, n))
547+
elif n <= 0xffffffff:
548+
self._buffer.write(struct.pack(">BI", 0xc6, n))
549+
else:
550+
raise PackValueError("Bytes is too large")
551+
return self._buffer.write(obj)
552+
if isinstance(obj, (Unicode, bytes)):
553+
if isinstance(obj, Unicode):
554+
if self._encoding is None:
555+
raise TypeError(
556+
"Can't encode unicode string: "
557+
"no encoding is specified")
558+
obj = obj.encode(self._encoding, self._unicode_errors)
559+
n = len(obj)
560+
if n <= 0x1f:
561+
self._buffer.write(struct.pack('B', 0xa0 + n))
562+
elif self._use_bin_type and n <= 0xff:
563+
self._buffer.write(struct.pack('>BB', 0xd9, n))
564+
elif n <= 0xffff:
565+
self._buffer.write(struct.pack(">BH", 0xda, n))
566+
elif n <= 0xffffffff:
567+
self._buffer.write(struct.pack(">BI", 0xdb, n))
568+
else:
569+
raise PackValueError("String is too large")
570+
return self._buffer.write(obj)
571+
if isinstance(obj, float):
572+
if self._use_float:
573+
return self._buffer.write(struct.pack(">Bf", 0xca, obj))
574+
return self._buffer.write(struct.pack(">Bd", 0xcb, obj))
575+
if isinstance(obj, ExtType):
576+
code = obj.code
577+
data = obj.data
578+
assert isinstance(code, int)
579+
assert isinstance(data, bytes)
580+
L = len(data)
581+
if L == 1:
582+
self._buffer.write(b'\xd4')
583+
elif L == 2:
584+
self._buffer.write(b'\xd5')
585+
elif L == 4:
586+
self._buffer.write(b'\xd6')
587+
elif L == 8:
588+
self._buffer.write(b'\xd7')
589+
elif L == 16:
590+
self._buffer.write(b'\xd8')
591+
elif L <= 0xff:
592+
self._buffer.write(struct.pack(">BB", 0xc7, L))
593+
elif L <= 0xffff:
594+
self._buffer.write(struct.pack(">BH", 0xc8, L))
595+
else:
596+
self._buffer.write(struct.pack(">BI", 0xc9, L))
597+
self._buffer.write(struct.pack("b", code))
598+
self._buffer.write(data)
599+
return
600+
if isinstance(obj, (list, tuple)):
601+
n = len(obj)
602+
self._fb_pack_array_header(n)
603+
for i in xrange(n):
604+
self._pack(obj[i], nest_limit - 1)
605+
return
606+
if isinstance(obj, dict):
607+
return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj),
608+
nest_limit - 1)
609+
if not default_used and self._default is not None:
610+
obj = self._default(obj)
611+
default_used = 1
612+
continue
613+
raise TypeError("Cannot serialize %r" % obj)
585614

586615
def pack(self, obj):
587616
self._pack(obj)

0 commit comments

Comments
 (0)