pub trait PyByteArrayMethods<'py>: Sealed {
// Required methods
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn data(&self) -> *mut u8;
unsafe fn as_bytes(&self) -> &[u8] ⓘ;
unsafe fn as_bytes_mut(&self) -> &mut [u8] ⓘ;
fn to_vec(&self) -> Vec<u8> ⓘ;
fn resize(&self, len: usize) -> PyResult<()>;
}
Expand description
Implementation of functionality for PyByteArray
.
These methods are defined for the Bound<'py, PyByteArray>
smart pointer, so to use method call
syntax these methods are separated into a trait, because stable Rust does not yet support
arbitrary_self_types
.
Required Methods§
Sourcefn data(&self) -> *mut u8
fn data(&self) -> *mut u8
Gets the start of the buffer containing the contents of the bytearray.
§Safety
See the safety requirements of PyByteArrayMethods::as_bytes
and PyByteArrayMethods::as_bytes_mut
.
Sourceunsafe fn as_bytes(&self) -> &[u8] ⓘ
unsafe fn as_bytes(&self) -> &[u8] ⓘ
Extracts a slice of the ByteArray
’s entire buffer.
§Safety
Mutation of the bytearray
invalidates the slice. If it is used afterwards, the behavior is
undefined.
These mutations may occur in Python code as well as from Rust:
- Calling methods like
PyByteArrayMethods::as_bytes_mut
andPyByteArrayMethods::resize
will invalidate the slice. - Actions like dropping objects or raising exceptions can invoke
__del__
methods or signal handlers, which may execute arbitrary Python code. This means that if Python code has a reference to thebytearray
you cannot safely use the vast majority of PyO3’s API whilst using the slice.
As a result, this slice should only be used for short-lived operations without executing any Python code, such as copying into a Vec.
§Examples
use pyo3::prelude::*;
use pyo3::exceptions::PyRuntimeError;
use pyo3::types::PyByteArray;
#[pyfunction]
fn a_valid_function(bytes: &Bound<'_, PyByteArray>) -> PyResult<()> {
let section = {
// SAFETY: We promise to not let the interpreter regain control
// or invoke any PyO3 APIs while using the slice.
let slice = unsafe { bytes.as_bytes() };
// Copy only a section of `bytes` while avoiding
// `to_vec` which copies the entire thing.
let section = slice
.get(6..11)
.ok_or_else(|| PyRuntimeError::new_err("input is not long enough"))?;
Vec::from(section)
};
// Now we can do things with `section` and call PyO3 APIs again.
// ...
Ok(())
}
§Incorrect usage
The following bug
function is unsound ⚠️
#[pyfunction]
fn bug(py: Python<'_>, bytes: &Bound<'_, PyByteArray>) {
let slice = unsafe { bytes.as_bytes() };
// This explicitly yields control back to the Python interpreter...
// ...but it's not always this obvious. Many things do this implicitly.
py.allow_threads(|| {
// Python code could be mutating through its handle to `bytes`,
// which makes reading it a data race, which is undefined behavior.
println!("{:?}", slice[0]);
});
// Python code might have mutated it, so we can not rely on the slice
// remaining valid. As such this is also undefined behavior.
println!("{:?}", slice[0]);
}
Sourceunsafe fn as_bytes_mut(&self) -> &mut [u8] ⓘ
unsafe fn as_bytes_mut(&self) -> &mut [u8] ⓘ
Extracts a mutable slice of the ByteArray
’s entire buffer.
§Safety
Any other accesses of the bytearray
’s buffer invalidate the slice. If it is used
afterwards, the behavior is undefined. The safety requirements of PyByteArrayMethods::as_bytes
apply to this function as well.
Sourcefn to_vec(&self) -> Vec<u8> ⓘ
fn to_vec(&self) -> Vec<u8> ⓘ
Copies the contents of the bytearray to a Rust vector.
§Examples
let bytearray = PyByteArray::new(py, b"Hello World.");
let mut copied_message = bytearray.to_vec();
assert_eq!(b"Hello World.", copied_message.as_slice());
copied_message[11] = b'!';
assert_eq!(b"Hello World!", copied_message.as_slice());
pyo3::py_run!(py, bytearray, "assert bytearray == b'Hello World.'");
Sourcefn resize(&self, len: usize) -> PyResult<()>
fn resize(&self, len: usize) -> PyResult<()>
Resizes the bytearray object to the new length len
.
Note that this will invalidate any pointers obtained by PyByteArrayMethods::data, as well as any (unsafe) slices obtained from PyByteArrayMethods::as_bytes and PyByteArrayMethods::as_bytes_mut.