msgpack-python/msgpack/_packer.pyx

368 lines
14 KiB
Cython
Raw Normal View History

2009-05-22 14:31:20 +09:00
# coding: utf-8
#cython: embedsignature=True, c_string_encoding=ascii
2009-05-22 14:31:20 +09:00
from cpython cimport *
from cpython.version cimport PY_MAJOR_VERSION
from cpython.exc cimport PyErr_WarnEx
2012-07-13 21:28:16 +09:00
from msgpack.exceptions import PackValueError, PackOverflowError
2013-10-20 20:28:32 +09:00
from msgpack import ExtType
2012-07-13 21:28:16 +09:00
2015-11-12 11:49:19 +01:00
cdef extern from "Python.h":
int PyMemoryView_Check(object obj)
int PyByteArray_Check(object obj)
int PyByteArray_CheckExact(object obj)
char* PyUnicode_AsUTF8AndSize(object obj, Py_ssize_t *l) except NULL
2015-11-12 11:49:19 +01:00
cdef extern from "pack.h":
2009-05-22 14:31:20 +09:00
struct msgpack_packer:
2009-07-01 00:57:46 +09:00
char* buf
size_t length
size_t buf_size
2013-10-17 08:44:25 +09:00
bint use_bin_type
2009-05-22 14:31:20 +09:00
int msgpack_pack_int(msgpack_packer* pk, int d)
int msgpack_pack_nil(msgpack_packer* pk)
int msgpack_pack_true(msgpack_packer* pk)
int msgpack_pack_false(msgpack_packer* pk)
int msgpack_pack_long(msgpack_packer* pk, long d)
int msgpack_pack_long_long(msgpack_packer* pk, long long d)
int msgpack_pack_unsigned_long_long(msgpack_packer* pk, unsigned long long d)
2012-08-20 21:56:55 +02:00
int msgpack_pack_float(msgpack_packer* pk, float d)
int msgpack_pack_double(msgpack_packer* pk, double d)
int msgpack_pack_array(msgpack_packer* pk, size_t l)
int msgpack_pack_map(msgpack_packer* pk, size_t l)
int msgpack_pack_raw(msgpack_packer* pk, size_t l)
2013-10-17 08:35:08 +09:00
int msgpack_pack_bin(msgpack_packer* pk, size_t l)
int msgpack_pack_raw_body(msgpack_packer* pk, char* body, size_t l)
int msgpack_pack_ext(msgpack_packer* pk, char typecode, size_t l)
int msgpack_pack_unicode(msgpack_packer* pk, object o, long long limit)
2009-05-22 14:31:20 +09:00
2018-11-09 20:55:13 +09:00
cdef extern from "buff_converter.h":
object buff_to_buff(char *, Py_ssize_t)
2010-10-26 02:09:52 +09:00
cdef int DEFAULT_RECURSE_LIMIT=511
cdef long long ITEM_LIMIT = (2**32)-1
2009-05-22 14:31:20 +09:00
2012-07-13 21:28:16 +09:00
cdef inline int PyBytesLike_Check(object o):
return PyBytes_Check(o) or PyByteArray_Check(o)
cdef inline int PyBytesLike_CheckExact(object o):
return PyBytes_CheckExact(o) or PyByteArray_CheckExact(o)
2009-06-28 21:24:02 +09:00
cdef class Packer(object):
2013-02-26 09:20:44 +09:00
"""
MessagePack Packer
2013-02-26 09:20:44 +09:00
usage::
2009-06-08 01:30:43 +09:00
packer = Packer()
astream.write(packer.pack(a))
astream.write(packer.pack(b))
2012-12-10 21:47:18 +09:00
Packer's constructor has some keyword arguments:
2013-02-26 09:20:44 +09:00
:param callable default:
Convert user type to builtin type that Packer supports.
See also simplejson's document.
2013-02-26 09:20:44 +09:00
:param bool use_single_float:
Use single precision float type for float. (default: False)
2013-02-26 09:20:44 +09:00
:param bool autoreset:
Reset buffer after each pack and return its content as `bytes`. (default: True).
2013-02-26 09:20:44 +09:00
If set this to false, use `bytes()` to get content and `.reset()` to clear buffer.
2013-10-17 08:35:08 +09:00
:param bool use_bin_type:
Use bin type introduced in msgpack spec 2.0 for bytes.
It also enables str8 type for unicode.
Current default value is false, but it will be changed to true
in future version. You should specify it explicitly.
2015-11-10 03:37:54 +09:00
:param bool strict_types:
If set to true, types will be checked to be exact. Derived classes
from serializeable types will not be serialized and will be
treated as unsupported type and forwarded to default.
Additionally tuples will not be serialized as lists.
This is useful when trying to implement accurate serialization
for python types.
2018-02-05 02:19:48 +09:00
:param str unicode_errors:
Error handler for encoding unicode. (default: 'strict')
:param str encoding:
(deprecated) Convert unicode to bytes with this encoding. (default: 'utf-8')
2009-06-08 01:30:43 +09:00
"""
2009-05-22 14:31:20 +09:00
cdef msgpack_packer pk
2011-01-29 07:27:10 +09:00
cdef object _default
cdef object _bencoding
cdef object _berrors
cdef const char *encoding
cdef const char *unicode_errors
2015-11-10 03:30:11 +09:00
cdef bint strict_types
2012-08-20 21:56:55 +02:00
cdef bool use_float
2012-12-10 21:47:18 +09:00
cdef bint autoreset
2009-05-22 14:31:20 +09:00
def __cinit__(self):
2009-07-01 00:57:46 +09:00
cdef int buf_size = 1024*1024
2016-04-30 17:07:14 +09:00
self.pk.buf = <char*> PyMem_Malloc(buf_size)
2011-01-10 20:47:23 +09:00
if self.pk.buf == NULL:
raise MemoryError("Unable to allocate internal buffer.")
2009-07-01 00:57:46 +09:00
self.pk.buf_size = buf_size
self.pk.length = 0
2009-05-22 14:31:20 +09:00
def __init__(self, default=None, encoding=None, unicode_errors=None,
bint use_single_float=False, bint autoreset=True, bint use_bin_type=False,
bint strict_types=False):
if encoding is not None:
PyErr_WarnEx(DeprecationWarning, "encoding is deprecated.", 1)
2012-09-21 14:08:34 +09:00
self.use_float = use_single_float
2015-11-10 03:30:11 +09:00
self.strict_types = strict_types
2012-12-10 21:47:18 +09:00
self.autoreset = autoreset
self.pk.use_bin_type = use_bin_type
if default is not None:
if not PyCallable_Check(default):
raise TypeError("default must be a callable.")
2011-01-29 07:27:10 +09:00
self._default = default
self._bencoding = encoding
if encoding is None:
if PY_MAJOR_VERSION < 3:
self.encoding = 'utf-8'
else:
self.encoding = NULL
else:
self.encoding = self._bencoding
self._berrors = unicode_errors
if unicode_errors is None:
self.unicode_errors = NULL
else:
self.unicode_errors = self._berrors
def __dealloc__(self):
2016-04-30 17:07:14 +09:00
PyMem_Free(self.pk.buf)
self.pk.buf = NULL
2009-05-22 14:31:20 +09:00
2011-01-29 07:27:10 +09:00
cdef int _pack(self, object o, int nest_limit=DEFAULT_RECURSE_LIMIT) except -1:
2009-06-28 21:24:02 +09:00
cdef long long llval
cdef unsigned long long ullval
2009-06-28 21:24:02 +09:00
cdef long longval
2012-08-20 21:56:55 +02:00
cdef float fval
cdef double dval
cdef char* rawval
cdef int ret
cdef dict d
cdef Py_ssize_t L
2013-10-20 20:28:32 +09:00
cdef int default_used = 0
2015-11-10 03:30:11 +09:00
cdef bint strict_types = self.strict_types
2015-11-12 11:49:19 +01:00
cdef Py_buffer view
2009-05-22 14:31:20 +09:00
if nest_limit < 0:
2012-12-11 22:15:21 +09:00
raise PackValueError("recursion limit exceeded.")
2013-10-20 20:28:32 +09:00
while True:
if o is None:
ret = msgpack_pack_nil(&self.pk)
2015-11-10 03:30:11 +09:00
elif PyBool_Check(o) if strict_types else isinstance(o, bool):
2013-10-20 20:28:32 +09:00
if o:
ret = msgpack_pack_true(&self.pk)
else:
ret = msgpack_pack_false(&self.pk)
2015-11-10 03:30:11 +09:00
elif PyLong_CheckExact(o) if strict_types else PyLong_Check(o):
2014-03-26 03:03:18 +09:00
# PyInt_Check(long) is True for Python 3.
2015-11-09 02:34:17 +09:00
# So we should test long before int.
try:
if o > 0:
ullval = o
ret = msgpack_pack_unsigned_long_long(&self.pk, ullval)
else:
llval = o
ret = msgpack_pack_long_long(&self.pk, llval)
2015-11-09 02:34:17 +09:00
except OverflowError as oe:
if not default_used and self._default is not None:
o = self._default(o)
default_used = True
continue
else:
raise PackOverflowError("Integer value out of range")
2015-11-10 03:30:11 +09:00
elif PyInt_CheckExact(o) if strict_types else PyInt_Check(o):
2013-10-20 20:28:32 +09:00
longval = o
ret = msgpack_pack_long(&self.pk, longval)
2015-11-10 03:30:11 +09:00
elif PyFloat_CheckExact(o) if strict_types else PyFloat_Check(o):
2013-10-20 20:28:32 +09:00
if self.use_float:
fval = o
ret = msgpack_pack_float(&self.pk, fval)
else:
dval = o
ret = msgpack_pack_double(&self.pk, dval)
elif PyBytesLike_CheckExact(o) if strict_types else PyBytesLike_Check(o):
2013-10-20 20:28:32 +09:00
L = len(o)
if L > ITEM_LIMIT:
raise PackValueError("%s is too large" % type(o).__name__)
2014-03-26 03:03:18 +09:00
rawval = o
2013-10-20 20:28:32 +09:00
ret = msgpack_pack_bin(&self.pk, L)
if ret == 0:
ret = msgpack_pack_raw_body(&self.pk, rawval, L)
2015-11-10 03:30:11 +09:00
elif PyUnicode_CheckExact(o) if strict_types else PyUnicode_Check(o):
if self.encoding == NULL and self.unicode_errors == NULL:
ret = msgpack_pack_unicode(&self.pk, o, ITEM_LIMIT);
if ret == -2:
raise PackValueError("unicode string is too large")
else:
o = PyUnicode_AsEncodedString(o, self.encoding, self.unicode_errors)
L = len(o)
if L > ITEM_LIMIT:
raise PackValueError("unicode string is too large")
ret = msgpack_pack_raw(&self.pk, L)
if ret == 0:
rawval = o
ret = msgpack_pack_raw_body(&self.pk, rawval, L)
2013-10-20 20:28:32 +09:00
elif PyDict_CheckExact(o):
d = <dict>o
2014-03-26 03:03:18 +09:00
L = len(d)
if L > ITEM_LIMIT:
raise PackValueError("dict is too large")
2014-03-26 03:03:18 +09:00
ret = msgpack_pack_map(&self.pk, L)
2013-10-20 20:28:32 +09:00
if ret == 0:
for k, v in d.iteritems():
ret = self._pack(k, nest_limit-1)
if ret != 0: break
ret = self._pack(v, nest_limit-1)
if ret != 0: break
2015-11-10 03:30:11 +09:00
elif not strict_types and PyDict_Check(o):
2014-03-26 03:03:18 +09:00
L = len(o)
if L > ITEM_LIMIT:
raise PackValueError("dict is too large")
2014-03-26 03:03:18 +09:00
ret = msgpack_pack_map(&self.pk, L)
2013-10-20 20:28:32 +09:00
if ret == 0:
for k, v in o.items():
ret = self._pack(k, nest_limit-1)
if ret != 0: break
ret = self._pack(v, nest_limit-1)
if ret != 0: break
2015-11-10 03:41:09 +09:00
elif type(o) is ExtType if strict_types else isinstance(o, ExtType):
2013-10-20 20:28:32 +09:00
# This should be before Tuple because ExtType is namedtuple.
2013-10-21 00:59:22 +09:00
longval = o.code
rawval = o.data
2013-10-21 01:12:57 +09:00
L = len(o.data)
if L > ITEM_LIMIT:
raise PackValueError("EXT data is too large")
2013-10-20 20:28:32 +09:00
ret = msgpack_pack_ext(&self.pk, longval, L)
2013-10-17 08:35:08 +09:00
ret = msgpack_pack_raw_body(&self.pk, rawval, L)
2015-11-10 03:30:11 +09:00
elif PyList_CheckExact(o) if strict_types else (PyTuple_Check(o) or PyList_Check(o)):
2014-03-26 03:03:18 +09:00
L = len(o)
if L > ITEM_LIMIT:
raise PackValueError("list is too large")
2014-03-26 03:03:18 +09:00
ret = msgpack_pack_array(&self.pk, L)
2013-10-20 20:28:32 +09:00
if ret == 0:
for v in o:
ret = self._pack(v, nest_limit-1)
if ret != 0: break
2015-11-12 11:49:19 +01:00
elif PyMemoryView_Check(o):
if PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) != 0:
raise PackValueError("could not get buffer for memoryview")
2015-11-12 11:49:19 +01:00
L = view.len
if L > ITEM_LIMIT:
2015-11-12 11:49:19 +01:00
PyBuffer_Release(&view);
raise PackValueError("memoryview is too large")
2015-11-12 11:49:19 +01:00
ret = msgpack_pack_bin(&self.pk, L)
if ret == 0:
ret = msgpack_pack_raw_body(&self.pk, <char*>view.buf, L)
PyBuffer_Release(&view);
2013-10-20 20:28:32 +09:00
elif not default_used and self._default:
o = self._default(o)
default_used = 1
continue
else:
raise TypeError("can't serialize %r" % (o,))
return ret
2012-03-08 16:59:08 +09:00
cpdef pack(self, object obj):
cdef int ret
try:
ret = self._pack(obj, DEFAULT_RECURSE_LIMIT)
except:
self.pk.length = 0
raise
if ret: # should not happen.
raise RuntimeError("internal error")
2012-12-10 21:47:18 +09:00
if self.autoreset:
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
self.pk.length = 0
return buf
2009-07-01 00:57:46 +09:00
2013-10-20 15:40:20 +09:00
def pack_ext_type(self, typecode, data):
msgpack_pack_ext(&self.pk, typecode, len(data))
msgpack_pack_raw_body(&self.pk, data, len(data))
def pack_array_header(self, long long size):
if size > ITEM_LIMIT:
raise PackValueError
2012-12-10 21:26:41 +09:00
cdef int ret = msgpack_pack_array(&self.pk, size)
if ret == -1:
raise MemoryError
elif ret: # should not happen
raise TypeError
2012-12-10 21:47:18 +09:00
if self.autoreset:
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
self.pk.length = 0
return buf
2012-12-10 21:26:41 +09:00
def pack_map_header(self, long long size):
if size > ITEM_LIMIT:
raise PackValueError
2012-12-10 21:26:41 +09:00
cdef int ret = msgpack_pack_map(&self.pk, size)
if ret == -1:
raise MemoryError
elif ret: # should not happen
raise TypeError
2012-12-10 21:47:18 +09:00
if self.autoreset:
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
self.pk.length = 0
return buf
2012-12-10 21:26:41 +09:00
def pack_map_pairs(self, object pairs):
"""
Pack *pairs* as msgpack map type.
*pairs* should be a sequence of pairs.
2013-02-26 09:20:44 +09:00
(`len(pairs)` and `for k, v in pairs:` should be supported.)
2012-12-10 21:26:41 +09:00
"""
cdef int ret = msgpack_pack_map(&self.pk, len(pairs))
if ret == 0:
for k, v in pairs:
ret = self._pack(k)
if ret != 0: break
ret = self._pack(v)
if ret != 0: break
if ret == -1:
raise MemoryError
elif ret: # should not happen
raise TypeError
2012-12-10 21:47:18 +09:00
if self.autoreset:
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
self.pk.length = 0
return buf
def reset(self):
2018-11-09 20:55:13 +09:00
"""Reset internal buffer.
This method is usaful only when autoreset=False.
"""
self.pk.length = 0
2012-12-10 21:47:18 +09:00
def bytes(self):
2018-11-09 20:55:13 +09:00
"""Return internal buffer contents as bytes object"""
2012-12-10 21:47:18 +09:00
return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
2018-11-09 20:55:13 +09:00
def getbuffer(self):
"""Return view of internal buffer."""
return buff_to_buff(self.pk.buf, self.pk.length)