1 use cpython::{PyBytes, Python}; |
1 use crate::cpython::buffer::Element; |
|
2 use cpython::{ |
|
3 buffer::PyBuffer, exc::ValueError, PyBytes, PyErr, PyResult, Python, |
|
4 }; |
2 use stable_deref_trait::StableDeref; |
5 use stable_deref_trait::StableDeref; |
3 |
6 |
4 /// Safe abstraction over a `PyBytes` together with the `&[u8]` slice |
7 /// Safe abstraction over a `PyBytes` together with the `&[u8]` slice |
5 /// that borrows it. Implements `Deref<Target = [u8]>`. |
8 /// that borrows it. Implements `Deref<Target = [u8]>`. |
6 /// |
9 /// |
53 |
56 |
54 // Safety: PyBytes is Send. Raw pointers are not by default, |
57 // Safety: PyBytes is Send. Raw pointers are not by default, |
55 // but here sending one to another thread is fine since we ensure it stays |
58 // but here sending one to another thread is fine since we ensure it stays |
56 // valid. |
59 // valid. |
57 unsafe impl Send for PyBytesDeref {} |
60 unsafe impl Send for PyBytesDeref {} |
|
61 |
|
62 /// |
|
63 /// It also enables using a (wrapped) `PyBuffer` in GIL-unaware generic code. |
|
64 pub struct PyBufferDeref { |
|
65 #[allow(unused)] |
|
66 keep_alive: PyBuffer, |
|
67 |
|
68 /// Borrows the buffer inside `self.keep_alive`, |
|
69 /// but the borrow-checker cannot express self-referential structs. |
|
70 data: *const [u8], |
|
71 } |
|
72 |
|
73 fn get_buffer<'a>(py: Python, buf: &'a PyBuffer) -> PyResult<&'a [u8]> { |
|
74 let len = buf.item_count(); |
|
75 |
|
76 let cbuf = buf.buf_ptr(); |
|
77 let has_correct_item_size = std::mem::size_of::<u8>() == buf.item_size(); |
|
78 let is_valid_buffer = has_correct_item_size |
|
79 && buf.is_c_contiguous() |
|
80 && u8::is_compatible_format(buf.format()) |
|
81 && buf.readonly(); |
|
82 |
|
83 let bytes = if is_valid_buffer { |
|
84 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) } |
|
85 } else { |
|
86 return Err(PyErr::new::<ValueError, _>( |
|
87 py, |
|
88 "Buffer has an invalid memory representation", |
|
89 )); |
|
90 }; |
|
91 Ok(bytes) |
|
92 } |
|
93 |
|
94 impl PyBufferDeref { |
|
95 pub fn new(py: Python, buf: PyBuffer) -> PyResult<Self> { |
|
96 Ok(Self { |
|
97 data: get_buffer(py, &buf)?, |
|
98 keep_alive: buf, |
|
99 }) |
|
100 } |
|
101 } |
|
102 |
|
103 impl std::ops::Deref for PyBufferDeref { |
|
104 type Target = [u8]; |
|
105 |
|
106 fn deref(&self) -> &[u8] { |
|
107 // Safety: the raw pointer is valid as long as the PyBuffer is still |
|
108 // alive, and the returned slice borrows `self`. |
|
109 unsafe { &*self.data } |
|
110 } |
|
111 } |
|
112 |
|
113 unsafe impl StableDeref for PyBufferDeref {} |
|
114 |
|
115 #[allow(unused)] |
|
116 fn static_assert_pybuffer_is_send() { |
|
117 #[allow(clippy::no_effect)] |
|
118 require_send::<PyBuffer>; |
|
119 } |
|
120 |
|
121 // Safety: PyBuffer is Send. Raw pointers are not by default, |
|
122 // but here sending one to another thread is fine since we ensure it stays |
|
123 // valid. |
|
124 unsafe impl Send for PyBufferDeref {} |