Skip to content

Commit 01c97c7

Browse files
committed
add PyBytes::new_bound
1 parent 0d421b1 commit 01c97c7

File tree

9 files changed

+73
-26
lines changed

9 files changed

+73
-26
lines changed

guide/src/conversions/traits.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ enum RustyEnum<'a> {
388388
# }
389389
#
390390
# {
391-
# let thing = PyBytes::new(py, b"text");
391+
# let thing = PyBytes::new_bound(py, b"text");
392392
# let rust_thing: RustyEnum<'_> = thing.extract()?;
393393
#
394394
# assert_eq!(

pytests/src/buf_and_str.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl BytesExtractor {
4343

4444
#[pyfunction]
4545
fn return_memoryview(py: Python<'_>) -> PyResult<&PyMemoryView> {
46-
let bytes: &PyAny = PyBytes::new(py, b"hello world").into();
46+
let bytes: &PyAny = PyBytes::new_bound(py, b"hello world").into_gil_ref();
4747
let memoryview = TryInto::try_into(bytes)?;
4848
Ok(memoryview)
4949
}

src/conversions/anyhow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
//! let res = Python::with_gil(|py| {
7878
//! let zlib = PyModule::import(py, "zlib")?;
7979
//! let decompress = zlib.getattr("decompress")?;
80-
//! let bytes = PyBytes::new(py, bytes);
80+
//! let bytes = PyBytes::new_bound(py, bytes);
8181
//! let value = decompress.call1((bytes,))?;
8282
//! value.extract::<Vec<u8>>()
8383
//! })?;

src/conversions/eyre.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
//! let res = Python::with_gil(|py| {
7777
//! let zlib = PyModule::import(py, "zlib")?;
7878
//! let decompress = zlib.getattr("decompress")?;
79-
//! let bytes = PyBytes::new(py, bytes);
79+
//! let bytes = PyBytes::new_bound(py, bytes);
8080
//! let value = decompress.call1((bytes,))?;
8181
//! value.extract::<Vec<u8>>()
8282
//! })?;

src/conversions/num_bigint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ macro_rules! bigint_conversion {
7878
#[cfg(Py_LIMITED_API)]
7979
fn to_object(&self, py: Python<'_>) -> PyObject {
8080
let bytes = $to_bytes(self);
81-
let bytes_obj = PyBytes::new(py, &bytes);
81+
let bytes_obj = PyBytes::new_bound(py, &bytes);
8282
let kwargs = if $is_signed > 0 {
8383
let kwargs = PyDict::new(py);
8484
kwargs.set_item(crate::intern!(py, "signed"), true).unwrap();

src/conversions/std/slice.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#[cfg(feature = "experimental-inspect")]
22
use crate::inspect::types::TypeInfo;
3-
use crate::{types::PyBytes, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject};
3+
use crate::{types::PyBytes, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python};
44

55
impl<'a> IntoPy<PyObject> for &'a [u8] {
66
fn into_py(self, py: Python<'_>) -> PyObject {
7-
PyBytes::new(py, self).to_object(py)
7+
PyBytes::new_bound(py, self).unbind().into()
88
}
99

1010
#[cfg(feature = "experimental-inspect")]

src/tests/hygiene/pymethods.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ impl Dummy {
2424
"Dummy"
2525
}
2626

27-
fn __bytes__<'py>(&self, py: crate::Python<'py>) -> &'py crate::types::PyBytes {
28-
crate::types::PyBytes::new(py, &[0])
27+
fn __bytes__<'py>(&self, py: crate::Python<'py>) -> crate::Bound<'py, crate::types::PyBytes> {
28+
crate::types::PyBytes::new_bound(py, &[0])
2929
}
3030

3131
fn __format__(&self, format_spec: ::std::string::String) -> ::std::string::String {
@@ -420,8 +420,8 @@ impl Dummy {
420420
"Dummy"
421421
}
422422

423-
fn __bytes__<'py>(&self, py: crate::Python<'py>) -> &'py crate::types::PyBytes {
424-
crate::types::PyBytes::new(py, &[0])
423+
fn __bytes__<'py>(&self, py: crate::Python<'py>) -> crate::Bound<'py, crate::types::PyBytes> {
424+
crate::types::PyBytes::new_bound(py, &[0])
425425
}
426426

427427
fn __format__(&self, format_spec: ::std::string::String) -> ::std::string::String {

src/types/bytes.rs

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
use crate::ffi_ptr_ext::FfiPtrExt;
12
use crate::instance::{Borrowed, Bound};
3+
use crate::types::any::PyAnyMethods;
24
use crate::{ffi, FromPyObject, IntoPy, Py, PyAny, PyNativeType, PyResult, Python, ToPyObject};
35
use std::borrow::Cow;
46
use std::ops::Index;
@@ -17,14 +19,45 @@ pub struct PyBytes(PyAny);
1719
pyobject_native_type_core!(PyBytes, pyobject_native_static_type_object!(ffi::PyBytes_Type), #checkfunction=ffi::PyBytes_Check);
1820

1921
impl PyBytes {
22+
/// Deprecated form of [`PyBytes::new_bound`].
23+
#[cfg_attr(
24+
not(feature = "gil-refs"),
25+
deprecated(
26+
since = "0.21.0",
27+
note = "`PyBytes::new` will be replaced by `PyBytes::new_bound` in a future PyO3 version"
28+
)
29+
)]
30+
pub fn new<'p>(py: Python<'p>, s: &[u8]) -> &'p PyBytes {
31+
Self::new_bound(py, s).into_gil_ref()
32+
}
33+
2034
/// Creates a new Python bytestring object.
2135
/// The bytestring is initialized by copying the data from the `&[u8]`.
2236
///
2337
/// Panics if out of memory.
24-
pub fn new<'p>(py: Python<'p>, s: &[u8]) -> &'p PyBytes {
38+
pub fn new_bound<'p>(py: Python<'p>, s: &[u8]) -> Bound<'p, PyBytes> {
2539
let ptr = s.as_ptr() as *const c_char;
2640
let len = s.len() as ffi::Py_ssize_t;
27-
unsafe { py.from_owned_ptr(ffi::PyBytes_FromStringAndSize(ptr, len)) }
41+
unsafe {
42+
ffi::PyBytes_FromStringAndSize(ptr, len)
43+
.assume_owned(py)
44+
.downcast_into_unchecked()
45+
}
46+
}
47+
48+
/// Deprecated form of [`PyBytes::new_bound_with`].
49+
#[cfg_attr(
50+
not(feature = "gil-refs"),
51+
deprecated(
52+
since = "0.21.0",
53+
note = "`PyBytes::new_with` will be replaced by `PyBytes::new_bound_with` in a future PyO3 version"
54+
)
55+
)]
56+
pub fn new_with<F>(py: Python<'_>, len: usize, init: F) -> PyResult<&PyBytes>
57+
where
58+
F: FnOnce(&mut [u8]) -> PyResult<()>,
59+
{
60+
Self::new_bound_with(py, len, init).map(Bound::into_gil_ref)
2861
}
2962

3063
/// Creates a new Python `bytes` object with an `init` closure to write its contents.
@@ -41,31 +74,31 @@ impl PyBytes {
4174
///
4275
/// # fn main() -> PyResult<()> {
4376
/// Python::with_gil(|py| -> PyResult<()> {
44-
/// let py_bytes = PyBytes::new_with(py, 10, |bytes: &mut [u8]| {
77+
/// let py_bytes = PyBytes::new_bound_with(py, 10, |bytes: &mut [u8]| {
4578
/// bytes.copy_from_slice(b"Hello Rust");
4679
/// Ok(())
4780
/// })?;
48-
/// let bytes: &[u8] = FromPyObject::extract(py_bytes)?;
81+
/// let bytes: &[u8] = py_bytes.extract()?;
4982
/// assert_eq!(bytes, b"Hello Rust");
5083
/// Ok(())
5184
/// })
5285
/// # }
5386
/// ```
54-
pub fn new_with<F>(py: Python<'_>, len: usize, init: F) -> PyResult<&PyBytes>
87+
pub fn new_bound_with<F>(py: Python<'_>, len: usize, init: F) -> PyResult<Bound<'_, PyBytes>>
5588
where
5689
F: FnOnce(&mut [u8]) -> PyResult<()>,
5790
{
5891
unsafe {
5992
let pyptr = ffi::PyBytes_FromStringAndSize(std::ptr::null(), len as ffi::Py_ssize_t);
6093
// Check for an allocation error and return it
61-
let pypybytes: Py<PyBytes> = Py::from_owned_ptr_or_err(py, pyptr)?;
94+
let pybytes = pyptr.assume_owned_or_err(py)?.downcast_into_unchecked();
6295
let buffer: *mut u8 = ffi::PyBytes_AsString(pyptr).cast();
6396
debug_assert!(!buffer.is_null());
6497
// Zero-initialise the uninitialised bytestring
6598
std::ptr::write_bytes(buffer, 0u8, len);
6699
// (Further) Initialise the bytestring in init
67100
// If init returns an Err, pypybytearray will automatically deallocate the buffer
68-
init(std::slice::from_raw_parts_mut(buffer, len)).map(|_| pypybytes.into_ref(py))
101+
init(std::slice::from_raw_parts_mut(buffer, len)).map(|_| pybytes)
69102
}
70103
}
71104

@@ -80,10 +113,23 @@ impl PyBytes {
80113
/// `std::slice::from_raw_parts`, this is
81114
/// unsafe](https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety).
82115
pub unsafe fn from_ptr(py: Python<'_>, ptr: *const u8, len: usize) -> &PyBytes {
83-
py.from_owned_ptr(ffi::PyBytes_FromStringAndSize(
84-
ptr as *const _,
85-
len as isize,
86-
))
116+
Self::bound_from_ptr(py, ptr, len).into_gil_ref()
117+
}
118+
119+
/// Creates a new Python byte string object from a raw pointer and length.
120+
///
121+
/// Panics if out of memory.
122+
///
123+
/// # Safety
124+
///
125+
/// This function dereferences the raw pointer `ptr` as the
126+
/// leading pointer of a slice of length `len`. [As with
127+
/// `std::slice::from_raw_parts`, this is
128+
/// unsafe](https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety).
129+
pub unsafe fn bound_from_ptr(py: Python<'_>, ptr: *const u8, len: usize) -> Bound<'_, PyBytes> {
130+
ffi::PyBytes_FromStringAndSize(ptr as *const _, len as isize)
131+
.assume_owned(py)
132+
.downcast_into_unchecked()
87133
}
88134

89135
/// Gets the Python string as a byte slice.
@@ -160,7 +206,7 @@ impl<'source> FromPyObject<'source> for Cow<'source, [u8]> {
160206

161207
impl ToPyObject for Cow<'_, [u8]> {
162208
fn to_object(&self, py: Python<'_>) -> Py<PyAny> {
163-
PyBytes::new(py, self.as_ref()).into()
209+
PyBytes::new_bound(py, self.as_ref()).into()
164210
}
165211
}
166212

@@ -171,6 +217,7 @@ impl IntoPy<Py<PyAny>> for Cow<'_, [u8]> {
171217
}
172218

173219
#[cfg(test)]
220+
#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))]
174221
mod tests {
175222
use super::*;
176223

tests/test_bytes.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ fn test_pybytes_bytes_conversion() {
2020
}
2121

2222
#[pyfunction]
23-
fn bytes_vec_conversion(py: Python<'_>, bytes: Vec<u8>) -> &PyBytes {
24-
PyBytes::new(py, bytes.as_slice())
23+
fn bytes_vec_conversion(py: Python<'_>, bytes: Vec<u8>) -> Bound<'_, PyBytes> {
24+
PyBytes::new_bound(py, bytes.as_slice())
2525
}
2626

2727
#[test]
@@ -43,7 +43,7 @@ fn test_bytearray_vec_conversion() {
4343
#[test]
4444
fn test_py_as_bytes() {
4545
let pyobj: pyo3::Py<pyo3::types::PyBytes> =
46-
Python::with_gil(|py| pyo3::types::PyBytes::new(py, b"abc").into_py(py));
46+
Python::with_gil(|py| pyo3::types::PyBytes::new_bound(py, b"abc").unbind());
4747

4848
let data = Python::with_gil(|py| pyobj.as_bytes(py));
4949

0 commit comments

Comments
 (0)