|
63 | 63 | PyBytes_Size,
|
64 | 64 | PyErr_CheckSignals,
|
65 | 65 | )
|
66 |
| -from cython.cimports.cpython.buffer import Py_buffer, PyBuffer_IsContiguous |
67 |
| -from cython.cimports.cpython.memoryview import PyMemoryView_GET_BUFFER |
| 66 | +from cython.cimports.cpython.buffer import ( |
| 67 | + Py_buffer, |
| 68 | + PyBUF_ANY_CONTIGUOUS, |
| 69 | + PyBUF_WRITABLE, |
| 70 | + PyBuffer_Release, |
| 71 | + PyObject_GetBuffer, |
| 72 | +) |
68 | 73 | from cython.cimports.libc.errno import EAGAIN, EINTR, ENAMETOOLONG, ENOENT, ENOTSOCK
|
69 | 74 |
|
70 | 75 | # cimports require Cython 3
|
@@ -245,14 +250,19 @@ def _copy_zmq_msg_bytes(zmq_msg: pointer(zmq_msg_t)) -> bytes:
|
245 | 250 |
|
246 | 251 | @cfunc
|
247 | 252 | @inline
|
248 |
| -def _asbuffer(buf, data_c: pointer(p_void)) -> size_t: |
| 253 | +def _asbuffer(obj, data_c: pointer(p_void), writable: bint = False) -> size_t: |
249 | 254 | """Get a C buffer from a memoryview"""
|
250 |
| - view = memoryview(buf) |
251 |
| - pybuf: pointer(Py_buffer) = PyMemoryView_GET_BUFFER(view) |
252 |
| - if not PyBuffer_IsContiguous(pybuf, 'A'): |
253 |
| - raise BufferError("memoryview: underlying buffer is not contiguous") |
| 255 | + pybuf = declare(Py_buffer) |
| 256 | + flags: C.int = PyBUF_ANY_CONTIGUOUS |
| 257 | + if writable: |
| 258 | + flags |= PyBUF_WRITABLE |
| 259 | + rc: C.int = PyObject_GetBuffer(obj, address(pybuf), flags) |
| 260 | + if rc < 0: |
| 261 | + raise ValueError("Couldn't create buffer") |
254 | 262 | data_c[0] = pybuf.buf
|
255 |
| - return pybuf.len |
| 263 | + data_size: size_t = pybuf.len |
| 264 | + PyBuffer_Release(address(pybuf)) |
| 265 | + return data_size |
256 | 266 |
|
257 | 267 |
|
258 | 268 | _gc = None
|
@@ -1237,31 +1247,26 @@ def recv_into(self, buffer, /, *, nbytes=0, flags=0) -> C.int:
|
1237 | 1247 | ------
|
1238 | 1248 | ZMQError
|
1239 | 1249 | for any of the reasons `zmq_recv` might fail.
|
1240 |
| - ValueError |
1241 |
| - for invalid inputs, such as readonly or not contiguous buffers, |
1242 |
| - or invalid nbytes. |
| 1250 | + BufferError |
| 1251 | + for invalid buffers, such as readonly or not contiguous. |
1243 | 1252 | """
|
1244 | 1253 | c_flags: C.int = flags
|
1245 | 1254 | _check_closed(self)
|
1246 |
| - c_nbytes: C.int = nbytes |
| 1255 | + c_nbytes: size_t = nbytes |
1247 | 1256 | if c_nbytes < 0:
|
1248 | 1257 | raise ValueError(f"{nbytes=} must be non-negative")
|
1249 | 1258 | view = memoryview(buffer)
|
1250 |
| - # get C buffer |
1251 |
| - py_buf: pointer(Py_buffer) = PyMemoryView_GET_BUFFER(view) |
1252 |
| - if py_buf.readonly: |
1253 |
| - raise ValueError("Cannot recv_into readonly buffer") |
1254 |
| - if not PyBuffer_IsContiguous(py_buf, 'A'): |
1255 |
| - raise ValueError("Can only recv_into contiguous buffer") |
| 1259 | + c_data = declare(pointer(C.void)) |
| 1260 | + view_bytes: C.size_t = _asbuffer(view, address(c_data), True) |
1256 | 1261 | if nbytes == 0:
|
1257 |
| - c_nbytes = py_buf.len |
1258 |
| - elif c_nbytes > py_buf.len: |
1259 |
| - raise ValueError(f"{nbytes=} too big for memoryview of {py_buf.len}B") |
| 1262 | + c_nbytes = view_bytes |
| 1263 | + elif c_nbytes > view_bytes: |
| 1264 | + raise ValueError(f"{nbytes=} too big for memoryview of {view_bytes}B") |
1260 | 1265 |
|
1261 | 1266 | # call zmq_recv, with retries
|
1262 | 1267 | while True:
|
1263 | 1268 | with nogil:
|
1264 |
| - rc: C.int = zmq_recv(self.handle, py_buf.buf, c_nbytes, c_flags) |
| 1269 | + rc: C.int = zmq_recv(self.handle, c_data, c_nbytes, c_flags) |
1265 | 1270 | try:
|
1266 | 1271 | _check_rc(rc)
|
1267 | 1272 | except InterruptedSystemCall:
|
|
0 commit comments