Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added an as_bytes method for Py<PyBytes> #2235

Merged
merged 1 commit into from Mar 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Panic during compilation when `PYO3_CROSS_LIB_DIR` is set for some host/target combinations. [#2232](https://github.com/PyO3/pyo3/pull/2232)

### Added

- Added `as_bytes` on `Py<PyBytes>`. [#2235](https://github.com/PyO3/pyo3/pull/2235)

## [0.16.2] - 2022-03-15

### Packaging
Expand Down
18 changes: 18 additions & 0 deletions src/types/bytes.rs
Expand Up @@ -97,6 +97,24 @@ impl PyBytes {
}
}

impl Py<PyBytes> {
/// Gets the Python bytes as a byte slice. Because Python bytes are
/// immutable, the result may be used for as long as the reference to
/// `self` is held, including when the GIL is released.
pub fn as_bytes<'a>(&'a self, _py: Python<'_>) -> &'a [u8] {
// py is required here because `PyBytes_AsString` and `PyBytes_Size`
// can both technically raise exceptions which require the GIL to be
// held. The only circumstance in which they raise is if the value
// isn't really a `PyBytes`, but better safe than sorry.
unsafe {
let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8;
let length = ffi::PyBytes_Size(self.as_ptr()) as usize;
debug_assert!(!buffer.is_null());
std::slice::from_raw_parts(buffer, length)
}
}
}

/// This is the same way [Vec] is indexed.
impl<I: SliceIndex<[u8]>> Index<I> for PyBytes {
type Output = I::Output;
Expand Down
15 changes: 15 additions & 0 deletions tests/test_bytes.rs
Expand Up @@ -41,3 +41,18 @@ fn test_bytearray_vec_conversion() {
let f = wrap_pyfunction!(bytes_vec_conversion)(py).unwrap();
py_assert!(py, f, "f(bytearray(b'Hello World')) == b'Hello World'");
}

#[test]
fn test_py_as_bytes() {
let pyobj: pyo3::Py<pyo3::types::PyBytes>;
let data: &[u8];

{
let gil = Python::acquire_gil();
let py = gil.python();
pyobj = pyo3::types::PyBytes::new(py, b"abc").into_py(py);
data = pyobj.as_bytes(py);
}

assert_eq!(data, b"abc");
}