diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index 07c8b451e48..5cf634d7e34 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -957,9 +957,10 @@ fn impl_complex_enum( quote! { impl<'py> #pyo3_path::conversion::IntoPyObject<'py> for #cls { type Target = Self; + type Output = #pyo3_path::Bound<'py, Self::Target>; type Error = #pyo3_path::PyErr; - fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result<#pyo3_path::Bound<'py, Self::Target>, Self::Error> { + fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result { match self { #(#match_arms)* } @@ -2027,9 +2028,10 @@ impl<'a> PyClassImplsBuilder<'a> { impl<'py> #pyo3_path::conversion::IntoPyObject<'py> for #cls { type Target = Self; + type Output = #pyo3_path::Bound<'py, Self::Target>; type Error = #pyo3_path::PyErr; - fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result<#pyo3_path::Bound<'py, Self::Target>, Self::Error> { + fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result { #pyo3_path::Bound::new(py, self) } } diff --git a/src/conversion.rs b/src/conversion.rs index 287c9ff6399..231f8f1dd24 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -179,6 +179,86 @@ pub trait IntoPy: Sized { } } +/// Owned or borrowed gil-bound Python smart pointer +pub trait AnyBound<'py, T> { + /// Borrow this smart pointer. + fn as_borrowed(&self) -> Borrowed<'_, 'py, T>; + /// Turns this smart pointer into an owned [`Bound<'py, T>`] + fn into_bound(self) -> Bound<'py, T>; + /// Upcast the target type of this smart pointer + fn into_any(self) -> impl AnyBound<'py, PyAny>; + /// Turn this smart pointer into a strong reference pointer + fn into_ptr(self) -> *mut ffi::PyObject; + /// Turn this smart pointer into an owned [`Py`] + fn unbind(self) -> Py; +} + +impl<'py, T> AnyBound<'py, T> for Bound<'py, T> { + fn as_borrowed(&self) -> Borrowed<'_, 'py, T> { + Bound::as_borrowed(self) + } + + fn into_bound(self) -> Bound<'py, T> { + self + } + + fn into_any(self) -> impl AnyBound<'py, PyAny> { + self.into_any() + } + + fn into_ptr(self) -> *mut ffi::PyObject { + self.into_ptr() + } + + fn unbind(self) -> Py { + self.unbind() + } +} + +impl<'py, T> AnyBound<'py, T> for &Bound<'py, T> { + fn as_borrowed(&self) -> Borrowed<'_, 'py, T> { + Bound::as_borrowed(self) + } + + fn into_bound(self) -> Bound<'py, T> { + self.clone() + } + + fn into_any(self) -> impl AnyBound<'py, PyAny> { + self.as_any() + } + + fn into_ptr(self) -> *mut ffi::PyObject { + self.clone().into_ptr() + } + + fn unbind(self) -> Py { + self.clone().unbind() + } +} + +impl<'py, T> AnyBound<'py, T> for Borrowed<'_, 'py, T> { + fn as_borrowed(&self) -> Borrowed<'_, 'py, T> { + *self + } + + fn into_bound(self) -> Bound<'py, T> { + (*self).to_owned() + } + + fn into_any(self) -> impl AnyBound<'py, PyAny> { + self.to_any() + } + + fn into_ptr(self) -> *mut ffi::PyObject { + (*self).to_owned().into_ptr() + } + + fn unbind(self) -> Py { + (*self).to_owned().unbind() + } +} + /// Defines a conversion from a Rust type to a Python object, which may fail. /// /// It functions similarly to std's [`TryInto`] trait, but requires a [GIL token](Python) @@ -186,55 +266,65 @@ pub trait IntoPy: Sized { pub trait IntoPyObject<'py>: Sized { /// The Python output type type Target; + /// The smart pointer type to use. + /// + /// This will usually be [`Bound<'py, Target>`], but can special cases `&'a Bound<'py, Target>` + /// or [`Borrowed<'a, 'py, Target>`] can be used to minimize reference counting overhead. + type Output: AnyBound<'py, Self::Target>; /// The type returned in the event of a conversion error. type Error; /// Performs the conversion. - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error>; + fn into_pyobject(self, py: Python<'py>) -> Result; } impl<'py, T> IntoPyObject<'py> for Bound<'py, T> { type Target = T; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, _py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, _py: Python<'py>) -> Result { Ok(self) } } -impl<'py, T> IntoPyObject<'py> for &Bound<'py, T> { +impl<'a, 'py, T> IntoPyObject<'py> for &'a Bound<'py, T> { type Target = T; + type Output = &'a Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, _py: Python<'py>) -> Result, Self::Error> { - Ok(self.clone()) + fn into_pyobject(self, _py: Python<'py>) -> Result { + Ok(self) } } -impl<'py, T> IntoPyObject<'py> for Borrowed<'_, 'py, T> { +impl<'a, 'py, T> IntoPyObject<'py> for Borrowed<'a, 'py, T> { type Target = T; + type Output = Borrowed<'a, 'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, _py: Python<'py>) -> Result, Self::Error> { - Ok(self.to_owned()) + fn into_pyobject(self, _py: Python<'py>) -> Result { + Ok(self) } } impl<'py, T> IntoPyObject<'py> for Py { type Target = T; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(self.into_bound(py)) } } -impl<'py, T> IntoPyObject<'py> for &Py { +impl<'a, 'py, T> IntoPyObject<'py> for &'a Py { type Target = T; + type Output = Borrowed<'a, 'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { - Ok(self.bind(py).clone()) + fn into_pyobject(self, py: Python<'py>) -> Result { + Ok(self.bind_borrowed(py)) } } @@ -579,9 +669,10 @@ impl IntoPy> for () { impl<'py> IntoPyObject<'py> for () { type Target = PyTuple; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PyTuple::empty_bound(py)) } } diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index b4e5f119bc5..19882aa4564 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -112,9 +112,10 @@ impl<'py> IntoPyObject<'py> for Duration { type Target = PyAny; #[cfg(not(Py_LIMITED_API))] type Target = PyDelta; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { // Total number of days let days = self.num_days(); // Remainder of seconds @@ -213,9 +214,10 @@ impl<'py> IntoPyObject<'py> for NaiveDate { type Target = PyAny; #[cfg(not(Py_LIMITED_API))] type Target = PyDate; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let DateArgs { year, month, day } = (&self).into(); #[cfg(not(Py_LIMITED_API))] { @@ -280,9 +282,10 @@ impl<'py> IntoPyObject<'py> for NaiveTime { type Target = PyAny; #[cfg(not(Py_LIMITED_API))] type Target = PyTime; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let TimeArgs { hour, min, @@ -338,9 +341,10 @@ impl<'py> IntoPyObject<'py> for NaiveDateTime { type Target = PyAny; #[cfg(not(Py_LIMITED_API))] type Target = PyDateTime; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let DateArgs { year, month, day } = (&self.date()).into(); let TimeArgs { hour, @@ -412,9 +416,10 @@ impl<'py, Tz: TimeZone> IntoPyObject<'py> for DateTime { type Target = PyAny; #[cfg(not(Py_LIMITED_API))] type Target = PyDateTime; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let tz = self.offset().fix().into_pyobject(py)?; let DateArgs { year, month, day } = (&self.naive_local().date()).into(); let TimeArgs { @@ -507,9 +512,10 @@ impl<'py> IntoPyObject<'py> for FixedOffset { type Target = PyAny; #[cfg(not(Py_LIMITED_API))] type Target = PyTzInfo; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let seconds_offset = self.local_minus_utc(); #[cfg(not(Py_LIMITED_API))] { @@ -573,9 +579,10 @@ impl<'py> IntoPyObject<'py> for Utc { type Target = PyAny; #[cfg(not(Py_LIMITED_API))] type Target = PyTzInfo; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { #[cfg(Py_LIMITED_API)] { Ok(timezone_utc_bound(py).into_any()) diff --git a/src/conversions/chrono_tz.rs b/src/conversions/chrono_tz.rs index 5f96a62652d..1b5e3cd95f7 100644 --- a/src/conversions/chrono_tz.rs +++ b/src/conversions/chrono_tz.rs @@ -64,9 +64,10 @@ impl IntoPy for Tz { impl<'py> IntoPyObject<'py> for Tz { type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { static ZONE_INFO: GILOnceCell> = GILOnceCell::new(); ZONE_INFO .get_or_try_init_type_ref(py, "zoneinfo", "ZoneInfo") diff --git a/src/conversions/either.rs b/src/conversions/either.rs index 060971f5ffa..abd06333c70 100644 --- a/src/conversions/either.rs +++ b/src/conversions/either.rs @@ -43,6 +43,7 @@ //! //! [either](https://docs.rs/either/ "A library for easy idiomatic error handling and reporting in Rust applications")’s +use crate::conversion::AnyBound; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ @@ -67,15 +68,17 @@ where } #[cfg_attr(docsrs, doc(cfg(feature = "either")))] -impl<'py, L, R, T, E> IntoPyObject<'py> for Either +impl<'py, L, R, T, E, O> IntoPyObject<'py> for Either where - L: IntoPyObject<'py, Target = T, Error = E>, - R: IntoPyObject<'py, Target = T, Error = E>, + L: IntoPyObject<'py, Target = T, Error = E, Output = O>, + R: IntoPyObject<'py, Target = T, Error = E, Output = O>, + O: AnyBound<'py, T>, { type Target = T; + type Output = O; type Error = E; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { match self { Either::Left(l) => l.into_pyobject(py), Either::Right(r) => r.into_pyobject(py), diff --git a/src/conversions/hashbrown.rs b/src/conversions/hashbrown.rs index 22bbafb0134..686c70e1c14 100644 --- a/src/conversions/hashbrown.rs +++ b/src/conversions/hashbrown.rs @@ -17,7 +17,7 @@ //! Note that you must use compatible versions of hashbrown and PyO3. //! The required hashbrown version may vary based on the version of PyO3. use crate::{ - conversion::IntoPyObject, + conversion::{AnyBound, IntoPyObject}, types::{ any::PyAnyMethods, dict::PyDictMethods, @@ -62,12 +62,16 @@ where PyErr: From + From, { type Target = PyDict; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new_bound(py); for (k, v) in self { - dict.set_item(k.into_pyobject(py)?, v.into_pyobject(py)?)?; + dict.set_item( + k.into_pyobject(py)?.into_bound(), + v.into_pyobject(py)?.into_bound(), + )?; } Ok(dict) } @@ -119,15 +123,16 @@ where PyErr: From, { type Target = PySet; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { try_new_from_iter( py, self.into_iter().map(|item| { item.into_pyobject(py) - .map(Bound::into_any) - .map(Bound::unbind) + .map(AnyBound::into_any) + .map(AnyBound::unbind) .map_err(Into::into) }), ) diff --git a/src/conversions/indexmap.rs b/src/conversions/indexmap.rs index fe0ba5ec187..4a22fbff05f 100644 --- a/src/conversions/indexmap.rs +++ b/src/conversions/indexmap.rs @@ -87,7 +87,7 @@ //! # if another hash table was used, the order could be random //! ``` -use crate::conversion::IntoPyObject; +use crate::conversion::{AnyBound, IntoPyObject}; use crate::types::*; use crate::{Bound, FromPyObject, IntoPy, PyErr, PyObject, Python, ToPyObject}; use std::{cmp, hash}; @@ -125,12 +125,16 @@ where PyErr: From + From, { type Target = PyDict; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new_bound(py); for (k, v) in self { - dict.set_item(k.into_pyobject(py)?, v.into_pyobject(py)?)?; + dict.set_item( + k.into_pyobject(py)?.into_bound(), + v.into_pyobject(py)?.into_bound(), + )?; } Ok(dict) } diff --git a/src/conversions/num_bigint.rs b/src/conversions/num_bigint.rs index daf02f3f6fa..fb24c9796d3 100644 --- a/src/conversions/num_bigint.rs +++ b/src/conversions/num_bigint.rs @@ -138,13 +138,11 @@ macro_rules! bigint_conversion { #[cfg_attr(docsrs, doc(cfg(feature = "num-bigint")))] impl<'py> IntoPyObject<'py> for $rust_ty { type Target = PyLong; + type Output = Bound<'py, Self::Target>; type Error = PyErr; #[cfg(not(Py_LIMITED_API))] - fn into_pyobject( - self, - py: Python<'py>, - ) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { use crate::ffi_ptr_ext::FfiPtrExt; let bytes = $to_bytes(&self); unsafe { @@ -160,10 +158,7 @@ macro_rules! bigint_conversion { } #[cfg(Py_LIMITED_API)] - fn into_pyobject( - self, - py: Python<'py>, - ) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { use $crate::py_result_ext::PyResultExt; let bytes = $to_bytes(&self); let bytes_obj = PyBytes::new_bound(py, &bytes); diff --git a/src/conversions/num_complex.rs b/src/conversions/num_complex.rs index 8910a9efc9c..64b1b978938 100644 --- a/src/conversions/num_complex.rs +++ b/src/conversions/num_complex.rs @@ -150,12 +150,10 @@ macro_rules! complex_conversion { #[cfg_attr(docsrs, doc(cfg(feature = "num-complex")))] impl<'py> crate::conversion::IntoPyObject<'py> for Complex<$float> { type Target = PyComplex; + type Output = Bound<'py, Self::Target>; type Error = std::convert::Infallible; - fn into_pyobject( - self, - py: Python<'py>, - ) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { unsafe { Ok( ffi::PyComplex_FromDoubles(self.re as c_double, self.im as c_double) diff --git a/src/conversions/rust_decimal.rs b/src/conversions/rust_decimal.rs index 5bbb7179e65..a70e955c987 100644 --- a/src/conversions/rust_decimal.rs +++ b/src/conversions/rust_decimal.rs @@ -104,9 +104,10 @@ impl IntoPy for Decimal { impl<'py> IntoPyObject<'py> for Decimal { type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let dec_cls = get_decimal_cls(py)?; // now call the constructor with the Rust Decimal string-ified // to not be lossy diff --git a/src/conversions/smallvec.rs b/src/conversions/smallvec.rs index 81f216c402e..f68adbbaec4 100644 --- a/src/conversions/smallvec.rs +++ b/src/conversions/smallvec.rs @@ -15,7 +15,7 @@ //! //! Note that you must use compatible versions of smallvec and PyO3. //! The required smallvec version may vary based on the version of PyO3. -use crate::conversion::IntoPyObject; +use crate::conversion::{AnyBound, IntoPyObject}; use crate::exceptions::PyTypeError; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; @@ -63,13 +63,14 @@ where PyErr: From<>::Error>, { type Target = PyList; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let mut iter = self.into_iter().map(|e| { e.into_pyobject(py) - .map(Bound::into_any) - .map(Bound::unbind) + .map(AnyBound::into_any) + .map(AnyBound::unbind) .map_err(Into::into) }); try_new_from_iter(py, &mut iter) diff --git a/src/conversions/std/array.rs b/src/conversions/std/array.rs index a4b93e1985f..a728bcec055 100644 --- a/src/conversions/std/array.rs +++ b/src/conversions/std/array.rs @@ -43,9 +43,11 @@ where T: IntoPyObject<'py>, { type Target = PyList; + type Output = Bound<'py, Self::Target>; type Error = T::Error; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { + use crate::conversion::AnyBound; unsafe { let len = N as ffi::Py_ssize_t; diff --git a/src/conversions/std/cell.rs b/src/conversions/std/cell.rs index 9693dde1e8a..c3ea4d97bab 100644 --- a/src/conversions/std/cell.rs +++ b/src/conversions/std/cell.rs @@ -19,9 +19,10 @@ impl> IntoPy for Cell { impl<'py, T: Copy + IntoPyObject<'py>> IntoPyObject<'py> for Cell { type Target = T::Target; + type Output = T::Output; type Error = T::Error; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.get().into_pyobject(py) } } diff --git a/src/conversions/std/ipaddr.rs b/src/conversions/std/ipaddr.rs index 43ff0ec3f11..688ec78ba1a 100755 --- a/src/conversions/std/ipaddr.rs +++ b/src/conversions/std/ipaddr.rs @@ -45,9 +45,10 @@ impl ToPyObject for Ipv4Addr { impl<'py> IntoPyObject<'py> for Ipv4Addr { type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { static IPV4_ADDRESS: GILOnceCell> = GILOnceCell::new(); IPV4_ADDRESS .get_or_try_init_type_ref(py, "ipaddress", "IPv4Address")? @@ -69,9 +70,10 @@ impl ToPyObject for Ipv6Addr { impl<'py> IntoPyObject<'py> for Ipv6Addr { type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { static IPV6_ADDRESS: GILOnceCell> = GILOnceCell::new(); IPV6_ADDRESS .get_or_try_init_type_ref(py, "ipaddress", "IPv6Address")? @@ -96,9 +98,10 @@ impl IntoPy for IpAddr { impl<'py> IntoPyObject<'py> for IpAddr { type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { match self { IpAddr::V4(ip) => ip.into_pyobject(py), IpAddr::V6(ip) => ip.into_pyobject(py), diff --git a/src/conversions/std/map.rs b/src/conversions/std/map.rs index 900b7e6a1cc..0c8859ee7f7 100644 --- a/src/conversions/std/map.rs +++ b/src/conversions/std/map.rs @@ -3,7 +3,7 @@ use std::{cmp, collections, hash}; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - conversion::IntoPyObject, + conversion::{AnyBound, IntoPyObject}, instance::Bound, types::{any::PyAnyMethods, dict::PyDictMethods, IntoPyDict, PyDict}, FromPyObject, IntoPy, PyAny, PyErr, PyObject, Python, ToPyObject, @@ -57,12 +57,16 @@ where PyErr: From + From, { type Target = PyDict; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new_bound(py); for (k, v) in self { - dict.set_item(k.into_pyobject(py)?, v.into_pyobject(py)?)?; + dict.set_item( + k.into_pyobject(py)?.into_bound(), + v.into_pyobject(py)?.into_bound(), + )?; } Ok(dict) } @@ -93,12 +97,16 @@ where PyErr: From + From, { type Target = PyDict; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new_bound(py); for (k, v) in self { - dict.set_item(k.into_pyobject(py)?, v.into_pyobject(py)?)?; + dict.set_item( + k.into_pyobject(py)?.into_bound(), + v.into_pyobject(py)?.into_bound(), + )?; } Ok(dict) } diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index 08a42563ad9..9579c5a0a8d 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -36,12 +36,10 @@ macro_rules! int_fits_larger_int { impl<'py> IntoPyObject<'py> for $rust_type { type Target = PyLong; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject( - self, - py: Python<'py>, - ) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { (self as $larger_type).into_pyobject(py) } } @@ -107,12 +105,10 @@ macro_rules! int_convert_u64_or_i64 { } impl<'py> IntoPyObject<'py> for $rust_type { type Target = PyLong; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject( - self, - py: Python<'py>, - ) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { unsafe { Ok($pylong_from_ll_or_ull(self) .assume_owned(py) @@ -153,12 +149,10 @@ macro_rules! int_fits_c_long { impl<'py> IntoPyObject<'py> for $rust_type { type Target = PyLong; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject( - self, - py: Python<'py>, - ) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { unsafe { Ok(ffi::PyLong_FromLong(self as c_long) .assume_owned(py) diff --git a/src/conversions/std/option.rs b/src/conversions/std/option.rs index bc641c42257..00bffb5092c 100644 --- a/src/conversions/std/option.rs +++ b/src/conversions/std/option.rs @@ -1,3 +1,4 @@ +use crate::conversion::AnyBound; use crate::{ conversion::IntoPyObject, ffi, types::any::PyAnyMethods, AsPyPointer, Bound, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject, @@ -29,12 +30,17 @@ where T: IntoPyObject<'py>, { type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = T::Error; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.map_or_else( || Ok(py.None().into_bound(py)), - |val| val.into_pyobject(py).map(Bound::into_any), + |val| { + val.into_pyobject(py) + .map(AnyBound::into_any) + .map(AnyBound::into_bound) + }, ) } } diff --git a/src/conversions/std/osstr.rs b/src/conversions/std/osstr.rs index 5bc32bc8331..3904010d35a 100644 --- a/src/conversions/std/osstr.rs +++ b/src/conversions/std/osstr.rs @@ -16,9 +16,10 @@ impl ToPyObject for OsStr { impl<'py> IntoPyObject<'py> for &OsStr { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { // If the string is UTF-8, take the quick and easy shortcut if let Some(valid_utf8_path) = self.to_str() { return valid_utf8_path.into_pyobject(py); @@ -141,9 +142,10 @@ impl IntoPy for Cow<'_, OsStr> { impl<'py> IntoPyObject<'py> for Cow<'_, OsStr> { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) } } @@ -163,9 +165,10 @@ impl IntoPy for OsString { impl<'py> IntoPyObject<'py> for OsString { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) } } @@ -178,9 +181,10 @@ impl<'a> IntoPy for &'a OsString { impl<'py> IntoPyObject<'py> for &OsString { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) } } diff --git a/src/conversions/std/path.rs b/src/conversions/std/path.rs index c0e83174275..1540c852f05 100644 --- a/src/conversions/std/path.rs +++ b/src/conversions/std/path.rs @@ -34,9 +34,10 @@ impl<'a> IntoPy for &'a Path { impl<'py> IntoPyObject<'py> for &Path { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) } } @@ -57,9 +58,10 @@ impl<'a> IntoPy for Cow<'a, Path> { impl<'py> IntoPyObject<'py> for Cow<'_, Path> { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) } } @@ -79,9 +81,10 @@ impl IntoPy for PathBuf { impl<'py> IntoPyObject<'py> for PathBuf { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) } } @@ -94,9 +97,10 @@ impl<'a> IntoPy for &'a PathBuf { impl<'py> IntoPyObject<'py> for &PathBuf { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) } } diff --git a/src/conversions/std/set.rs b/src/conversions/std/set.rs index 93dc70f3b6d..3247238ef70 100644 --- a/src/conversions/std/set.rs +++ b/src/conversions/std/set.rs @@ -3,7 +3,7 @@ use std::{cmp, collections, hash}; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - conversion::IntoPyObject, + conversion::{AnyBound, IntoPyObject}, instance::Bound, types::{ any::PyAnyMethods, @@ -61,15 +61,16 @@ where PyErr: From, { type Target = PySet; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { try_new_from_iter( py, self.into_iter().map(|item| { item.into_pyobject(py) - .map(Bound::into_any) - .map(Bound::unbind) + .map(AnyBound::into_any) + .map(AnyBound::unbind) .map_err(Into::into) }), ) @@ -122,15 +123,16 @@ where PyErr: From, { type Target = PySet; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { try_new_from_iter( py, self.into_iter().map(|item| { item.into_pyobject(py) - .map(Bound::into_any) - .map(Bound::unbind) + .map(AnyBound::into_any) + .map(AnyBound::unbind) .map_err(Into::into) }), ) diff --git a/src/conversions/std/slice.rs b/src/conversions/std/slice.rs index b8eb1f8b68b..55309cd63fc 100644 --- a/src/conversions/std/slice.rs +++ b/src/conversions/std/slice.rs @@ -21,9 +21,10 @@ impl<'a> IntoPy for &'a [u8] { impl<'py> IntoPyObject<'py> for &[u8] { type Target = PyBytes; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PyBytes::new_bound(py, self)) } } @@ -101,9 +102,10 @@ impl IntoPy> for Cow<'_, [u8]> { impl<'py> IntoPyObject<'py> for Cow<'_, [u8]> { type Target = PyBytes; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PyBytes::new_bound(py, &self)) } } diff --git a/src/conversions/std/string.rs b/src/conversions/std/string.rs index 4a3f6b6ed1f..9adea563baa 100644 --- a/src/conversions/std/string.rs +++ b/src/conversions/std/string.rs @@ -44,9 +44,10 @@ impl<'a> IntoPy> for &'a str { impl<'py> IntoPyObject<'py> for &str { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PyString::new_bound(py, self)) } } @@ -74,9 +75,10 @@ impl IntoPy for Cow<'_, str> { impl<'py> IntoPyObject<'py> for Cow<'_, str> { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) } } @@ -110,9 +112,10 @@ impl IntoPy for char { impl<'py> IntoPyObject<'py> for char { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let mut bytes = [0u8; 4]; Ok(PyString::new_bound(py, self.encode_utf8(&mut bytes))) } @@ -131,9 +134,10 @@ impl IntoPy for String { impl<'py> IntoPyObject<'py> for String { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PyString::new_bound(py, &self)) } } @@ -152,9 +156,10 @@ impl<'a> IntoPy for &'a String { impl<'py> IntoPyObject<'py> for &String { type Target = PyString; + type Output = Bound<'py, Self::Target>; type Error = Infallible; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PyString::new_bound(py, self)) } } diff --git a/src/conversions/std/time.rs b/src/conversions/std/time.rs index 4c725fd21fd..31b7afa79a1 100755 --- a/src/conversions/std/time.rs +++ b/src/conversions/std/time.rs @@ -95,9 +95,10 @@ impl<'py> IntoPyObject<'py> for Duration { type Target = PyDelta; #[cfg(Py_LIMITED_API)] type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let days = self.as_secs() / SECONDS_PER_DAY; let seconds = self.as_secs() % SECONDS_PER_DAY; let microseconds = self.subsec_micros(); @@ -158,9 +159,10 @@ impl IntoPy for SystemTime { impl<'py> IntoPyObject<'py> for SystemTime { type Target = PyAny; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let duration_since_unix_epoch = self.duration_since(UNIX_EPOCH).unwrap().into_pyobject(py)?; unix_epoch_py(py) diff --git a/src/conversions/std/vec.rs b/src/conversions/std/vec.rs index 425c94ea215..390a2f02b56 100644 --- a/src/conversions/std/vec.rs +++ b/src/conversions/std/vec.rs @@ -1,4 +1,4 @@ -use crate::conversion::IntoPyObject; +use crate::conversion::{AnyBound, IntoPyObject}; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::types::list::{new_from_iter, try_new_from_iter}; @@ -47,13 +47,14 @@ where PyErr: From, { type Target = PyList; + type Output = Bound<'py, Self::Target>; type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, py: Python<'py>) -> Result { let mut iter = self.into_iter().map(|e| { e.into_pyobject(py) - .map(Bound::into_any) - .map(Bound::unbind) + .map(AnyBound::into_any) + .map(AnyBound::unbind) .map_err(Into::into) }); diff --git a/src/impl_/wrap.rs b/src/impl_/wrap.rs index 2f122f8f407..88a289d940f 100644 --- a/src/impl_/wrap.rs +++ b/src/impl_/wrap.rs @@ -1,5 +1,6 @@ use std::convert::Infallible; +use crate::conversion::AnyBound; use crate::{ conversion::IntoPyObject, ffi, types::PyNone, Bound, IntoPy, PyErr, PyObject, PyResult, Python, }; @@ -128,6 +129,7 @@ impl IntoPyObjectTag { PyErr: From, { obj.and_then(|obj| obj.into_pyobject(py).map_err(Into::into)) + .map(AnyBound::into_bound) .map(Bound::into_ptr) } diff --git a/src/instance.rs b/src/instance.rs index 697df2c7bae..fdff9bbf6c9 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -552,7 +552,7 @@ unsafe impl AsPyPointer for Bound<'_, T> { #[repr(transparent)] pub struct Borrowed<'a, 'py, T>(NonNull, PhantomData<&'a Py>, Python<'py>); -impl<'py, T> Borrowed<'_, 'py, T> { +impl<'a, 'py, T> Borrowed<'a, 'py, T> { /// Creates a new owned [`Bound`] from this borrowed reference by /// increasing the reference count. /// @@ -580,6 +580,10 @@ impl<'py, T> Borrowed<'_, 'py, T> { pub fn to_owned(self) -> Bound<'py, T> { (*self).clone() } + + pub(crate) fn to_any(self) -> Borrowed<'a, 'py, PyAny> { + Borrowed(self.0, PhantomData, self.2) + } } impl<'a, 'py> Borrowed<'a, 'py, PyAny> { diff --git a/src/pycell.rs b/src/pycell.rs index 2cd70d2fcdf..aec27d5ebac 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -831,19 +831,21 @@ impl IntoPy for &'_ PyRef<'_, T> { impl<'py, T: PyClass> IntoPyObject<'py> for PyRef<'py, T> { type Target = T; + type Output = Bound<'py, T>; type Error = Infallible; - fn into_pyobject(self, _py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, _py: Python<'py>) -> Result { Ok(self.inner.clone()) } } -impl<'py, T: PyClass> IntoPyObject<'py> for &PyRef<'py, T> { +impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRef<'py, T> { type Target = T; + type Output = &'a Bound<'py, T>; type Error = Infallible; - fn into_pyobject(self, _py: Python<'py>) -> Result, Self::Error> { - Ok(self.inner.clone()) + fn into_pyobject(self, _py: Python<'py>) -> Result { + Ok(&self.inner) } } @@ -1027,19 +1029,21 @@ impl> IntoPy for &'_ PyRefMut<'_, T> { impl<'py, T: PyClass> IntoPyObject<'py> for PyRefMut<'py, T> { type Target = T; + type Output = Bound<'py, T>; type Error = Infallible; - fn into_pyobject(self, _py: Python<'py>) -> Result, Self::Error> { + fn into_pyobject(self, _py: Python<'py>) -> Result { Ok(self.inner.clone()) } } -impl<'py, T: PyClass> IntoPyObject<'py> for &PyRefMut<'py, T> { +impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRefMut<'py, T> { type Target = T; + type Output = &'a Bound<'py, T>; type Error = Infallible; - fn into_pyobject(self, _py: Python<'py>) -> Result, Self::Error> { - Ok(self.inner.clone()) + fn into_pyobject(self, _py: Python<'py>) -> Result { + Ok(&self.inner) } }