Add PyMemoryView::from_owned_buffer for zero-copy memoryview creation#5937
Add PyMemoryView::from_owned_buffer for zero-copy memoryview creation#5937
Conversation
ac672ac to
800c7dc
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
710f6b2 to
2353d5d
Compare
|
netlify stuff looks unrelated? |
|
Indeed, hopefully #5939 will resolve that. |
|
#5941 might make the |
2353d5d to
fba259b
Compare
|
No luck with netlify... |
|
#5945 has finally got things green, one more rebase / merge should fix. |
4de5647 to
7f86fc8
Compare
davidhewitt
left a comment
There was a problem hiding this comment.
Thanks for moving this forward and sorry to be a touch slow to review. Please forgive me for being slightly critical in comments, as per the OP hinting this was generated by Claude I do feel that the code has a somewhat AI-bloaty feel.
tests/test_memoryview.rs
Outdated
| // Force GC to ensure the owner is kept alive by the memoryview | ||
| py.run(c"import gc; gc.collect()", None, None).unwrap(); | ||
| let bytes: Vec<u8> = view.call_method0("tobytes").unwrap().extract().unwrap(); | ||
| assert_eq!(bytes, b"kept alive"); |
There was a problem hiding this comment.
We perhaps need to test the opposite, that after the MemoryView is dropped the owner is also freed.
tests/test_memoryview.rs
Outdated
There was a problem hiding this comment.
I am generally trending towards having tests inside the library, gated on cfg(feature = "macros") where necessary. Perhaps can do the same here?
src/types/memoryview.rs
Outdated
| // SAFETY: PyMemoryView_FromBuffer creates a memoryview that takes | ||
| // ownership of the buffer (it will call PyBuffer_Release when the | ||
| // memoryview is deallocated, which will decref view.obj). |
There was a problem hiding this comment.
Is this definitely the case? I don't see documentation or tests which demonstrate that view is stolen by the call.
There was a problem hiding this comment.
I'm pretty sure it is with respect to the Py_buffer.... however in going back to triple check I spotted https://github.com/python/cpython/blob/main/Objects/memoryobject.c#L769-L788 which I'm now confused/concerned about the correctness.
There was a problem hiding this comment.
Yup, turns out CPython throws away the owner 🙃. Going to file this upstream.
There was a problem hiding this comment.
Mmm, good catch! I guess possibly also relevant is https://github.com/python/cpython/blob/d24ce178a2a413d3b5bb032264434e8cb416d8fe/Objects/memoryobject.c#L832 - the implementation of __buffer__ wrapper for bf_getbuffer implementations.
That might hint that an alternative implementation we could use is to support __buffer__ in #[pymethods] (we would like that anyway, see #3148). We could perhaps allow two signatures:
- low-level signature equivalent to our current
__getbuffer__method (or maybe with small tweaks) fn __buffer__(&self) -> &[u8], i.e. the equivalent of what's here, but packaged up to callPyBuffer_FillInfosomewhere in PyO3 machinery
There was a problem hiding this comment.
I'm not so convinced there's value in adding tests here if we already added tests at the Rust level.
Adds a new method to create a Python memoryview that exposes a read-only view of byte data owned by a frozen PyClass instance without copying. This is useful for libraries like pyca/cryptography that need to expose internal buffers efficiently. The method uses PyBuffer_FillInfo + PyMemoryView_FromBuffer to create a memoryview backed by the owner's data, with the owner kept alive via the buffer's obj reference. Safety is enforced at compile time: - T: PyClass<Frozen = True> prevents mutation that could invalidate pointers - for<'a> FnOnce(&'a T) -> &'a [u8] ensures the slice borrows from T or is 'static Closes PyO3#5871 https://claude.ai/code/session_01EEP1DaqJwHGCoNufi2JT9H
7f86fc8 to
ddec6dd
Compare
|
Thanks for the review -- sorry I hadn't caught the sloppy comments prior to putting this up. I think this may be on pause while I work through the CPython bug, or figure out an alternative path. Which is frustrating, because conceptually the buffer machinery supports everything we need for this... |
Adds a new method to create a Python memoryview that exposes a read-only view of byte data owned by a frozen PyClass instance without copying. This is useful for libraries like pyca/cryptography that need to expose internal buffers efficiently.
The method uses PyBuffer_FillInfo + PyMemoryView_FromBuffer to create a memoryview backed by the owner's data, with the owner kept alive via the buffer's obj reference.
Safety is enforced at compile time:
Closes #5871
https://claude.ai/code/session_01EEP1DaqJwHGCoNufi2JT9H