Skip to content

Commit c44d2f5

Browse files
authored
Merge pull request #3692 from davidhewitt/as-bound
Add `as_borrowed` conversion from gil-refs to `Bound<T>`
2 parents f37c682 + d36ad8f commit c44d2f5

20 files changed

+201
-242
lines changed

newsfragments/3692.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `PyNativeType::as_bound` to convert "GIL refs" to the new `Bound` smart pointer.

newsfragments/3692.changed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Include `PyNativeType` in `pyo3::prelude`.

src/conversions/chrono.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
//! }
4343
//! ```
4444
use crate::exceptions::{PyTypeError, PyUserWarning, PyValueError};
45-
use crate::instance::Bound;
4645
#[cfg(Py_LIMITED_API)]
4746
use crate::sync::GILOnceCell;
4847
#[cfg(not(Py_LIMITED_API))]
@@ -56,7 +55,9 @@ use crate::types::{
5655
};
5756
#[cfg(Py_LIMITED_API)]
5857
use crate::{intern, PyDowncastError};
59-
use crate::{FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject};
58+
use crate::{
59+
FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject,
60+
};
6061
use chrono::offset::{FixedOffset, Utc};
6162
use chrono::{
6263
DateTime, Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone, Timelike,
@@ -466,7 +467,7 @@ fn warn_truncated_leap_second(obj: &PyAny) {
466467
"ignored leap-second, `datetime` does not support leap-seconds",
467468
0,
468469
) {
469-
e.write_unraisable_bound(py, Some(Bound::borrowed_from_gil_ref(&obj)))
470+
e.write_unraisable_bound(py, Some(&obj.as_borrowed()))
470471
};
471472
}
472473

src/err/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
exceptions::{self, PyBaseException},
88
ffi,
99
};
10-
use crate::{IntoPy, Py, PyAny, PyObject, Python, ToPyObject};
10+
use crate::{IntoPy, Py, PyAny, PyNativeType, PyObject, Python, ToPyObject};
1111
use std::borrow::Cow;
1212
use std::cell::UnsafeCell;
1313
use std::ffi::CString;
@@ -542,7 +542,7 @@ impl PyErr {
542542
)]
543543
#[inline]
544544
pub fn write_unraisable(self, py: Python<'_>, obj: Option<&PyAny>) {
545-
self.write_unraisable_bound(py, obj.as_ref().map(Bound::borrowed_from_gil_ref))
545+
self.write_unraisable_bound(py, obj.map(PyAny::as_borrowed).as_deref())
546546
}
547547

548548
/// Reports the error as unraisable.
@@ -821,7 +821,7 @@ impl<'a> std::error::Error for PyDowncastError<'a> {}
821821

822822
impl<'a> std::fmt::Display for PyDowncastError<'a> {
823823
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
824-
display_downcast_error(f, Bound::borrowed_from_gil_ref(&self.from), &self.to)
824+
display_downcast_error(f, &self.from.as_borrowed(), &self.to)
825825
}
826826
}
827827

src/instance.rs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ pub unsafe trait PyNativeType: Sized {
2828
/// The form of this which is stored inside a `Py<T>` smart pointer.
2929
type AsRefSource: HasPyGilRef<AsRefTarget = Self>;
3030

31+
/// Cast `&self` to a `Borrowed` smart pointer.
32+
///
33+
/// `Borrowed<T>` implements `Deref<Target=Bound<T>>`, so can also be used in locations
34+
/// where `Bound<T>` is expected.
35+
///
36+
/// This is available as a migration tool to adjust code from the deprecated "GIL Refs"
37+
/// API to the `Bound` smart pointer API.
38+
fn as_borrowed(&self) -> Borrowed<'_, '_, Self::AsRefSource> {
39+
// Safety: &'py Self is expected to be a Python pointer,
40+
// so has the same layout as Borrowed<'py, 'py, T>
41+
unsafe { std::mem::transmute(self) }
42+
}
43+
3144
/// Returns a GIL marker constrained to the lifetime of this type.
3245
#[inline]
3346
fn py(&self) -> Python<'_> {
@@ -184,16 +197,13 @@ impl<'py, T> Bound<'py, T> {
184197
self.into_non_null().as_ptr()
185198
}
186199

187-
/// Internal helper to convert e.g. &'a &'py PyDict to &'a Bound<'py, PyDict> for
188-
/// backwards-compatibility during migration to removal of pool.
189-
#[doc(hidden)] // public and doc(hidden) to use in examples and tests for now
190-
pub fn borrowed_from_gil_ref<'a, U>(gil_ref: &'a &'py U) -> &'a Self
191-
where
192-
U: PyNativeType<AsRefSource = T>,
193-
{
194-
// Safety: &'py T::AsRefTarget is expected to be a Python pointer,
195-
// so &'a &'py T::AsRefTarget has the same layout as &'a Bound<'py, T>
196-
unsafe { std::mem::transmute(gil_ref) }
200+
/// Casts this `Bound<T>` to a `Borrowed<T>` smart pointer.
201+
pub fn as_borrowed<'a>(&'a self) -> Borrowed<'a, 'py, T> {
202+
Borrowed(
203+
unsafe { NonNull::new_unchecked(self.as_ptr()) },
204+
PhantomData,
205+
self.py(),
206+
)
197207
}
198208

199209
/// Casts this `Bound<T>` as the corresponding "GIL Ref" type.
@@ -299,24 +309,14 @@ impl<'a, 'py> Borrowed<'a, 'py, PyAny> {
299309
impl<'a, 'py, T> From<&'a Bound<'py, T>> for Borrowed<'a, 'py, T> {
300310
/// Create borrow on a Bound
301311
fn from(instance: &'a Bound<'py, T>) -> Self {
302-
Self(
303-
unsafe { NonNull::new_unchecked(instance.as_ptr()) },
304-
PhantomData,
305-
instance.py(),
306-
)
312+
instance.as_borrowed()
307313
}
308314
}
309315

310316
impl<'py, T> Borrowed<'py, 'py, T>
311317
where
312318
T: HasPyGilRef,
313319
{
314-
pub(crate) fn from_gil_ref(gil_ref: &'py T::AsRefTarget) -> Self {
315-
// Safety: &'py T::AsRefTarget is expected to be a Python pointer,
316-
// so &'py T::AsRefTarget has the same layout as Self.
317-
unsafe { std::mem::transmute(gil_ref) }
318-
}
319-
320320
// pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget {
321321
// // Safety: self is a borrow over `'py`.
322322
// unsafe { self.py().from_borrowed_ptr(self.0.as_ptr()) }
@@ -1366,7 +1366,7 @@ where
13661366
{
13671367
/// Extracts `Self` from the source `PyObject`.
13681368
fn extract(ob: &'a PyAny) -> PyResult<Self> {
1369-
Bound::borrowed_from_gil_ref(&ob)
1369+
ob.as_borrowed()
13701370
.downcast()
13711371
.map(Clone::clone)
13721372
.map_err(Into::into)
@@ -1485,7 +1485,7 @@ impl PyObject {
14851485
mod tests {
14861486
use super::{Bound, Py, PyObject};
14871487
use crate::types::{PyDict, PyString};
1488-
use crate::{PyAny, PyResult, Python, ToPyObject};
1488+
use crate::{PyAny, PyNativeType, PyResult, Python, ToPyObject};
14891489

14901490
#[test]
14911491
fn test_call0() {
@@ -1612,8 +1612,11 @@ a = A()
16121612
#[test]
16131613
fn test_py2_into_py_object() {
16141614
Python::with_gil(|py| {
1615-
let instance: Bound<'_, PyAny> =
1616-
Bound::borrowed_from_gil_ref(&py.eval("object()", None, None).unwrap()).clone();
1615+
let instance = py
1616+
.eval("object()", None, None)
1617+
.unwrap()
1618+
.as_borrowed()
1619+
.to_owned();
16171620
let ptr = instance.as_ptr();
16181621
let instance: PyObject = instance.clone().into();
16191622
assert_eq!(instance.as_ptr(), ptr);

src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub use crate::marker::Python;
1717
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
1818
pub use crate::pyclass_init::PyClassInitializer;
1919
pub use crate::types::{PyAny, PyModule};
20+
pub use crate::PyNativeType;
2021

2122
#[cfg(feature = "macros")]
2223
pub use pyo3_macros::{pyclass, pyfunction, pymethods, pymodule, FromPyObject};

0 commit comments

Comments
 (0)