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§


fn len(&self) -> usize

Gets the length of the bytearray.


fn is_empty(&self) -> bool

Checks if the bytearray is empty.


fn data(&self) -> *mut u8

Gets the start of the buffer containing the contents of the bytearray.


See the safety requirements of PyByteArray::as_bytes and PyByteArray::as_bytes_mut.


unsafe fn as_bytes(&self) -> &[u8]

Extracts a slice of the ByteArray’s entire buffer.


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 PyByteArray::as_bytes_mut and PyByteArray::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.

use pyo3::prelude::*;
use pyo3::exceptions::PyRuntimeError;
use pyo3::types::PyByteArray;

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
            .ok_or_else(|| PyRuntimeError::new_err("input is not long enough"))?;

    // Now we can do things with `section` and call PyO3 APIs again.
    // ...

§Incorrect usage

The following bug function is unsound ⚠️

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]);

unsafe fn as_bytes_mut(&self) -> &mut [u8]

Extracts a mutable slice of the ByteArray’s entire buffer.


Any other accesses of the bytearray’s buffer invalidate the slice. If it is used afterwards, the behavior is undefined. The safety requirements of PyByteArray::as_bytes apply to this function as well.


fn to_vec(&self) -> Vec<u8>

Copies the contents of the bytearray to a Rust vector.

let bytearray = PyByteArray::new_bound(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.'");

fn resize(&self, len: usize) -> PyResult<()>

Resizes the bytearray object to the new length len.

Note that this will invalidate any pointers obtained by PyByteArray::data, as well as any (unsafe) slices obtained from PyByteArray::as_bytes and PyByteArray::as_bytes_mut.