@@ -24,21 +24,20 @@ cdef extern from "pack.h":
24
24
size_t buf_size
25
25
bint use_bin_type
26
26
27
- int msgpack_pack_nil(msgpack_packer* pk)
28
- int msgpack_pack_true(msgpack_packer* pk)
29
- int msgpack_pack_false(msgpack_packer* pk)
30
- int msgpack_pack_long_long(msgpack_packer* pk, long long d)
31
- int msgpack_pack_unsigned_long_long(msgpack_packer* pk, unsigned long long d)
32
- int msgpack_pack_float(msgpack_packer* pk, float d)
33
- int msgpack_pack_double(msgpack_packer* pk, double d)
34
- int msgpack_pack_array(msgpack_packer* pk, size_t l)
35
- int msgpack_pack_map(msgpack_packer* pk, size_t l)
36
- int msgpack_pack_raw(msgpack_packer* pk, size_t l)
37
- int msgpack_pack_bin(msgpack_packer* pk, size_t l)
38
- int msgpack_pack_raw_body(msgpack_packer* pk, char * body, size_t l)
39
- int msgpack_pack_ext(msgpack_packer* pk, char typecode, size_t l)
40
- int msgpack_pack_timestamp(msgpack_packer* x, long long seconds, unsigned long nanoseconds);
41
- int msgpack_pack_unicode(msgpack_packer* pk, object o, long long limit)
27
+ int msgpack_pack_nil(msgpack_packer* pk) except - 1
28
+ int msgpack_pack_true(msgpack_packer* pk) except - 1
29
+ int msgpack_pack_false(msgpack_packer* pk) except - 1
30
+ int msgpack_pack_long_long(msgpack_packer* pk, long long d) except - 1
31
+ int msgpack_pack_unsigned_long_long(msgpack_packer* pk, unsigned long long d) except - 1
32
+ int msgpack_pack_float(msgpack_packer* pk, float d) except - 1
33
+ int msgpack_pack_double(msgpack_packer* pk, double d) except - 1
34
+ int msgpack_pack_array(msgpack_packer* pk, size_t l) except - 1
35
+ int msgpack_pack_map(msgpack_packer* pk, size_t l) except - 1
36
+ int msgpack_pack_raw(msgpack_packer* pk, size_t l) except - 1
37
+ int msgpack_pack_bin(msgpack_packer* pk, size_t l) except - 1
38
+ int msgpack_pack_raw_body(msgpack_packer* pk, char * body, size_t l) except - 1
39
+ int msgpack_pack_ext(msgpack_packer* pk, char typecode, size_t l) except - 1
40
+ int msgpack_pack_timestamp(msgpack_packer* x, long long seconds, unsigned long nanoseconds) except - 1
42
41
43
42
44
43
cdef int DEFAULT_RECURSE_LIMIT= 511
@@ -119,6 +118,10 @@ cdef class Packer:
119
118
self .pk.buf_size = buf_size
120
119
self .pk.length = 0
121
120
121
+ def __dealloc__ (self ):
122
+ PyMem_Free(self .pk.buf)
123
+ self .pk.buf = NULL
124
+
122
125
def __init__ (self , *, default = None ,
123
126
bint use_single_float = False , bint autoreset = True , bint use_bin_type = True ,
124
127
bint strict_types = False , bint datetime = False , unicode_errors = None ,
@@ -139,155 +142,127 @@ cdef class Packer:
139
142
else :
140
143
self .unicode_errors = self ._berrors
141
144
142
- def __dealloc__ (self ):
143
- PyMem_Free(self .pk.buf)
144
- self .pk.buf = NULL
145
-
146
- cdef int _pack(self , object o, int nest_limit = DEFAULT_RECURSE_LIMIT) except - 1 :
145
+ # returns -2 when default should(o) be called
146
+ cdef int _pack_inner(self , object o, bint will_default, int nest_limit) except - 1 :
147
147
cdef long long llval
148
148
cdef unsigned long long ullval
149
149
cdef unsigned long ulval
150
- cdef long longval
151
- cdef float fval
152
- cdef double dval
153
- cdef char * rawval
154
- cdef int ret
155
- cdef dict d
150
+ cdef const char * rawval
156
151
cdef Py_ssize_t L
157
- cdef int default_used = 0
158
- cdef bint strict_types = self .strict_types
152
+ cdef bool strict_types = self .strict_types
159
153
cdef Py_buffer view
160
154
161
- if nest_limit < 0 :
162
- raise ValueError (" recursion limit exceeded." )
163
-
164
- while True :
165
- if o is None :
166
- ret = msgpack_pack_nil(& self .pk)
167
- elif o is True :
168
- ret = msgpack_pack_true(& self .pk)
169
- elif o is False :
170
- ret = msgpack_pack_false(& self .pk)
171
- elif PyLong_CheckExact(o) if strict_types else PyLong_Check(o):
172
- # PyInt_Check(long) is True for Python 3.
173
- # So we should test long before int.
174
- try :
175
- if o > 0 :
176
- ullval = o
177
- ret = msgpack_pack_unsigned_long_long(& self .pk, ullval)
178
- else :
179
- llval = o
180
- ret = msgpack_pack_long_long(& self .pk, llval)
181
- except OverflowError as oe:
182
- if not default_used and self ._default is not None :
183
- o = self ._default(o)
184
- default_used = True
185
- continue
186
- else :
187
- raise OverflowError (" Integer value out of range" )
188
- elif PyFloat_CheckExact(o) if strict_types else PyFloat_Check(o):
189
- if self .use_float:
190
- fval = o
191
- ret = msgpack_pack_float(& self .pk, fval)
155
+ if o is None :
156
+ msgpack_pack_nil(& self .pk)
157
+ elif o is True :
158
+ msgpack_pack_true(& self .pk)
159
+ elif o is False :
160
+ msgpack_pack_false(& self .pk)
161
+ elif PyLong_CheckExact(o) if strict_types else PyLong_Check(o):
162
+ try :
163
+ if o > 0 :
164
+ ullval = o
165
+ msgpack_pack_unsigned_long_long(& self .pk, ullval)
192
166
else :
193
- dval = o
194
- ret = msgpack_pack_double(& self .pk, dval)
195
- elif PyBytesLike_CheckExact(o) if strict_types else PyBytesLike_Check(o):
196
- L = Py_SIZE(o)
197
- if L > ITEM_LIMIT:
198
- PyErr_Format(ValueError , b" %.200s object is too large" , Py_TYPE(o).tp_name)
199
- rawval = o
200
- ret = msgpack_pack_bin(& self .pk, L)
201
- if ret == 0 :
202
- ret = msgpack_pack_raw_body(& self .pk, rawval, L)
203
- elif PyUnicode_CheckExact(o) if strict_types else PyUnicode_Check(o):
204
- if self .unicode_errors == NULL :
205
- ret = msgpack_pack_unicode(& self .pk, o, ITEM_LIMIT);
206
- if ret == - 2 :
207
- raise ValueError (" unicode string is too large" )
167
+ llval = o
168
+ msgpack_pack_long_long(& self .pk, llval)
169
+ except OverflowError as oe:
170
+ if will_default:
171
+ return - 2
208
172
else :
209
- o = PyUnicode_AsEncodedString(o, NULL , self .unicode_errors)
210
- L = Py_SIZE(o)
211
- if L > ITEM_LIMIT:
212
- raise ValueError (" unicode string is too large" )
213
- ret = msgpack_pack_raw(& self .pk, L)
214
- if ret == 0 :
215
- rawval = o
216
- ret = msgpack_pack_raw_body(& self .pk, rawval, L)
217
- elif PyDict_CheckExact(o):
218
- d = < dict > o
219
- L = len (d)
220
- if L > ITEM_LIMIT:
221
- raise ValueError (" dict is too large" )
222
- ret = msgpack_pack_map(& self .pk, L)
223
- if ret == 0 :
224
- for k, v in d.items():
225
- ret = self ._pack(k, nest_limit- 1 )
226
- if ret != 0 : break
227
- ret = self ._pack(v, nest_limit- 1 )
228
- if ret != 0 : break
229
- elif not strict_types and PyDict_Check(o):
230
- L = len (o)
231
- if L > ITEM_LIMIT:
232
- raise ValueError (" dict is too large" )
233
- ret = msgpack_pack_map(& self .pk, L)
234
- if ret == 0 :
235
- for k, v in o.items():
236
- ret = self ._pack(k, nest_limit- 1 )
237
- if ret != 0 : break
238
- ret = self ._pack(v, nest_limit- 1 )
239
- if ret != 0 : break
240
- elif type (o) is ExtType if strict_types else isinstance (o, ExtType):
241
- # This should be before Tuple because ExtType is namedtuple.
242
- longval = o.code
243
- rawval = o.data
244
- L = len (o.data)
245
- if L > ITEM_LIMIT:
246
- raise ValueError (" EXT data is too large" )
247
- ret = msgpack_pack_ext(& self .pk, longval, L)
248
- ret = msgpack_pack_raw_body(& self .pk, rawval, L)
249
- elif type (o) is Timestamp:
250
- llval = o.seconds
251
- ulval = o.nanoseconds
252
- ret = msgpack_pack_timestamp(& self .pk, llval, ulval)
253
- elif PyList_CheckExact(o) if strict_types else (PyTuple_Check(o) or PyList_Check(o)):
173
+ raise OverflowError (" Integer value out of range" )
174
+ elif PyFloat_CheckExact(o) if strict_types else PyFloat_Check(o):
175
+ if self .use_float:
176
+ msgpack_pack_float(& self .pk, < float > o)
177
+ else :
178
+ msgpack_pack_double(& self .pk, < double > o)
179
+ elif PyBytesLike_CheckExact(o) if strict_types else PyBytesLike_Check(o):
180
+ L = Py_SIZE(o)
181
+ if L > ITEM_LIMIT:
182
+ PyErr_Format(ValueError , b" %.200s object is too large" , Py_TYPE(o).tp_name)
183
+ rawval = o
184
+ msgpack_pack_bin(& self .pk, L)
185
+ msgpack_pack_raw_body(& self .pk, rawval, L)
186
+ elif PyUnicode_CheckExact(o) if strict_types else PyUnicode_Check(o):
187
+ if self .unicode_errors == NULL :
188
+ rawval = PyUnicode_AsUTF8AndSize(o, & L)
189
+ if L > ITEM_LIMIT:
190
+ raise ValueError (" unicode string is too large" )
191
+ else :
192
+ o = PyUnicode_AsEncodedString(o, NULL , self .unicode_errors)
254
193
L = Py_SIZE(o)
255
194
if L > ITEM_LIMIT:
256
- raise ValueError (" list is too large" )
257
- ret = msgpack_pack_array(& self .pk, L)
258
- if ret == 0 :
259
- for v in o:
260
- ret = self ._pack(v, nest_limit- 1 )
261
- if ret != 0 : break
262
- elif PyMemoryView_Check(o):
263
- if PyObject_GetBuffer(o, & view, PyBUF_SIMPLE) != 0 :
264
- raise ValueError (" could not get buffer for memoryview" )
265
- L = view.len
266
- if L > ITEM_LIMIT:
267
- PyBuffer_Release(& view);
268
- raise ValueError (" memoryview is too large" )
269
- ret = msgpack_pack_bin(& self .pk, L)
270
- if ret == 0 :
271
- ret = msgpack_pack_raw_body(& self .pk, < char * > view.buf, L)
195
+ raise ValueError (" unicode string is too large" )
196
+ rawval = o
197
+ msgpack_pack_raw(& self .pk, L)
198
+ msgpack_pack_raw_body(& self .pk, rawval, L)
199
+ elif PyDict_CheckExact(o) if strict_types else PyDict_Check(o):
200
+ L = len (o)
201
+ if L > ITEM_LIMIT:
202
+ raise ValueError (" dict is too large" )
203
+ msgpack_pack_map(& self .pk, L)
204
+ for k, v in o.items():
205
+ self ._pack(k, nest_limit)
206
+ self ._pack(v, nest_limit)
207
+ elif type (o) is ExtType if strict_types else isinstance (o, ExtType):
208
+ # This should be before Tuple because ExtType is namedtuple.
209
+ rawval = o.data
210
+ L = len (o.data)
211
+ if L > ITEM_LIMIT:
212
+ raise ValueError (" EXT data is too large" )
213
+ msgpack_pack_ext(& self .pk, < long > o.code, L)
214
+ msgpack_pack_raw_body(& self .pk, rawval, L)
215
+ elif type (o) is Timestamp:
216
+ llval = o.seconds
217
+ ulval = o.nanoseconds
218
+ msgpack_pack_timestamp(& self .pk, llval, ulval)
219
+ elif PyList_CheckExact(o) if strict_types else (PyTuple_Check(o) or PyList_Check(o)):
220
+ L = Py_SIZE(o)
221
+ if L > ITEM_LIMIT:
222
+ raise ValueError (" list is too large" )
223
+ msgpack_pack_array(& self .pk, L)
224
+ for v in o:
225
+ self ._pack(v, nest_limit)
226
+ elif PyMemoryView_Check(o):
227
+ PyObject_GetBuffer(o, & view, PyBUF_SIMPLE)
228
+ L = view.len
229
+ if L > ITEM_LIMIT:
272
230
PyBuffer_Release(& view);
273
- elif self .datetime and PyDateTime_CheckExact(o) and datetime_tzinfo(o) is not None :
274
- delta = o - epoch
275
- if not PyDelta_CheckExact(delta):
276
- raise ValueError (" failed to calculate delta" )
277
- llval = timedelta_days(delta) * < long long > (24 * 60 * 60 ) + timedelta_seconds(delta)
278
- ulval = timedelta_microseconds(delta) * 1000
279
- ret = msgpack_pack_timestamp(& self .pk, llval, ulval)
280
- elif not default_used and self ._default:
231
+ raise ValueError (" memoryview is too large" )
232
+ try :
233
+ msgpack_pack_bin(& self .pk, L)
234
+ msgpack_pack_raw_body(& self .pk, < char * > view.buf, L)
235
+ finally :
236
+ PyBuffer_Release(& view);
237
+ elif self .datetime and PyDateTime_CheckExact(o) and datetime_tzinfo(o) is not None :
238
+ delta = o - epoch
239
+ if not PyDelta_CheckExact(delta):
240
+ raise ValueError (" failed to calculate delta" )
241
+ llval = timedelta_days(delta) * < long long > (24 * 60 * 60 ) + timedelta_seconds(delta)
242
+ ulval = timedelta_microseconds(delta) * 1000
243
+ msgpack_pack_timestamp(& self .pk, llval, ulval)
244
+ elif will_default:
245
+ return - 2
246
+ elif self .datetime and PyDateTime_CheckExact(o):
247
+ # this should be later than will_default
248
+ PyErr_Format(ValueError , b" can not serialize '%.200s ' object where tzinfo=None" , Py_TYPE(o).tp_name)
249
+ else :
250
+ PyErr_Format(TypeError , b" can not serialize '%.200s ' object" , Py_TYPE(o).tp_name)
251
+
252
+ cdef int _pack(self , object o, int nest_limit = DEFAULT_RECURSE_LIMIT) except - 1 :
253
+ cdef int ret
254
+ if nest_limit < 0 :
255
+ raise ValueError (" recursion limit exceeded." )
256
+ nest_limit -= 1
257
+ if self ._default is not None :
258
+ ret = self ._pack_inner(o, 1 , nest_limit)
259
+ if ret == - 2 :
281
260
o = self ._default(o)
282
- default_used = 1
283
- continue
284
- elif self .datetime and PyDateTime_CheckExact(o):
285
- PyErr_Format(ValueError , b" can not serialize '%.200s ' object where tzinfo=None" , Py_TYPE(o).tp_name)
286
261
else :
287
- PyErr_Format( TypeError , b " can not serialize ' %.200s ' object " , Py_TYPE(o).tp_name)
288
- return ret
262
+ return ret
263
+ return self ._pack_inner(o, 0 , nest_limit)
289
264
290
- cpdef pack(self , object obj):
265
+ def pack (self , object obj ):
291
266
cdef int ret
292
267
try :
293
268
ret = self ._pack(obj, DEFAULT_RECURSE_LIMIT)
@@ -308,11 +283,7 @@ cdef class Packer:
308
283
def pack_array_header (self , long long size ):
309
284
if size > ITEM_LIMIT:
310
285
raise ValueError
311
- cdef int ret = msgpack_pack_array(& self .pk, size)
312
- if ret == - 1 :
313
- raise MemoryError
314
- elif ret: # should not happen
315
- raise TypeError
286
+ msgpack_pack_array(& self .pk, size)
316
287
if self .autoreset:
317
288
buf = PyBytes_FromStringAndSize(self .pk.buf, self .pk.length)
318
289
self .pk.length = 0
@@ -321,11 +292,7 @@ cdef class Packer:
321
292
def pack_map_header (self , long long size ):
322
293
if size > ITEM_LIMIT:
323
294
raise ValueError
324
- cdef int ret = msgpack_pack_map(& self .pk, size)
325
- if ret == - 1 :
326
- raise MemoryError
327
- elif ret: # should not happen
328
- raise TypeError
295
+ msgpack_pack_map(& self .pk, size)
329
296
if self .autoreset:
330
297
buf = PyBytes_FromStringAndSize(self .pk.buf, self .pk.length)
331
298
self .pk.length = 0
@@ -338,17 +305,10 @@ cdef class Packer:
338
305
*pairs* should be a sequence of pairs.
339
306
(`len(pairs)` and `for k, v in pairs:` should be supported.)
340
307
"""
341
- cdef int ret = msgpack_pack_map(& self .pk, len (pairs))
342
- if ret == 0 :
343
- for k, v in pairs:
344
- ret = self ._pack(k)
345
- if ret != 0 : break
346
- ret = self ._pack(v)
347
- if ret != 0 : break
348
- if ret == - 1 :
349
- raise MemoryError
350
- elif ret: # should not happen
351
- raise TypeError
308
+ msgpack_pack_map(& self .pk, len (pairs))
309
+ for k, v in pairs:
310
+ self ._pack(k)
311
+ self ._pack(v)
352
312
if self .autoreset:
353
313
buf = PyBytes_FromStringAndSize(self .pk.buf, self .pk.length)
354
314
self .pk.length = 0
0 commit comments