Skip to content

Commit b8dd626

Browse files
authored
Merge pull request #2235 from alex/pybytes-as-bytes
Added an as_bytes method for Py<PyBytes>
2 parents 16ad15e + 6965545 commit b8dd626

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414

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

17+
### Added
18+
19+
- Added `as_bytes` on `Py<PyBytes>`. [#2235](https://github.com/PyO3/pyo3/pull/2235)
20+
1721
## [0.16.2] - 2022-03-15
1822

1923
### Packaging

src/types/bytes.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,24 @@ impl PyBytes {
9797
}
9898
}
9999

100+
impl Py<PyBytes> {
101+
/// Gets the Python bytes as a byte slice. Because Python bytes are
102+
/// immutable, the result may be used for as long as the reference to
103+
/// `self` is held, including when the GIL is released.
104+
pub fn as_bytes<'a>(&'a self, _py: Python<'_>) -> &'a [u8] {
105+
// py is required here because `PyBytes_AsString` and `PyBytes_Size`
106+
// can both technically raise exceptions which require the GIL to be
107+
// held. The only circumstance in which they raise is if the value
108+
// isn't really a `PyBytes`, but better safe than sorry.
109+
unsafe {
110+
let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8;
111+
let length = ffi::PyBytes_Size(self.as_ptr()) as usize;
112+
debug_assert!(!buffer.is_null());
113+
std::slice::from_raw_parts(buffer, length)
114+
}
115+
}
116+
}
117+
100118
/// This is the same way [Vec] is indexed.
101119
impl<I: SliceIndex<[u8]>> Index<I> for PyBytes {
102120
type Output = I::Output;

tests/test_bytes.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,18 @@ fn test_bytearray_vec_conversion() {
4141
let f = wrap_pyfunction!(bytes_vec_conversion)(py).unwrap();
4242
py_assert!(py, f, "f(bytearray(b'Hello World')) == b'Hello World'");
4343
}
44+
45+
#[test]
46+
fn test_py_as_bytes() {
47+
let pyobj: pyo3::Py<pyo3::types::PyBytes>;
48+
let data: &[u8];
49+
50+
{
51+
let gil = Python::acquire_gil();
52+
let py = gil.python();
53+
pyobj = pyo3::types::PyBytes::new(py, b"abc").into_py(py);
54+
data = pyobj.as_bytes(py);
55+
}
56+
57+
assert_eq!(data, b"abc");
58+
}

0 commit comments

Comments
 (0)