diff --git a/src/conversion.rs b/src/conversion.rs index aec15a05..50b5a698 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -165,7 +165,7 @@ where /// Extract reference to instance from `PyObject` impl<'a, T> FromPyObject<'a> for &'a T where - T: PyTryFrom, + T: PyTryFrom<'a>, { #[inline] default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T> { @@ -176,7 +176,7 @@ where /// Extract mutable reference to instance from `PyObject` impl<'a, T> FromPyObject<'a> for &'a mut T where - T: PyTryFrom, + T: PyTryFrom<'a>, { #[inline] default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a mut T> { @@ -221,33 +221,35 @@ pub trait PyTryInto: Sized { /// Trait implemented by Python object types that allow a checked downcast. /// This trait is similar to `std::convert::TryFrom` -pub trait PyTryFrom: Sized { +pub trait PyTryFrom<'v>: Sized { /// Cast from a concrete Python object type to PyObject. - fn try_from(value: &PyObjectRef) -> Result<&Self, PyDowncastError>; + fn try_from>(value: V) -> Result<&'v Self, PyDowncastError>; /// Cast from a concrete Python object type to PyObject. With exact type check. - fn try_from_exact(value: &PyObjectRef) -> Result<&Self, PyDowncastError>; + fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError>; /// Cast from a concrete Python object type to PyObject. - fn try_from_mut(value: &PyObjectRef) -> Result<&mut Self, PyDowncastError>; + fn try_from_mut>(value: V) -> Result<&'v mut Self, PyDowncastError>; /// Cast from a concrete Python object type to PyObject. With exact type check. - fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut Self, PyDowncastError>; + fn try_from_mut_exact>( + value: V, + ) -> Result<&'v mut Self, PyDowncastError>; /// Cast a PyObjectRef to a specific type of PyObject. The caller must /// have already verified the reference is for this type. - unsafe fn try_from_unchecked(value: &PyObjectRef) -> &Self; + unsafe fn try_from_unchecked>(value: V) -> &'v Self; /// Cast a PyObjectRef to a specific type of PyObject. The caller must /// have already verified the reference is for this type. #[allow(clippy::mut_from_ref)] - unsafe fn try_from_mut_unchecked(value: &PyObjectRef) -> &mut Self; + unsafe fn try_from_mut_unchecked>(value: V) -> &'v mut Self; } // TryFrom implies TryInto impl PyTryInto for PyObjectRef where - U: PyTryFrom, + U: for<'v> PyTryFrom<'v>, { type Error = PyDowncastError; @@ -265,11 +267,12 @@ where } } -impl PyTryFrom for T +impl<'v, T> PyTryFrom<'v> for T where T: PyTypeInfo, { - fn try_from(value: &PyObjectRef) -> Result<&T, PyDowncastError> { + fn try_from>(value: V) -> Result<&'v T, PyDowncastError> { + let value = value.into(); unsafe { if T::is_instance(value) { Ok(PyTryFrom::try_from_unchecked(value)) @@ -279,7 +282,8 @@ where } } - fn try_from_exact(value: &PyObjectRef) -> Result<&T, PyDowncastError> { + fn try_from_exact>(value: V) -> Result<&'v T, PyDowncastError> { + let value = value.into(); unsafe { if T::is_exact_instance(value) { Ok(PyTryFrom::try_from_unchecked(value)) @@ -289,7 +293,8 @@ where } } - fn try_from_mut(value: &PyObjectRef) -> Result<&mut T, PyDowncastError> { + fn try_from_mut>(value: V) -> Result<&'v mut T, PyDowncastError> { + let value = value.into(); unsafe { if T::is_instance(value) { Ok(PyTryFrom::try_from_mut_unchecked(value)) @@ -299,7 +304,10 @@ where } } - fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut T, PyDowncastError> { + fn try_from_mut_exact>( + value: V, + ) -> Result<&'v mut T, PyDowncastError> { + let value = value.into(); unsafe { if T::is_exact_instance(value) { Ok(PyTryFrom::try_from_mut_unchecked(value)) @@ -310,7 +318,8 @@ where } #[inline] - unsafe fn try_from_unchecked(value: &PyObjectRef) -> &T { + unsafe fn try_from_unchecked>(value: V) -> &'v T { + let value = value.into(); let ptr = if T::OFFSET == 0 { value as *const _ as *const u8 as *const T } else { @@ -320,7 +329,8 @@ where } #[inline] - unsafe fn try_from_mut_unchecked(value: &PyObjectRef) -> &mut T { + unsafe fn try_from_mut_unchecked>(value: V) -> &'v mut T { + let value = value.into(); let ptr = if T::OFFSET == 0 { value as *const _ as *mut u8 as *mut T } else { @@ -357,8 +367,6 @@ impl ReturnTypeIntoPyResult for PyResult { } } - - #[cfg(test)] mod test { use super::PyTryFrom; diff --git a/src/instance.rs b/src/instance.rs index d5fd4995..d5ab353f 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -55,6 +55,15 @@ impl<'a, T> Deref for PyRef<'a, T> { } } +impl<'a, T> Into<&'a PyObjectRef> for PyRef<'a, T> +where + T: PyTypeInfo, +{ + fn into(self) -> &'a PyObjectRef { + unsafe { &*(self.as_ptr() as *const PyObjectRef) } + } +} + #[derive(Debug)] pub struct PyRefMut<'a, T> { inner: &'a mut T, @@ -91,18 +100,27 @@ impl<'a, T> DerefMut for PyRefMut<'a, T> { } } +impl<'a, T> Into<&'a PyObjectRef> for PyRefMut<'a, T> +where + T: PyTypeInfo, +{ + fn into(self) -> &'a PyObjectRef { + unsafe { &*(self.as_ptr() as *const PyObjectRef) } + } +} + /// Trait implements object reference extraction from python managed pointer. pub trait AsPyRef: Sized { /// Return reference to object. - fn as_ref(&self, py: Python) -> &T; + fn as_ref(&self, py: Python) -> PyRef; /// Return mutable reference to object. - fn as_mut(&mut self, py: Python) -> &mut T; + fn as_mut(&mut self, py: Python) -> PyRefMut; /// Acquire python gil and call closure with object reference. fn with(&self, f: F) -> R where - F: FnOnce(Python, &T) -> R, + F: FnOnce(Python, PyRef) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); @@ -113,7 +131,7 @@ pub trait AsPyRef: Sized { /// Acquire python gil and call closure with mutable object reference. fn with_mut(&mut self, f: F) -> R where - F: FnOnce(Python, &mut T) -> R, + F: FnOnce(Python, PyRefMut) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); @@ -124,7 +142,7 @@ pub trait AsPyRef: Sized { fn into_py(self, f: F) -> R where Self: IntoPyPointer, - F: FnOnce(Python, &T) -> R, + F: FnOnce(Python, PyRef) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); @@ -137,7 +155,7 @@ pub trait AsPyRef: Sized { fn into_mut_py(mut self, f: F) -> R where Self: IntoPyPointer, - F: FnOnce(Python, &mut T) -> R, + F: FnOnce(Python, PyRefMut) -> R, { let gil = Python::acquire_gil(); let py = gil.python(); @@ -307,12 +325,12 @@ where T: PyTypeInfo, { #[inline] - fn as_ref(&self, py: Python) -> &T { - self.as_ref_dispatch(py) + fn as_ref(&self, py: Python) -> PyRef { + PyRef::new(self.as_ref_dispatch(py)) } #[inline] - fn as_mut(&mut self, py: Python) -> &mut T { - self.as_mut_dispatch(py) + fn as_mut(&mut self, py: Python) -> PyRefMut { + PyRefMut::new(self.as_mut_dispatch(py)) } } diff --git a/src/object.rs b/src/object.rs index cfd7c771..dbac3955 100644 --- a/src/object.rs +++ b/src/object.rs @@ -7,7 +7,7 @@ use crate::conversion::{ }; use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; -use crate::instance::{AsPyRef, PyObjectWithGIL}; +use crate::instance::{AsPyRef, PyObjectWithGIL, PyRef, PyRefMut}; use crate::python::{IntoPyPointer, Python, ToPyPointer}; use crate::pythonrun; use crate::types::{PyDict, PyObjectRef, PyTuple}; @@ -154,7 +154,7 @@ impl PyObject { /// Casts the PyObject to a concrete Python object type. pub fn cast_as(&self, py: Python) -> Result<&D, PyDowncastError> where - D: PyTryFrom, + D: for<'v> PyTryFrom<'v>, { D::try_from(self.as_ref(py)) } @@ -165,7 +165,7 @@ impl PyObject { where D: FromPyObject<'p>, { - FromPyObject::extract(self.as_ref(py)) + FromPyObject::extract(self.as_ref(py).into()) } /// Retrieves an attribute value. @@ -256,12 +256,12 @@ impl PyObject { impl AsPyRef for PyObject { #[inline] - fn as_ref(&self, _py: Python) -> &PyObjectRef { - unsafe { &*(self as *const _ as *const PyObjectRef) } + fn as_ref(&self, _py: Python) -> PyRef { + unsafe { PyRef::new(&*(self as *const _ as *const PyObjectRef)) } } #[inline] - fn as_mut(&mut self, _py: Python) -> &mut PyObjectRef { - unsafe { &mut *(self as *mut _ as *mut PyObjectRef) } + fn as_mut(&mut self, _py: Python) -> PyRefMut { + unsafe { PyRefMut::new(&mut *(self as *mut _ as *mut PyObjectRef)) } } } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index a4bf2372..e3c20052 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -187,7 +187,7 @@ pub trait ObjectProtocol { /// Casts the PyObject to a concrete Python object type. fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom, + D: PyTryFrom<'a>, &'a PyObjectRef: std::convert::From<&'a Self>; /// Extracts some type from the Python object. @@ -471,10 +471,10 @@ where fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom, + D: PyTryFrom<'a>, &'a PyObjectRef: std::convert::From<&'a Self>, { - D::try_from(self.into()) + D::try_from(self) } fn extract<'a, D>(&'a self) -> PyResult diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 0a74dfe8..70943658 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -85,12 +85,12 @@ impl<'p> Drop for PyIterator<'p> { mod tests { use indoc::indoc; - use crate::conversion::{PyTryFrom, ToPyObject}; + use crate::conversion::ToPyObject; use crate::instance::AsPyRef; use crate::objectprotocol::ObjectProtocol; use crate::python::Python; use crate::pythonrun::GILPool; - use crate::types::{PyDict, PyList, PyObjectRef}; + use crate::types::{PyDict, PyList}; use crate::GILGuard; #[test] @@ -98,7 +98,7 @@ mod tests { let gil_guard = Python::acquire_gil(); let py = gil_guard.python(); let obj = vec![10, 20].to_object(py); - let inst = ::try_from(obj.as_ref(py)).unwrap(); + let inst = obj.as_ref(py); let mut it = inst.iter().unwrap(); assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap()); assert_eq!(20, it.next().unwrap().unwrap().extract().unwrap()); @@ -119,7 +119,7 @@ mod tests { { let gil_guard = Python::acquire_gil(); let py = gil_guard.python(); - let inst = ::try_from(obj.as_ref(py)).unwrap(); + let inst = obj.as_ref(py); let mut it = inst.iter().unwrap(); assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap()); @@ -147,7 +147,7 @@ mod tests { { let _pool = GILPool::new(); - let inst = ::try_from(obj.as_ref(py)).unwrap(); + let inst = obj.as_ref(py); let mut it = inst.iter().unwrap(); assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap()); diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 8127ed01..7cadfa7b 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -275,8 +275,9 @@ where Ok(v) } -impl PyTryFrom for PySequence { - fn try_from(value: &PyObjectRef) -> Result<&PySequence, PyDowncastError> { +impl<'v> PyTryFrom<'v> for PySequence { + fn try_from>(value: V) -> Result<&'v PySequence, PyDowncastError> { + let value = value.into(); unsafe { if ffi::PySequence_Check(value.as_ptr()) != 0 { Ok(::try_from_unchecked(value)) @@ -286,11 +287,16 @@ impl PyTryFrom for PySequence { } } - fn try_from_exact(value: &PyObjectRef) -> Result<&PySequence, PyDowncastError> { + fn try_from_exact>( + value: V, + ) -> Result<&'v PySequence, PyDowncastError> { ::try_from(value) } - fn try_from_mut(value: &PyObjectRef) -> Result<&mut PySequence, PyDowncastError> { + fn try_from_mut>( + value: V, + ) -> Result<&'v mut PySequence, PyDowncastError> { + let value = value.into(); unsafe { if ffi::PySequence_Check(value.as_ptr()) != 0 { Ok(::try_from_mut_unchecked(value)) @@ -300,19 +306,21 @@ impl PyTryFrom for PySequence { } } - fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut PySequence, PyDowncastError> { + fn try_from_mut_exact>( + value: V, + ) -> Result<&'v mut PySequence, PyDowncastError> { ::try_from_mut(value) } #[inline] - unsafe fn try_from_unchecked(value: &PyObjectRef) -> &PySequence { - let ptr = value as *const _ as *const PySequence; + unsafe fn try_from_unchecked>(value: V) -> &'v PySequence { + let ptr = value.into() as *const _ as *const PySequence; &*ptr } #[inline] - unsafe fn try_from_mut_unchecked(value: &PyObjectRef) -> &mut PySequence { - let ptr = value as *const _ as *mut PySequence; + unsafe fn try_from_mut_unchecked>(value: V) -> &'v mut PySequence { + let ptr = value.into() as *const _ as *mut PySequence; &mut *ptr } } diff --git a/src/types/string.rs b/src/types/string.rs index 73d10348..5a8b7663 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -141,7 +141,7 @@ mod test { let s = "Hello Python"; let py_string = s.to_object(py); - let s2: &str = FromPyObject::extract(py_string.as_ref(py)).unwrap(); + let s2: &str = FromPyObject::extract(py_string.as_ref(py).into()).unwrap(); assert_eq!(s, s2); } diff --git a/src/types/tuple.rs b/src/types/tuple.rs index afd38304..6a3e7c04 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -115,7 +115,7 @@ impl<'a> Iterator for PyTupleIterator<'a> { if self.index < self.slice.len() { let item = self.slice[self.index].as_ref(self.py); self.index += 1; - Some(item) + Some(item.into()) } else { None }