Unpacker: add tell() (#227)

This commit is contained in:
jfolz 2017-04-29 19:33:20 +02:00 committed by INADA Naoki
parent 3388e4a6ee
commit a8d9162ca6
3 changed files with 32 additions and 0 deletions

View file

@ -29,6 +29,7 @@ cdef extern from "Python.h":
from libc.stdlib cimport * from libc.stdlib cimport *
from libc.string cimport * from libc.string cimport *
from libc.limits cimport * from libc.limits cimport *
ctypedef unsigned long long uint64_t
from msgpack.exceptions import ( from msgpack.exceptions import (
BufferFull, BufferFull,
@ -314,6 +315,7 @@ cdef class Unpacker(object):
cdef object object_hook, object_pairs_hook, list_hook, ext_hook cdef object object_hook, object_pairs_hook, list_hook, ext_hook
cdef object encoding, unicode_errors cdef object encoding, unicode_errors
cdef Py_ssize_t max_buffer_size cdef Py_ssize_t max_buffer_size
cdef uint64_t stream_offset
def __cinit__(self): def __cinit__(self):
self.buf = NULL self.buf = NULL
@ -358,6 +360,7 @@ cdef class Unpacker(object):
self.buf_size = read_size self.buf_size = read_size
self.buf_head = 0 self.buf_head = 0
self.buf_tail = 0 self.buf_tail = 0
self.stream_offset = 0
if encoding is not None: if encoding is not None:
if isinstance(encoding, unicode): if isinstance(encoding, unicode):
@ -468,6 +471,7 @@ cdef class Unpacker(object):
try: try:
ret = execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head) ret = execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head)
self.stream_offset += self.buf_head - prev_head
if write_bytes is not None: if write_bytes is not None:
write_bytes(PyBytes_FromStringAndSize(self.buf + prev_head, self.buf_head - prev_head)) write_bytes(PyBytes_FromStringAndSize(self.buf + prev_head, self.buf_head - prev_head))
@ -534,6 +538,9 @@ cdef class Unpacker(object):
""" """
return self._unpack(read_map_header, write_bytes) return self._unpack(read_map_header, write_bytes)
def tell(self):
return self.stream_offset
def __iter__(self): def __iter__(self):
return self return self

View file

@ -244,6 +244,7 @@ class Unpacker(object):
self._max_array_len = max_array_len self._max_array_len = max_array_len
self._max_map_len = max_map_len self._max_map_len = max_map_len
self._max_ext_len = max_ext_len self._max_ext_len = max_ext_len
self._stream_offset = 0
if list_hook is not None and not callable(list_hook): if list_hook is not None and not callable(list_hook):
raise TypeError('`list_hook` is not callable') raise TypeError('`list_hook` is not callable')
@ -266,6 +267,7 @@ class Unpacker(object):
def _consume(self): def _consume(self):
""" Gets rid of the used parts of the buffer. """ """ Gets rid of the used parts of the buffer. """
self._stream_offset += self._buff_i - self._buf_checkpoint
self._buf_checkpoint = self._buff_i self._buf_checkpoint = self._buff_i
def _got_extradata(self): def _got_extradata(self):
@ -629,6 +631,9 @@ class Unpacker(object):
self._consume() self._consume()
return ret return ret
def tell(self):
return self._stream_offset
class Packer(object): class Packer(object):
""" """

View file

@ -3,6 +3,7 @@
import io import io
from msgpack import Unpacker, BufferFull from msgpack import Unpacker, BufferFull
from msgpack import pack
from msgpack.exceptions import OutOfData from msgpack.exceptions import OutOfData
from pytest import raises from pytest import raises
@ -96,3 +97,22 @@ def test_issue124():
unpacker.feed(b"!") unpacker.feed(b"!")
assert tuple(unpacker) == (b'!',) assert tuple(unpacker) == (b'!',)
assert tuple(unpacker) == () assert tuple(unpacker) == ()
def test_unpack_tell():
stream = io.BytesIO()
messages = [2**i-1 for i in range(65)]
messages += [-(2**i) for i in range(1, 64)]
messages += [b'hello', b'hello'*1000, list(range(20)),
{i: bytes(i)*i for i in range(10)},
{i: bytes(i)*i for i in range(32)}]
offsets = []
for m in messages:
pack(m, stream)
offsets.append(stream.tell())
stream.seek(0)
unpacker = Unpacker(stream)
for m, o in zip(messages, offsets):
m2 = next(unpacker)
assert m == m2
assert o == unpacker.tell()