@@ -20,6 +20,9 @@ cdef extern from "Python.h":
2020 cdef bint PyFloat_Check(object o)
2121 cdef bint PyBytes_Check(object o)
2222 cdef bint PyUnicode_Check(object o)
23+ cdef bint PyCallable_Check(object o)
24+ cdef void Py_INCREF(object o)
25+ cdef void Py_DECREF(object o)
2326
2427cdef extern from " stdlib.h" :
2528 void * malloc(size_t)
@@ -60,13 +63,20 @@ cdef class Packer(object):
6063 astream.write(packer.pack(b))
6164 """
6265 cdef msgpack_packer pk
66+ cdef object default
6367
6468 def __cinit__ (self ):
6569 cdef int buf_size = 1024 * 1024
6670 self .pk.buf = < char * > malloc(buf_size);
6771 self .pk.buf_size = buf_size
6872 self .pk.length = 0
6973
74+ def __init__ (self , default = None ):
75+ if default is not None :
76+ if not PyCallable_Check(default):
77+ raise TypeError (" default must be a callable." )
78+ self .default = default
79+
7080 def __dealloc__ (self ):
7181 free(self .pk.buf);
7282
@@ -126,9 +136,18 @@ cdef class Packer(object):
126136 for v in o:
127137 ret = self ._pack(v)
128138 if ret != 0 : break
139+ elif self .default is not None :
140+ o = self .default(o)
141+ d = o
142+ ret = msgpack_pack_map(& self .pk, len (d))
143+ if ret == 0 :
144+ for k,v in d.items():
145+ ret = self ._pack(k)
146+ if ret != 0 : break
147+ ret = self ._pack(v)
148+ if ret != 0 : break
129149 else :
130- # TODO: Serialize with defalt() like simplejson.
131- raise TypeError , " can't serialize %r " % (o,)
150+ raise TypeError (" can't serialize %r " % (o,))
132151 return ret
133152
134153 def pack (self , object obj ):
@@ -141,21 +160,22 @@ cdef class Packer(object):
141160 return buf
142161
143162
144- def pack (object o , object stream ):
163+ def pack (object o , object stream , default = None ):
145164 """ pack an object `o` and write it to stream)."""
146- packer = Packer()
165+ packer = Packer(default )
147166 stream.write(packer.pack(o))
148167
149- def packb (object o ):
168+ def packb (object o , default = None ):
150169 """ pack o and return packed bytes."""
151- packer = Packer()
170+ packer = Packer(default = default )
152171 return packer.pack(o)
153172
154173packs = packb
155174
156175cdef extern from " unpack.h" :
157176 ctypedef struct msgpack_user:
158177 int use_list
178+ PyObject* object_hook
159179
160180 ctypedef struct template_context:
161181 msgpack_user user
@@ -170,26 +190,35 @@ cdef extern from "unpack.h":
170190 object template_data(template_context* ctx)
171191
172192
173- def unpackb (bytes packed_bytes ):
193+ def unpackb (bytes packed_bytes , object object_hook = None ):
174194 """ Unpack packed_bytes to object. Returns an unpacked object."""
175195 cdef const_char_ptr p = packed_bytes
176196 cdef template_context ctx
177197 cdef size_t off = 0
178198 cdef int ret
179199 template_init(& ctx)
180200 ctx.user.use_list = 0
201+ ctx.user.object_hook = NULL
202+ if object_hook is not None :
203+ if not PyCallable_Check(object_hook):
204+ raise TypeError (" object_hook must be a callable." )
205+ Py_INCREF(object_hook)
206+ ctx.user.object_hook = < PyObject* > object_hook
181207 ret = template_execute(& ctx, p, len (packed_bytes), & off)
208+ if object_hook is not None :
209+ pass
210+ # Py_DECREF(object_hook)
182211 if ret == 1 :
183212 return template_data(& ctx)
184213 else :
185214 return None
186215
187216unpacks = unpackb
188217
189- def unpack (object stream ):
218+ def unpack (object stream , object object_hook = None ):
190219 """ unpack an object from stream."""
191220 packed = stream.read()
192- return unpackb(packed)
221+ return unpackb(packed, object_hook = object_hook )
193222
194223cdef class UnpackIterator(object ):
195224 cdef object unpacker
@@ -234,6 +263,7 @@ cdef class Unpacker(object):
234263 cdef int read_size
235264 cdef object waiting_bytes
236265 cdef bint use_list
266+ cdef object object_hook
237267
238268 def __cinit__ (self ):
239269 self .buf = NULL
@@ -242,7 +272,8 @@ cdef class Unpacker(object):
242272 if self .buf:
243273 free(self .buf);
244274
245- def __init__ (self , file_like = None , int read_size = 0 , bint use_list = 0 ):
275+ def __init__ (self , file_like = None , int read_size = 0 , bint use_list = 0 ,
276+ object object_hook = None ):
246277 if read_size == 0 :
247278 read_size = 1024 * 1024
248279 self .use_list = use_list
@@ -255,6 +286,11 @@ cdef class Unpacker(object):
255286 self .buf_tail = 0
256287 template_init(& self .ctx)
257288 self .ctx.user.use_list = use_list
289+ self .ctx.user.object_hook = < PyObject* > NULL
290+ if object_hook is not None :
291+ if not PyCallable_Check(object_hook):
292+ raise TypeError (" object_hook must be a callable." )
293+ self .ctx.user.object_hook = < PyObject* > object_hook
258294
259295 def feed (self , bytes next_bytes ):
260296 self .waiting_bytes.append(next_bytes)
0 commit comments