Merge pull request #3514 from messense/memoryview
Add `PyMemoryView` type
This commit is contained in:
commit
f12f928bd5
1
newsfragments/3514.added.md
Normal file
1
newsfragments/3514.added.md
Normal file
|
@ -0,0 +1 @@
|
|||
Add `PyMemoryView` type.
|
|
@ -29,7 +29,10 @@ extern "C" {
|
|||
size: Py_ssize_t,
|
||||
flags: c_int,
|
||||
) -> *mut PyObject;
|
||||
// skipped non-limited PyMemoryView_FromBuffer
|
||||
#[cfg(any(Py_3_11, not(Py_LIMITED_API)))]
|
||||
#[cfg_attr(PyPy, link_name = "PyPyMemoryView_FromBuffer")]
|
||||
pub fn PyMemoryView_FromBuffer(view: *const crate::Py_buffer) -> *mut PyObject;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyMemoryView_GetContiguous")]
|
||||
pub fn PyMemoryView_GetContiguous(
|
||||
base: *mut PyObject,
|
||||
buffertype: c_int,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! Objects related to PyBuffer and PyStr
|
||||
use pyo3::buffer::PyBuffer;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyBytes, PyString};
|
||||
use pyo3::types::{PyBytes, PyMemoryView, PyString};
|
||||
|
||||
/// This is for confirming that PyBuffer does not cause memory leak
|
||||
#[pyclass]
|
||||
|
@ -41,8 +41,16 @@ impl BytesExtractor {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn return_memoryview(py: Python<'_>) -> PyResult<&PyMemoryView> {
|
||||
let bytes: &PyAny = PyBytes::new(py, b"hello world").into();
|
||||
let memoryview = TryInto::try_into(bytes)?;
|
||||
Ok(memoryview)
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
pub fn buf_and_str(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
m.add_class::<BytesExtractor>()?;
|
||||
m.add_function(wrap_pyfunction!(return_memoryview, m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from pyo3_pytests.buf_and_str import BytesExtractor
|
||||
from pyo3_pytests.buf_and_str import BytesExtractor, return_memoryview
|
||||
|
||||
|
||||
def test_extract_bytes():
|
||||
|
@ -27,3 +27,10 @@ def test_extract_buffer():
|
|||
|
||||
arr = bytearray(b'\\(-"-;) A message written in bytes')
|
||||
assert extractor.from_buffer(arr) == len(arr)
|
||||
|
||||
|
||||
def test_return_memoryview():
|
||||
view = return_memoryview()
|
||||
assert view.readonly
|
||||
assert view.contiguous
|
||||
assert view.tobytes() == b"hello world"
|
||||
|
|
|
@ -241,10 +241,20 @@ impl PyByteArray {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'py> TryFrom<&'py PyAny> for &'py PyByteArray {
|
||||
type Error = crate::PyErr;
|
||||
|
||||
/// Creates a new Python `bytearray` object from another Python object that
|
||||
/// implements the buffer protocol.
|
||||
fn try_from(value: &'py PyAny) -> Result<Self, Self::Error> {
|
||||
PyByteArray::from(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::exceptions;
|
||||
use crate::types::PyByteArray;
|
||||
use crate::{exceptions, PyAny};
|
||||
use crate::{PyObject, Python};
|
||||
|
||||
#[test]
|
||||
|
@ -322,6 +332,17 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from() {
|
||||
Python::with_gil(|py| {
|
||||
let src = b"Hello Python";
|
||||
let bytearray: &PyAny = PyByteArray::new(py, src).into();
|
||||
let bytearray: &PyByteArray = TryInto::try_into(bytearray).unwrap();
|
||||
|
||||
assert_eq!(src, unsafe { bytearray.as_bytes() });
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resize() {
|
||||
Python::with_gil(|py| {
|
||||
|
|
29
src/types/memoryview.rs
Normal file
29
src/types/memoryview.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use crate::err::PyResult;
|
||||
use crate::{ffi, AsPyPointer, PyAny};
|
||||
|
||||
/// Represents a Python `memoryview`.
|
||||
#[repr(transparent)]
|
||||
pub struct PyMemoryView(PyAny);
|
||||
|
||||
pyobject_native_type_core!(PyMemoryView, pyobject_native_static_type_object!(ffi::PyMemoryView_Type), #checkfunction=ffi::PyMemoryView_Check);
|
||||
|
||||
impl PyMemoryView {
|
||||
/// Creates a new Python `memoryview` object from another Python object that
|
||||
/// implements the buffer protocol.
|
||||
pub fn from(src: &PyAny) -> PyResult<&PyMemoryView> {
|
||||
unsafe {
|
||||
src.py()
|
||||
.from_owned_ptr_or_err(ffi::PyMemoryView_FromObject(src.as_ptr()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'py> TryFrom<&'py PyAny> for &'py PyMemoryView {
|
||||
type Error = crate::PyErr;
|
||||
|
||||
/// Creates a new Python `memoryview` object from another Python object that
|
||||
/// implements the buffer protocol.
|
||||
fn try_from(value: &'py PyAny) -> Result<Self, Self::Error> {
|
||||
PyMemoryView::from(value)
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ pub use self::function::PyFunction;
|
|||
pub use self::iterator::PyIterator;
|
||||
pub use self::list::PyList;
|
||||
pub use self::mapping::PyMapping;
|
||||
pub use self::memoryview::PyMemoryView;
|
||||
pub use self::module::PyModule;
|
||||
pub use self::none::PyNone;
|
||||
pub use self::notimplemented::PyNotImplemented;
|
||||
|
@ -289,6 +290,7 @@ mod function;
|
|||
mod iterator;
|
||||
pub(crate) mod list;
|
||||
mod mapping;
|
||||
mod memoryview;
|
||||
mod module;
|
||||
mod none;
|
||||
mod notimplemented;
|
||||
|
|
Loading…
Reference in a new issue