pyo3::types

Trait PyByteArrayMethods

Source
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§

Source

fn len(&self) -> usize

Gets the length of the bytearray.

Source

fn is_empty(&self) -> bool

Checks if the bytearray is empty.

Source

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.

Source

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 and PyByteArrayMethods::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 the bytearray 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]);
}
Source

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.

Source

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.'");
Source

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.

Implementors§