Commit b8285d96 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #22113: struct.pack_into() now supports new buffer protocol (in

particular accepts writable memoryview).
parent 4809d1fc
......@@ -433,24 +433,24 @@ class StructTest(unittest.TestCase):
self.assertRaises(struct.error, s.unpack_from, data, i)
self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
def test_pack_into(self):
def test_pack_into(self, cls=bytearray, tobytes=str):
test_string = 'Reykjavik rocks, eow!'
writable_buf = array.array('c', ' '*100)
writable_buf = cls(' '*100)
fmt = '21s'
s = struct.Struct(fmt)
# Test without offset
s.pack_into(writable_buf, 0, test_string)
from_buf = writable_buf.tostring()[:len(test_string)]
from_buf = tobytes(writable_buf)[:len(test_string)]
self.assertEqual(from_buf, test_string)
# Test with offset.
s.pack_into(writable_buf, 10, test_string)
from_buf = writable_buf.tostring()[:len(test_string)+10]
from_buf = tobytes(writable_buf)[:len(test_string)+10]
self.assertEqual(from_buf, test_string[:10] + test_string)
# Go beyond boundaries.
small_buf = array.array('c', ' '*10)
small_buf = cls(' '*10)
self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
test_string)
self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
......@@ -461,6 +461,15 @@ class StructTest(unittest.TestCase):
self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
None)
def test_pack_into_array(self):
self.test_pack_into(cls=lambda b: array.array('c', b),
tobytes=array.array.tostring)
def test_pack_into_memoryview(self):
# Issue #22113
self.test_pack_into(cls=lambda b: memoryview(bytearray(b)),
tobytes=memoryview.tobytes)
def test_pack_into_fn(self):
test_string = 'Reykjavik rocks, eow!'
writable_buf = array.array('c', ' '*100)
......
......@@ -18,6 +18,9 @@ Core and Builtins
Library
-------
- Issue #22113: struct.pack_into() now supports new buffer protocol (in
particular accepts writable memoryview).
- Issues #814253, #9179: Warnings now are raised when group references and
conditional group references are used in lookbehind assertions in regular
expressions.
......
......@@ -1657,8 +1657,8 @@ static PyObject *
s_pack_into(PyObject *self, PyObject *args)
{
PyStructObject *soself;
char *buffer;
Py_ssize_t buffer_len, offset;
Py_buffer buf;
Py_ssize_t offset;
/* Validate arguments. +1 is for the first arg as buffer. */
soself = (PyStructObject *)self;
......@@ -1683,33 +1683,35 @@ s_pack_into(PyObject *self, PyObject *args)
}
/* Extract a writable memory buffer from the first argument */
if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0),
(void**)&buffer, &buffer_len) == -1 ) {
if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buf))
return NULL;
}
assert( buffer_len >= 0 );
/* Extract the offset from the first argument */
offset = PyInt_AsSsize_t(PyTuple_GET_ITEM(args, 1));
if (offset == -1 && PyErr_Occurred())
if (offset == -1 && PyErr_Occurred()) {
PyBuffer_Release(&buf);
return NULL;
}
/* Support negative offsets. */
if (offset < 0)
offset += buffer_len;
offset += buf.len;
/* Check boundaries */
if (offset < 0 || (buffer_len - offset) < soself->s_size) {
if (offset < 0 || (buf.len - offset) < soself->s_size) {
PyErr_Format(StructError,
"pack_into requires a buffer of at least %zd bytes",
soself->s_size);
PyBuffer_Release(&buf);
return NULL;
}
/* Call the guts */
if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) {
if (s_pack_internal(soself, args, 2, (char *)buf.buf + offset) != 0) {
PyBuffer_Release(&buf);
return NULL;
}
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment