From 3fa4326c42755e24f5d1f21b17d0893a8d5e087f Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Tue, 28 Apr 2020 20:25:33 +0100 Subject: [PATCH 01/11] Experimenting with PyAny<'a> --- src/conversion.rs | 26 +++++++++++++------------- src/err.rs | 2 +- src/exceptions.rs | 16 ++++++++-------- src/instance.rs | 13 +++++++------ src/marshal.rs | 2 +- src/object.rs | 6 +++--- src/objectprotocol.rs | 8 ++++---- src/pycell.rs | 4 ++-- src/python.rs | 10 +++++----- src/type_object.rs | 16 ++++++++-------- src/types/any.rs | 11 ++++++----- src/types/boolobject.rs | 2 +- src/types/datetime.rs | 20 ++++++++++---------- src/types/dict.rs | 6 +++--- src/types/iterator.rs | 4 ++-- src/types/list.rs | 4 ++-- src/types/mod.rs | 30 +++++++++++++++--------------- src/types/sequence.rs | 10 +++++----- src/types/set.rs | 8 ++++---- src/types/tuple.rs | 4 ++-- src/types/typeobject.rs | 9 +++++---- 21 files changed, 107 insertions(+), 104 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index 6ca0792a58d..76a48971404 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -311,16 +311,16 @@ where /// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`. /// /// This trait is similar to `std::convert::TryFrom` -pub trait PyTryFrom<'v>: Sized + PyDowncastImpl { +pub trait PyTryFrom<'v>: Sized + PyDowncastImpl<'v> { /// Cast from a concrete Python object type to PyObject. - fn try_from>(value: V) -> Result<&'v 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: V) -> Result<&'v Self, PyDowncastError>; + fn try_from_exact>>(value: V) -> Result<&'v Self, PyDowncastError>; /// Cast a PyAny to a specific type of PyObject. The caller must /// have already verified the reference is for this type. - unsafe fn try_from_unchecked>(value: V) -> &'v Self; + unsafe fn try_from_unchecked>>(value: V) -> &'v Self; } /// Trait implemented by Python object types that allow a checked downcast. @@ -334,9 +334,9 @@ pub trait PyTryInto: Sized { } // TryFrom implies TryInto -impl PyTryInto for PyAny +impl<'v, U> PyTryInto for PyAny<'v> where - U: for<'v> PyTryFrom<'v>, + U: PyTryFrom<'v>, { fn try_into(&self) -> Result<&U, PyDowncastError> { U::try_from(self) @@ -348,9 +348,9 @@ where impl<'v, T> PyTryFrom<'v> for T where - T: PyDowncastImpl + PyTypeInfo + PyNativeType, + T: PyDowncastImpl<'v> + PyTypeInfo + PyNativeType, { - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError> { + fn try_from>>(value: V) -> Result<&'v Self, PyDowncastError> { let value = value.into(); unsafe { if T::is_instance(value) { @@ -361,7 +361,7 @@ where } } - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError> { + fn try_from_exact>>(value: V) -> Result<&'v Self, PyDowncastError> { let value = value.into(); unsafe { if T::is_exact_instance(value) { @@ -373,7 +373,7 @@ where } #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v Self { + unsafe fn try_from_unchecked>>(value: V) -> &'v Self { Self::unchecked_downcast(value.into()) } } @@ -382,7 +382,7 @@ impl<'v, T> PyTryFrom<'v> for PyCell where T: 'v + PyClass, { - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError> { + fn try_from>>(value: V) -> Result<&'v Self, PyDowncastError> { let value = value.into(); unsafe { if T::is_instance(value) { @@ -392,7 +392,7 @@ where } } } - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError> { + fn try_from_exact>>(value: V) -> Result<&'v Self, PyDowncastError> { let value = value.into(); unsafe { if T::is_exact_instance(value) { @@ -403,7 +403,7 @@ where } } #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v Self { + unsafe fn try_from_unchecked>>(value: V) -> &'v Self { Self::unchecked_downcast(value.into()) } } diff --git a/src/err.rs b/src/err.rs index 2cdfcac32c2..54df0c1daaf 100644 --- a/src/err.rs +++ b/src/err.rs @@ -37,7 +37,7 @@ impl PyErrValue { /// Represents a Python exception that was raised. pub struct PyErr { /// The type of the exception. This should be either a `PyClass` or a `PyType`. - pub ptype: Py, + pub ptype: Py>, /// The value of the exception. /// diff --git a/src/exceptions.rs b/src/exceptions.rs index 4d7d476840d..11bae0b8616 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -89,7 +89,7 @@ macro_rules! import_exception { macro_rules! import_exception_type_object { ($module: expr, $name: ident) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType> { + fn type_object(py: $crate::Python) -> &$crate::types::PyType { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -111,7 +111,7 @@ macro_rules! import_exception_type_object { } }); - unsafe { $crate::Py::from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } + unsafe { py.from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } } } }; @@ -173,7 +173,7 @@ macro_rules! create_exception { macro_rules! create_exception_type_object { ($module: ident, $name: ident, $base: ty) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType> { + fn type_object(py: $crate::Python) -> &$crate::types::PyType { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -186,7 +186,7 @@ macro_rules! create_exception_type_object { ) }); - unsafe { $crate::Py::from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } + unsafe { py.from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } } } }; @@ -215,8 +215,8 @@ macro_rules! impl_native_exception ( } } unsafe impl PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType> { - unsafe { $crate::Py::from_borrowed_ptr(ffi::$exc_name) } + fn type_object(py: Python) -> &$crate::types::PyType { + unsafe { py.from_borrowed_ptr(ffi::$exc_name) } } } ); @@ -291,7 +291,7 @@ impl UnicodeDecodeError { input: &[u8], range: ops::Range, reason: &CStr, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { unsafe { let input: &[c_char] = &*(input as *const [u8] as *const [c_char]); py.from_owned_ptr_or_err(ffi::PyUnicodeDecodeError_Create( @@ -310,7 +310,7 @@ impl UnicodeDecodeError { py: Python<'p>, input: &[u8], err: std::str::Utf8Error, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { let pos = err.valid_up_to(); UnicodeDecodeError::new_err( py, diff --git a/src/instance.rs b/src/instance.rs index 8afaa6f2dbb..5986e70559d 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -35,7 +35,7 @@ pub unsafe trait PyNativeType: Sized { /// specified type information. #[derive(Debug)] #[repr(transparent)] -pub struct Py(NonNull, PhantomData); +pub struct Py(NonNull, PhantomData); unsafe impl Send for Py {} @@ -164,18 +164,19 @@ impl Py { /// let py = gil.python(); /// assert_eq!(obj.as_ref(py).len().unwrap(), 0); // PyAny implements ObjectProtocol /// ``` -pub trait AsPyRef: Sized { - type Target; +pub trait AsPyRef<'p>: Sized { + type Target: 'p; /// Return reference to object. - fn as_ref<'p>(&'p self, py: Python<'p>) -> &'p Self::Target; + fn as_ref(&self, py: Python<'p>) -> &Self::Target; } -impl AsPyRef for Py +impl<'p, T> AsPyRef<'p> for Py where T: PyTypeInfo, + T::AsRefTarget: 'p, { type Target = T::AsRefTarget; - fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p Self::Target { + fn as_ref(&self, _py: Python<'p>) -> &Self::Target { let any = self as *const Py as *const PyAny; unsafe { PyDowncastImpl::unchecked_downcast(&*any) } } diff --git a/src/marshal.rs b/src/marshal.rs index d0c7350b912..104db45c74f 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -35,7 +35,7 @@ pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyR } /// Deserialize an object from bytes using the Python built-in marshal module. -pub fn loads<'a, B>(py: Python<'a>, data: &B) -> PyResult<&'a PyAny> +pub fn loads<'a, B>(py: Python<'a>, data: &B) -> PyResult> where B: AsRef<[u8]> + ?Sized, { diff --git a/src/object.rs b/src/object.rs index 642c94c48c4..7fdfbaa4021 100644 --- a/src/object.rs +++ b/src/object.rs @@ -265,9 +265,9 @@ impl PyObject { } } -impl AsPyRef for PyObject { - type Target = PyAny; - fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p PyAny { +impl<'p> AsPyRef<'p> for PyObject { + type Target = PyAny<'p>; + fn as_ref(&self, _py: Python<'p>) -> &PyAny<'p> { unsafe { &*(self as *const _ as *const PyAny) } } } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 04a70d4bada..b62330aa3d5 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -199,7 +199,7 @@ pub trait ObjectProtocol { fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where D: PyTryFrom<'a>, - &'a PyAny: std::convert::From<&'a Self>; + Self: AsRef>; /// Extracts some type from the Python object. /// @@ -207,7 +207,7 @@ pub trait ObjectProtocol { fn extract<'a, D>(&'a self) -> PyResult where D: FromPyObject<'a>, - &'a PyAny: std::convert::From<&'a Self>; + Self: AsRef>; /// Returns the reference count for the Python object. fn get_refcnt(&self) -> isize; @@ -468,7 +468,7 @@ where fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where D: PyTryFrom<'a>, - &'a PyAny: std::convert::From<&'a Self>, + Self: AsRef>, { D::try_from(self) } @@ -476,7 +476,7 @@ where fn extract<'a, D>(&'a self) -> PyResult where D: FromPyObject<'a>, - &'a PyAny: std::convert::From<&'a T>, + Self: AsRef>, { FromPyObject::extract(self.into()) } diff --git a/src/pycell.rs b/src/pycell.rs index 82dcf9bae18..28f12b916a8 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -360,8 +360,8 @@ unsafe impl PyLayout for PyCell { } } -unsafe impl PyDowncastImpl for PyCell { - unsafe fn unchecked_downcast(obj: &PyAny) -> &Self { +unsafe impl<'py, T: PyClass> PyDowncastImpl<'py> for PyCell { + unsafe fn unchecked_downcast<'a>(obj: &'a PyAny) -> &'a Self { &*(obj.as_ptr() as *const Self) } private_impl! {} diff --git a/src/python.rs b/src/python.rs index 67cf22eab88..452c461061b 100644 --- a/src/python.rs +++ b/src/python.rs @@ -163,7 +163,7 @@ impl<'p> Python<'p> { code: &str, globals: Option<&PyDict>, locals: Option<&PyDict>, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { self.run_code(code, ffi::Py_eval_input, globals, locals) } @@ -216,7 +216,7 @@ impl<'p> Python<'p> { start: c_int, globals: Option<&PyDict>, locals: Option<&PyDict>, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { let code = CString::new(code)?; unsafe { let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _); @@ -242,7 +242,7 @@ impl<'p> Python<'p> { } /// Gets the Python type object for type `T`. - pub fn get_type(self) -> &'p PyType + pub fn get_type(self) -> &'p PyType<'p> where T: PyTypeObject, { @@ -301,7 +301,7 @@ impl<'p> Python<'p> { /// to the specific type. pub unsafe fn cast_as(self, obj: PyObject) -> &'p T where - T: PyDowncastImpl + PyTypeInfo, + T: PyDowncastImpl<'p> + PyTypeInfo, { let obj = gil::register_owned(self, obj.into_nonnull()); T::unchecked_downcast(obj) @@ -309,7 +309,7 @@ impl<'p> Python<'p> { /// Registers the object pointer in the release pool. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_borrowed_ptr_to_obj(self, ptr: *mut ffi::PyObject) -> &'p PyAny { + pub unsafe fn from_borrowed_ptr_to_obj(self, ptr: *mut ffi::PyObject) -> &'p PyAny<'p> { match NonNull::new(ptr) { Some(p) => gil::register_borrowed(self, p), None => crate::err::panic_after_error(), diff --git a/src/type_object.rs b/src/type_object.rs index 5069de176e0..203c331e15e 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -68,22 +68,22 @@ pub mod type_flags { // `&PyCell` is a pointer of `ffi::PyObject` but `&PyAny` is a pointer of a pointer, // so we need abstraction. // This mismatch eventually should be fixed(e.g., https://github.com/PyO3/pyo3/issues/679). -pub unsafe trait PyDowncastImpl { +pub unsafe trait PyDowncastImpl<'py> { /// Cast `&PyAny` to `&Self` without no type checking. /// /// # Safety /// /// Unless obj is not an instance of a type corresponding to Self, /// this method causes undefined behavior. - unsafe fn unchecked_downcast(obj: &PyAny) -> &Self; + unsafe fn unchecked_downcast<'a>(obj: &'a PyAny<'py>) -> &'a Self; private_decl! {} } -unsafe impl<'py, T> PyDowncastImpl for T +unsafe impl<'py, T> PyDowncastImpl<'py> for T where T: 'py + crate::PyNativeType, { - unsafe fn unchecked_downcast(obj: &PyAny) -> &Self { + unsafe fn unchecked_downcast<'a>(obj: &'a PyAny<'py>) -> &'a Self { &*(obj as *const _ as *const Self) } private_impl! {} @@ -124,7 +124,7 @@ pub unsafe trait PyTypeInfo: Sized { type Initializer: PyObjectInit; /// Utility type to make AsPyRef work - type AsRefTarget: PyDowncastImpl; + type AsRefTarget: for<'py> PyDowncastImpl<'py>; /// PyTypeObject instance for this type. fn type_object() -> &'static ffi::PyTypeObject; @@ -150,15 +150,15 @@ pub unsafe trait PyTypeInfo: Sized { /// See [PyTypeInfo::type_object] pub unsafe trait PyTypeObject { /// Returns the safe abstraction over the type object. - fn type_object() -> Py; + fn type_object(py: Python) -> &PyType; } unsafe impl PyTypeObject for T where T: PyTypeInfo, { - fn type_object() -> Py { - unsafe { Py::from_borrowed_ptr(::type_object() as *const _ as _) } + fn type_object(py: Python) -> &PyType { + unsafe { py.from_borrowed_ptr(::type_object() as *const _ as _) } } } diff --git a/src/types/any.rs b/src/types/any.rs index ee9f47b472d..26fbba9776d 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -1,7 +1,8 @@ use crate::conversion::PyTryFrom; use crate::err::PyDowncastError; -use crate::internal_tricks::Unsendable; -use crate::{ffi, PyObject}; +use crate::ffi; +use std::marker::PhantomData; +use std::ptr::NonNull; /// A Python object with GIL lifetime /// @@ -28,9 +29,9 @@ use crate::{ffi, PyObject}; /// assert!(any.downcast::().is_err()); /// ``` #[repr(transparent)] -pub struct PyAny(PyObject, Unsendable); -unsafe impl crate::type_object::PyLayout for ffi::PyObject {} -impl crate::type_object::PySizedLayout for ffi::PyObject {} +pub struct PyAny<'a>(NonNull, PhantomData<&'a ffi::PyObject>); +unsafe impl crate::type_object::PyLayout> for ffi::PyObject {} +impl crate::type_object::PySizedLayout> for ffi::PyObject {} pyobject_native_type_named!(PyAny); pyobject_native_type_convert!( PyAny, diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 0702b995c7f..70a9056d8b0 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -7,7 +7,7 @@ use crate::{ /// Represents a Python `bool`. #[repr(transparent)] -pub struct PyBool(PyObject, Unsendable); +pub struct PyBool<'a>(PyAny<'a>); pyobject_native_type!(PyBool, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check); diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 293eabff09b..1946a30ec15 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -27,7 +27,7 @@ use crate::ffi::{ }; use crate::internal_tricks::Unsendable; use crate::object::PyObject; -use crate::types::PyTuple; +use crate::types::{PyAny, PyTuple}; use crate::AsPyPointer; use crate::Python; use crate::ToPyObject; @@ -66,7 +66,7 @@ pub trait PyTimeAccess { } /// Bindings around `datetime.date` -pub struct PyDate(PyObject, Unsendable); +pub struct PyDate<'a>(PyAny<'a>); pyobject_native_type!( PyDate, crate::ffi::PyDateTime_Date, @@ -122,7 +122,7 @@ impl PyDateAccess for PyDate { } /// Bindings for `datetime.datetime` -pub struct PyDateTime(PyObject, Unsendable); +pub struct PyDateTime<'a>(PyAny<'a>); pyobject_native_type!( PyDateTime, crate::ffi::PyDateTime_DateTime, @@ -142,7 +142,7 @@ impl PyDateTime { second: u8, microsecond: u32, tzinfo: Option<&PyObject>, - ) -> PyResult<&'p PyDateTime> { + ) -> PyResult> { unsafe { let ptr = (PyDateTimeAPI.DateTime_FromDateAndTime)( year, @@ -166,7 +166,7 @@ impl PyDateTime { py: Python<'p>, timestamp: f64, time_zone_info: Option<&PyTzInfo>, - ) -> PyResult<&'p PyDateTime> { + ) -> PyResult> { let timestamp: PyObject = timestamp.to_object(py); let time_zone_info: PyObject = match time_zone_info { @@ -232,7 +232,7 @@ impl PyTimeAccess for PyDateTime { } /// Bindings for `datetime.time` -pub struct PyTime(PyObject, Unsendable); +pub struct PyTime<'a>(PyAny<'a>); pyobject_native_type!( PyTime, crate::ffi::PyDateTime_Time, @@ -249,7 +249,7 @@ impl PyTime { second: u8, microsecond: u32, tzinfo: Option<&PyObject>, - ) -> PyResult<&'p PyTime> { + ) -> PyResult> { unsafe { let ptr = (PyDateTimeAPI.Time_FromTime)( c_int::from(hour), @@ -275,7 +275,7 @@ impl PyTime { microsecond: u32, tzinfo: Option<&PyObject>, fold: bool, - ) -> PyResult<&'p PyTime> { + ) -> PyResult> { unsafe { let ptr = (PyDateTimeAPI.Time_FromTimeAndFold)( c_int::from(hour), @@ -317,7 +317,7 @@ impl PyTimeAccess for PyTime { /// Bindings for `datetime.tzinfo` /// /// This is an abstract base class and should not be constructed directly. -pub struct PyTzInfo(PyObject, Unsendable); +pub struct PyTzInfo<'a>(PyAny<'a>); pyobject_native_type!( PyTzInfo, crate::ffi::PyObject, @@ -327,7 +327,7 @@ pyobject_native_type!( ); /// Bindings for `datetime.timedelta` -pub struct PyDelta(PyObject, Unsendable); +pub struct PyDelta<'a>(PyAny<'a>); pyobject_native_type!( PyDelta, crate::ffi::PyDateTime_Delta, diff --git a/src/types/dict.rs b/src/types/dict.rs index caee04eca77..3593863a4b5 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -179,12 +179,12 @@ impl PyDict { } pub struct PyDictIterator<'py> { - dict: &'py PyAny, + dict: &'py PyAny<'py>, pos: isize, } impl<'py> Iterator for PyDictIterator<'py> { - type Item = (&'py PyAny, &'py PyAny); + type Item = (&'py PyAny<'py>, &'py PyAny<'py>); #[inline] fn next(&mut self) -> Option { @@ -202,7 +202,7 @@ impl<'py> Iterator for PyDictIterator<'py> { } impl<'a> std::iter::IntoIterator for &'a PyDict { - type Item = (&'a PyAny, &'a PyAny); + type Item = (&'a PyAny<'a>, &'a PyAny<'a>); type IntoIter = PyDictIterator<'a>; fn into_iter(self) -> Self::IntoIter { diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 88f5fc78814..11501f72a98 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -25,7 +25,7 @@ use crate::{ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyRes /// # Ok(()) /// # } /// ``` -pub struct PyIterator<'p>(&'p PyAny); +pub struct PyIterator<'p>(PyAny<'p>); impl<'p> PyIterator<'p> { /// Constructs a `PyIterator` from a Python iterator object. @@ -52,7 +52,7 @@ impl<'p> PyIterator<'p> { } impl<'p> Iterator for PyIterator<'p> { - type Item = PyResult<&'p PyAny>; + type Item = PyResult>; /// Retrieves the next item from an iterator. /// diff --git a/src/types/list.rs b/src/types/list.rs index 1ecfa1ff8ff..437010a95a1 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -136,7 +136,7 @@ pub struct PyListIterator<'a> { } impl<'a> Iterator for PyListIterator<'a> { - type Item = &'a PyAny; + type Item = &'a PyAny<'a>; #[inline] fn next(&mut self) -> Option<&'a PyAny> { @@ -151,7 +151,7 @@ impl<'a> Iterator for PyListIterator<'a> { } impl<'a> std::iter::IntoIterator for &'a PyList { - type Item = &'a PyAny; + type Item = &'a PyAny<'a>; type IntoIter = PyListIterator<'a>; fn into_iter(self) -> Self::IntoIter { diff --git a/src/types/mod.rs b/src/types/mod.rs index a6bf3942fee..95f2e65826f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -27,17 +27,17 @@ pub use self::typeobject::PyType; #[macro_export] macro_rules! pyobject_native_type_named ( - ($name: ty $(,$type_param: ident)*) => { - impl<$($type_param,)*> ::std::convert::AsRef<$crate::PyAny> for $name { + ($name: ident $(,$type_param: ident)*) => { + impl<'a, $($type_param,)*> ::std::convert::AsRef<$crate::PyAny<'a>> for $name<'a> { #[inline] - fn as_ref(&self) -> &$crate::PyAny { + fn as_ref(&self) -> &$crate::PyAny<'a> { unsafe{&*(self as *const $name as *const $crate::PyAny)} } } - unsafe impl<$($type_param,)*> $crate::PyNativeType for $name {} + unsafe impl<$($type_param,)*> $crate::PyNativeType for $name<'_> {} - impl<$($type_param,)*> $crate::AsPyPointer for $name { + impl<$($type_param,)*> $crate::AsPyPointer for $name<'_> { /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] fn as_ptr(&self) -> *mut $crate::ffi::PyObject { @@ -45,7 +45,7 @@ macro_rules! pyobject_native_type_named ( } } - impl<$($type_param,)*> PartialEq for $name { + impl<$($type_param,)*> PartialEq for $name<'_> { #[inline] fn eq(&self, o: &$name) -> bool { use $crate::AsPyPointer; @@ -58,14 +58,14 @@ macro_rules! pyobject_native_type_named ( #[macro_export] macro_rules! pyobject_native_type { - ($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name> for $layout {} - impl $crate::type_object::PySizedLayout<$name> for $layout {} - impl $crate::derive_utils::PyBaseTypeUtils for $name { + ($name: ident, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { + unsafe impl $crate::type_object::PyLayout<$name<'_>> for $layout {} + impl $crate::type_object::PySizedLayout<$name<'_>> for $layout {} + impl $crate::derive_utils::PyBaseTypeUtils for $name<'_> { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; - type LayoutAsBase = $crate::pycell::PyCellBase<$name>; - type BaseNativeType = $name; + type LayoutAsBase = $crate::pycell::PyCellBase; + type BaseNativeType = Self; } pyobject_native_type_named!($name $(,$type_param)*); pyobject_native_type_convert!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); @@ -120,11 +120,11 @@ macro_rules! pyobject_native_type_extract { #[macro_export] macro_rules! pyobject_native_type_convert( - ($name: ty, $layout: path, $typeobject: expr, + ($name: ident, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl<$($type_param,)*> $crate::type_object::PyTypeInfo for $name { + unsafe impl<'a, $($type_param,)*> $crate::type_object::PyTypeInfo for $name<'a> { type Type = (); - type BaseType = $crate::PyAny; + type BaseType = $crate::PyAny<'a>; type Layout = $layout; type BaseLayout = ffi::PyObject; type Initializer = $crate::pyclass_init::PyNativeTypeInitializer; diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 71f9200089d..7063ce8dab1 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -14,7 +14,7 @@ use crate::{FromPyObject, PyTryFrom, ToBorrowedObject}; /// Represents a reference to a Python object supporting the sequence protocol. #[repr(transparent)] -pub struct PySequence(PyObject, Unsendable); +pub struct PySequence<'a>(PyAny<'a>); pyobject_native_type_named!(PySequence); pyobject_native_type_extract!(PySequence); @@ -360,8 +360,8 @@ where Ok(()) } -impl<'v> PyTryFrom<'v> for PySequence { - fn try_from>(value: V) -> Result<&'v PySequence, PyDowncastError> { +impl<'v> PyTryFrom<'v> for PySequence<'v> { + fn try_from>>(value: V) -> Result<&'v PySequence<'v>, PyDowncastError> { let value = value.into(); unsafe { if ffi::PySequence_Check(value.as_ptr()) != 0 { @@ -372,12 +372,12 @@ impl<'v> PyTryFrom<'v> for PySequence { } } - fn try_from_exact>(value: V) -> Result<&'v PySequence, PyDowncastError> { + fn try_from_exact>>(value: V) -> Result<&'v PySequence<'v>, PyDowncastError> { ::try_from(value) } #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v PySequence { + unsafe fn try_from_unchecked>>(value: V) -> &'v PySequence<'v> { let ptr = value.into() as *const _ as *const PySequence; &*ptr } diff --git a/src/types/set.rs b/src/types/set.rs index 40f8dadd3be..b7f2745b223 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -122,13 +122,13 @@ impl PySet { #[cfg(not(Py_LIMITED_API))] pub struct PySetIterator<'py> { - set: &'py super::PyAny, + set: PyAny<'py>, pos: isize, } #[cfg(not(Py_LIMITED_API))] impl<'py> Iterator for PySetIterator<'py> { - type Item = &'py super::PyAny; + type Item = &'py PyAny<'py>; #[inline] fn next(&mut self) -> Option { @@ -146,7 +146,7 @@ impl<'py> Iterator for PySetIterator<'py> { #[cfg(not(Py_LIMITED_API))] impl<'a> std::iter::IntoIterator for &'a PySet { - type Item = &'a PyAny; + type Item = &'a PyAny<'a>; type IntoIter = PySetIterator<'a>; fn into_iter(self) -> Self::IntoIter { @@ -288,7 +288,7 @@ impl PyFrozenSet { #[cfg(not(Py_LIMITED_API))] impl<'a> std::iter::IntoIterator for &'a PyFrozenSet { - type Item = &'a PyAny; + type Item = &'a PyAny<'a>; type IntoIter = PySetIterator<'a>; fn into_iter(self) -> Self::IntoIter { diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 3466b39a056..b692b11dbba 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -109,7 +109,7 @@ pub struct PyTupleIterator<'a> { } impl<'a> Iterator for PyTupleIterator<'a> { - type Item = &'a PyAny; + type Item = &'a PyAny<'a>; #[inline] fn next(&mut self) -> Option<&'a PyAny> { @@ -124,7 +124,7 @@ impl<'a> Iterator for PyTupleIterator<'a> { } impl<'a> IntoIterator for &'a PyTuple { - type Item = &'a PyAny; + type Item = &'a PyAny<'a>; type IntoIter = PyTupleIterator<'a>; fn into_iter(self) -> Self::IntoIter { diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 5525bec3c3b..d6da963ebd1 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -8,6 +8,7 @@ use crate::instance::{Py, PyNativeType}; use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::type_object::PyTypeObject; +use crate::types::PyAny; use crate::AsPyPointer; use crate::Python; use std::borrow::Cow; @@ -15,15 +16,15 @@ use std::ffi::CStr; /// Represents a reference to a Python `type object`. #[repr(transparent)] -pub struct PyType(PyObject, Unsendable); +pub struct PyType<'a>(PyAny<'a>); pyobject_native_var_type!(PyType, ffi::PyType_Type, ffi::PyType_Check); -impl PyType { +impl<'py> PyType<'py> { /// Creates a new type object. #[inline] - pub fn new() -> Py { - T::type_object() + pub fn new(py: Python<'py>) -> Self { + T::type_object(py).clone() } /// Retrieves the underlying FFI pointer associated with this Python object. From 64ccdb8cd9b4db597f00d9eaf418e4e511db66a0 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 29 Apr 2020 08:50:21 +0100 Subject: [PATCH 02/11] Before going too far down PyTypeInfo change --- src/class/sequence.rs | 2 +- src/conversion.rs | 77 ++++++-------------- src/derive_utils.rs | 12 ++-- src/err.rs | 3 +- src/gil.rs | 6 +- src/instance.rs | 26 ++----- src/marshal.rs | 8 +-- src/object.rs | 21 ++++-- src/objectprotocol.rs | 62 ++++++++--------- src/pycell.rs | 149 +++++++++++++++++++++++---------------- src/pyclass.rs | 21 +++--- src/pyclass_init.rs | 7 +- src/python.rs | 25 ++++--- src/type_object.rs | 30 ++++---- src/types/any.rs | 64 +++++++++++++++-- src/types/boolobject.rs | 6 +- src/types/bytearray.rs | 9 +-- src/types/bytes.rs | 10 +-- src/types/complex.rs | 39 ++++++----- src/types/datetime.rs | 62 ++++++++--------- src/types/dict.rs | 48 ++++++------- src/types/floatob.rs | 6 +- src/types/iterator.rs | 3 +- src/types/list.rs | 12 ++-- src/types/mod.rs | 151 ++++++++++++++++++++++++++-------------- src/types/module.rs | 32 ++++----- src/types/num.rs | 2 +- src/types/sequence.rs | 60 ++++++++++------ src/types/set.rs | 40 +++++------ src/types/slice.rs | 7 +- src/types/string.rs | 8 +-- src/types/tuple.rs | 30 ++++---- src/types/typeobject.rs | 12 ++-- 33 files changed, 576 insertions(+), 474 deletions(-) diff --git a/src/class/sequence.rs b/src/class/sequence.rs index 4d31ce57d38..8472729db02 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -12,7 +12,7 @@ use std::os::raw::c_int; /// Sequence interface #[allow(unused_variables)] -pub trait PySequenceProtocol<'p>: PyClass + Sized { +pub trait PySequenceProtocol<'p>: PyClass<'p> + Sized { fn __len__(&'p self) -> Self::Result where Self: PySequenceLenProtocol<'p>, diff --git a/src/conversion.rs b/src/conversion.rs index 76a48971404..a330fab18ac 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -252,7 +252,7 @@ where } } -impl<'a, T> FromPyObject<'a> for &'a PyCell +impl<'a, T> FromPyObject<'a> for &'a PyCell<'a, T> where T: PyClass, { @@ -311,16 +311,16 @@ where /// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`. /// /// This trait is similar to `std::convert::TryFrom` -pub trait PyTryFrom<'v>: Sized + PyDowncastImpl<'v> { +pub trait PyTryFrom<'py>: Sized + PyDowncastImpl<'py> { /// Cast from a concrete Python object type to PyObject. - fn try_from>>(value: V) -> Result<&'v Self, PyDowncastError>; + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError>; /// Cast from a concrete Python object type to PyObject. With exact type check. - fn try_from_exact>>(value: V) -> Result<&'v Self, PyDowncastError>; + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError>; /// Cast a PyAny to a specific type of PyObject. The caller must /// have already verified the reference is for this type. - unsafe fn try_from_unchecked>>(value: V) -> &'v Self; + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a Self; } /// Trait implemented by Python object types that allow a checked downcast. @@ -346,12 +346,11 @@ where } } -impl<'v, T> PyTryFrom<'v> for T +impl<'py, T> PyTryFrom<'py> for T where - T: PyDowncastImpl<'v> + PyTypeInfo + PyNativeType, + T: PyDowncastImpl<'py> + PyTypeInfo + PyNativeType<'py>, { - fn try_from>>(value: V) -> Result<&'v Self, PyDowncastError> { - let value = value.into(); + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { if T::is_instance(value) { Ok(Self::try_from_unchecked(value)) @@ -361,8 +360,7 @@ where } } - fn try_from_exact>>(value: V) -> Result<&'v Self, PyDowncastError> { - let value = value.into(); + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { if T::is_exact_instance(value) { Ok(Self::try_from_unchecked(value)) @@ -373,16 +371,16 @@ where } #[inline] - unsafe fn try_from_unchecked>>(value: V) -> &'v Self { + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a Self { Self::unchecked_downcast(value.into()) } } -impl<'v, T> PyTryFrom<'v> for PyCell +impl<'py, T> PyTryFrom<'py> for PyCell<'py, T> where - T: 'v + PyClass, + T: 'py + PyClass, { - fn try_from>>(value: V) -> Result<&'v Self, PyDowncastError> { + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { let value = value.into(); unsafe { if T::is_instance(value) { @@ -392,8 +390,7 @@ where } } } - fn try_from_exact>>(value: V) -> Result<&'v Self, PyDowncastError> { - let value = value.into(); + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { if T::is_exact_instance(value) { Ok(Self::try_from_unchecked(value)) @@ -403,31 +400,31 @@ where } } #[inline] - unsafe fn try_from_unchecked>>(value: V) -> &'v Self { - Self::unchecked_downcast(value.into()) + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a Self { + Self::unchecked_downcast(value) } } /// Converts `()` to an empty Python tuple. -impl FromPy<()> for Py { - fn from_py(_: (), py: Python) -> Py { +impl FromPy<()> for Py> { + fn from_py(_: (), py: Python) -> Py> { Py::from_py(PyTuple::empty(py), py) } } /// Raw level conversion between `*mut ffi::PyObject` and PyO3 types. pub unsafe trait FromPyPointer<'p>: Sized { - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self>; - unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self { + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option; + unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { match Self::from_owned_ptr_or_opt(py, ptr) { Some(s) => s, None => err::panic_after_error(), } } - unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self { + unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { Self::from_owned_ptr_or_panic(py, ptr) } - unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult<&'p Self> { + unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult { match Self::from_owned_ptr_or_opt(py, ptr) { Some(s) => Ok(s), None => Err(err::PyErr::fetch(py)), @@ -455,36 +452,6 @@ pub unsafe trait FromPyPointer<'p>: Sized { } } -unsafe impl<'p, T> FromPyPointer<'p> for T -where - T: 'p + crate::PyNativeType, -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_owned(py, p))) - } - unsafe fn from_borrowed_ptr_or_opt( - py: Python<'p>, - ptr: *mut ffi::PyObject, - ) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p))) - } -} - -unsafe impl<'p, T> FromPyPointer<'p> for PyCell -where - T: PyClass, -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyCell)) - } - unsafe fn from_borrowed_ptr_or_opt( - py: Python<'p>, - ptr: *mut ffi::PyObject, - ) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell)) - } -} - #[cfg(test)] mod test { use crate::types::PyList; diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 76a05182b9d..61d3f637af7 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -32,15 +32,15 @@ pub struct ParamDescription { /// * kwargs: Keyword arguments /// * output: Output array that receives the arguments. /// Must have same length as `params` and must be initialized to `None`. -pub fn parse_fn_args<'p>( +pub fn parse_fn_args<'a, 'py>( fname: Option<&str>, params: &[ParamDescription], - args: &'p PyTuple, - kwargs: Option<&'p PyDict>, + args: &'a PyTuple<'py>, + kwargs: Option<&'a PyDict<'py>>, accept_args: bool, accept_kwargs: bool, - output: &mut [Option<&'p PyAny>], -) -> PyResult<(&'p PyTuple, Option<&'p PyDict>)> { + output: &mut [Option<&'a PyAny<'py>>], +) -> PyResult<(&'a PyTuple<'py>, Option<&'a PyDict<'py>>)> { let nargs = args.len(); let mut used_args = 0; macro_rules! raise_error { @@ -263,7 +263,7 @@ pub trait TryFromPyCell<'a, T: PyClass>: Sized { impl<'a, T, R> TryFromPyCell<'a, T> for R where T: 'a + PyClass, - R: std::convert::TryFrom<&'a PyCell>, + R: std::convert::TryFrom<&'a PyCell<'a, T>>, R::Error: Into, { type Error = R::Error; diff --git a/src/err.rs b/src/err.rs index 54df0c1daaf..275fcb8a1ed 100644 --- a/src/err.rs +++ b/src/err.rs @@ -3,6 +3,7 @@ use crate::type_object::PyTypeObject; use crate::types::PyType; use crate::{exceptions, ffi}; +use crate::instance::PyNativeType; use crate::{ AsPyPointer, FromPy, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToBorrowedObject, ToPyObject, @@ -151,7 +152,7 @@ impl PyErr { } } else { PyErr { - ptype: exceptions::TypeError::type_object(), + ptype: exceptions::TypeError::type_object(obj.py()).into(), pvalue: PyErrValue::ToObject(Box::new("exceptions must derive from BaseException")), ptraceback: None, } diff --git a/src/gil.rs b/src/gil.rs index 72ff1781adc..9ff43e43f49 100644 --- a/src/gil.rs +++ b/src/gil.rs @@ -394,7 +394,7 @@ mod test { { let gil = Python::acquire_gil(); let py = gil.python(); - let _ = gil::register_owned(py, obj.into_nonnull()); + let _ = gil::register_owned(py, obj.into_non_null()); assert_eq!(ffi::Py_REFCNT(obj_ptr), 2); assert_eq!(p.owned.len(), 1); @@ -423,14 +423,14 @@ mod test { let _pool = GILPool::new(); assert_eq!(p.owned.len(), 0); - let _ = gil::register_owned(py, obj.into_nonnull()); + let _ = gil::register_owned(py, obj.into_non_null()); assert_eq!(p.owned.len(), 1); assert_eq!(ffi::Py_REFCNT(obj_ptr), 2); { let _pool = GILPool::new(); let obj = get_object(); - let _ = gil::register_owned(py, obj.into_nonnull()); + let _ = gil::register_owned(py, obj.into_non_null()); assert_eq!(p.owned.len(), 2); } assert_eq!(p.owned.len(), 1); diff --git a/src/instance.rs b/src/instance.rs index 5986e70559d..6fa644b6e8b 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -17,8 +17,8 @@ use std::ptr::NonNull; /// PyO3 is designed in a way that all references to those types are bound /// to the GIL, which is why you can get a token from all references of those /// types. -pub unsafe trait PyNativeType: Sized { - fn py(&self) -> Python { +pub unsafe trait PyNativeType<'p>: Sized { + fn py(&self) -> Python<'p> { unsafe { Python::assume_gil_acquired() } } } @@ -218,7 +218,7 @@ impl IntoPyPointer for Py { // Native types `&T` can be converted to `Py` impl<'a, T> std::convert::From<&'a T> for Py where - T: AsPyPointer + PyNativeType, + T: AsPyPointer + PyNativeType<'a>, { fn from(obj: &'a T) -> Self { unsafe { Py::from_borrowed_ptr(obj.as_ptr()) } @@ -226,7 +226,7 @@ where } // `&PyCell` can be converted to `Py` -impl<'a, T> std::convert::From<&PyCell> for Py +impl<'a, T> std::convert::From<&PyCell<'_, T>> for Py where T: PyClass, { @@ -276,24 +276,6 @@ impl std::convert::From> for PyObject { } } -impl<'a, T> std::convert::From<&'a T> for PyObject -where - T: AsPyPointer, -{ - fn from(ob: &'a T) -> Self { - unsafe { Py::::from_borrowed_ptr(ob.as_ptr()) }.into() - } -} - -impl<'a, T> std::convert::From<&'a mut T> for PyObject -where - T: AsPyPointer, -{ - fn from(ob: &'a mut T) -> Self { - unsafe { Py::::from_borrowed_ptr(ob.as_ptr()) }.into() - } -} - impl<'a, T> FromPyObject<'a> for Py where T: PyTypeInfo, diff --git a/src/marshal.rs b/src/marshal.rs index 104db45c74f..a99ec974f79 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -27,7 +27,7 @@ pub const VERSION: i32 = 4; /// /// let bytes = marshal::dumps(py, dict, marshal::VERSION); /// ``` -pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyResult<&'a PyBytes> { +pub fn dumps<'py>(py: Python<'py>, object: &impl AsPyPointer, version: i32) -> PyResult> { unsafe { let bytes = ffi::PyMarshal_WriteObjectToString(object.as_ptr(), version as c_int); FromPyPointer::from_owned_ptr_or_err(py, bytes) @@ -35,7 +35,7 @@ pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyR } /// Deserialize an object from bytes using the Python built-in marshal module. -pub fn loads<'a, B>(py: Python<'a>, data: &B) -> PyResult> +pub fn loads<'py, B>(py: Python<'py>, data: &B) -> PyResult> where B: AsRef<[u8]> + ?Sized, { @@ -65,9 +65,9 @@ mod test { let bytes = dumps(py, dict, VERSION) .expect("marshalling failed") .as_bytes(); - let deserialzed = loads(py, bytes).expect("unmarshalling failed"); + let deserialized = loads(py, bytes).expect("unmarshalling failed"); - assert!(equal(py, dict, deserialzed)); + assert!(equal(py, dict, &deserialized)); } fn equal(_py: Python, a: &impl AsPyPointer, b: &impl AsPyPointer) -> bool { diff --git a/src/object.rs b/src/object.rs index 7fdfbaa4021..1d34a3bea8d 100644 --- a/src/object.rs +++ b/src/object.rs @@ -28,11 +28,11 @@ unsafe impl Sync for PyObject {} impl PyObject { /// For internal conversions - pub(crate) unsafe fn from_not_null(ptr: NonNull) -> PyObject { + pub(crate) unsafe fn from_non_null(ptr: NonNull) -> PyObject { PyObject(ptr) } - pub(crate) unsafe fn into_nonnull(self) -> NonNull { + pub(crate) unsafe fn into_non_null(self) -> NonNull { let res = self.0; std::mem::forget(self); // Avoid Drop res @@ -191,7 +191,7 @@ impl PyObject { pub fn call( &self, py: Python, - args: impl IntoPy>, + args: impl IntoPy>>, kwargs: Option<&PyDict>, ) -> PyResult { let args = args.into_py(py).into_ptr(); @@ -209,7 +209,7 @@ impl PyObject { /// Calls the object with only positional arguments. /// /// This is equivalent to the Python expression `self(*args)`. - pub fn call1(&self, py: Python, args: impl IntoPy>) -> PyResult { + pub fn call1(&self, py: Python, args: impl IntoPy>>) -> PyResult { self.call(py, args, None) } @@ -227,7 +227,7 @@ impl PyObject { &self, py: Python, name: &str, - args: impl IntoPy>, + args: impl IntoPy>>, kwargs: Option<&PyDict>, ) -> PyResult { name.with_borrowed_ptr(py, |name| unsafe { @@ -252,7 +252,7 @@ impl PyObject { &self, py: Python, name: &str, - args: impl IntoPy>, + args: impl IntoPy>>, ) -> PyResult { self.call_method(py, name, args, None) } @@ -265,6 +265,15 @@ impl PyObject { } } +impl<'a, T> std::convert::From<&'a T> for PyObject +where + T: AsPyPointer, +{ + fn from(ob: &'a T) -> Self { + unsafe { PyObject::from_not_null(NonNull::new(ob.as_ptr()).expect("Null ptr")) } + } +} + impl<'p> AsPyRef<'p> for PyObject { type Target = PyAny<'p>; fn as_ref(&self, _py: Python<'p>) -> &PyAny<'p> { diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index b62330aa3d5..8fe17e29d3d 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering; use std::os::raw::c_int; /// Python object model helper methods -pub trait ObjectProtocol { +pub trait ObjectProtocol<'py> { /// Determines whether this object has the given attribute. /// /// This is equivalent to the Python expression `hasattr(self, attr_name)`. @@ -23,7 +23,7 @@ pub trait ObjectProtocol { /// Retrieves an attribute value. /// /// This is equivalent to the Python expression `self.attr_name`. - fn getattr(&self, attr_name: N) -> PyResult<&PyAny> + fn getattr(&self, attr_name: N) -> PyResult> where N: ToPyObject; @@ -76,12 +76,12 @@ pub trait ObjectProtocol { /// Computes the "repr" representation of self. /// /// This is equivalent to the Python expression `repr(self)`. - fn repr(&self) -> PyResult<&PyString>; + fn repr(&self) -> PyResult>; /// Computes the "str" representation of self. /// /// This is equivalent to the Python expression `str(self)`. - fn str(&self) -> PyResult<&PyString>; + fn str(&self) -> PyResult>; /// Determines whether this object is callable. fn is_callable(&self) -> bool; @@ -89,17 +89,17 @@ pub trait ObjectProtocol { /// Calls the object. /// /// This is equivalent to the Python expression `self(*args, **kwargs)`. - fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult<&PyAny>; + fn call(&self, args: impl IntoPy>>, kwargs: Option<&PyDict>) -> PyResult>; /// Calls the object with only positional arguments. /// /// This is equivalent to the Python expression `self(*args)`. - fn call1(&self, args: impl IntoPy>) -> PyResult<&PyAny>; + fn call1(&self, args: impl IntoPy>>) -> PyResult>; /// Calls the object without arguments. /// /// This is equivalent to the Python expression `self()`. - fn call0(&self) -> PyResult<&PyAny>; + fn call0(&self) -> PyResult>; /// Calls a method on the object. /// @@ -120,19 +120,19 @@ pub trait ObjectProtocol { fn call_method( &self, name: &str, - args: impl IntoPy>, + args: impl IntoPy>>, kwargs: Option<&PyDict>, - ) -> PyResult<&PyAny>; + ) -> PyResult>; /// Calls a method on the object with only positional arguments. /// /// This is equivalent to the Python expression `self.name(*args)`. - fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyAny>; + fn call_method1(&self, name: &str, args: impl IntoPy>>) -> PyResult>; /// Calls a method on the object without arguments. /// /// This is equivalent to the Python expression `self.name()`. - fn call_method0(&self, name: &str) -> PyResult<&PyAny>; + fn call_method0(&self, name: &str) -> PyResult>; /// Retrieves the hash code of the object. /// @@ -162,7 +162,7 @@ pub trait ObjectProtocol { /// Gets an item from the collections. /// /// This is equivalent to the Python expression `self[key]`. - fn get_item(&self, key: K) -> PyResult<&PyAny> + fn get_item(&self, key: K) -> PyResult> where K: ToBorrowedObject; @@ -185,10 +185,10 @@ pub trait ObjectProtocol { /// /// This is typically a new iterator but if the argument is an iterator, /// this returns itself. - fn iter(&self) -> PyResult; + fn iter(&self) -> PyResult>; /// Returns the Python type object for this object's type. - fn get_type(&self) -> &PyType; + fn get_type(&self) -> &PyType<'py>; /// Returns the Python type pointer for this object. fn get_type_ptr(&self) -> *mut ffi::PyTypeObject; @@ -217,9 +217,9 @@ pub trait ObjectProtocol { fn None(&self) -> PyObject; } -impl ObjectProtocol for T +impl<'py, T> ObjectProtocol<'py> for T where - T: PyNativeType + AsPyPointer, + T: PyNativeType<'py> + AsPyPointer, { fn hasattr(&self, attr_name: N) -> PyResult where @@ -230,7 +230,7 @@ where }) } - fn getattr(&self, attr_name: N) -> PyResult<&PyAny> + fn getattr(&self, attr_name: N) -> PyResult> where N: ToPyObject, { @@ -315,14 +315,14 @@ where } } - fn repr(&self) -> PyResult<&PyString> { + fn repr(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PyObject_Repr(self.as_ptr())) } } - fn str(&self) -> PyResult<&PyString> { + fn str(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PyObject_Str(self.as_ptr())) @@ -333,7 +333,7 @@ where unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 } } - fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult<&PyAny> { + fn call(&self, args: impl IntoPy>>, kwargs: Option<&PyDict>) -> PyResult> { let args = args.into_py(self.py()).into_ptr(); let kwargs = kwargs.into_ptr(); let result = unsafe { @@ -347,20 +347,20 @@ where result } - fn call0(&self) -> PyResult<&PyAny> { + fn call0(&self) -> PyResult> { self.call((), None) } - fn call1(&self, args: impl IntoPy>) -> PyResult<&PyAny> { + fn call1(&self, args: impl IntoPy>>) -> PyResult> { self.call(args, None) } fn call_method( &self, name: &str, - args: impl IntoPy>, + args: impl IntoPy>>, kwargs: Option<&PyDict>, - ) -> PyResult<&PyAny> { + ) -> PyResult> { name.with_borrowed_ptr(self.py(), |name| unsafe { let py = self.py(); let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name); @@ -378,11 +378,11 @@ where }) } - fn call_method0(&self, name: &str) -> PyResult<&PyAny> { + fn call_method0(&self, name: &str) -> PyResult> { self.call_method(name, (), None) } - fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyAny> { + fn call_method1(&self, name: &str, args: impl IntoPy>>) -> PyResult> { self.call_method(name, args, None) } @@ -421,7 +421,7 @@ where self.len().map(|l| l == 0) } - fn get_item(&self, key: K) -> PyResult<&PyAny> + fn get_item(&self, key: K) -> PyResult> where K: ToBorrowedObject, { @@ -452,11 +452,11 @@ where }) } - fn iter(&self) -> PyResult { + fn iter(&self) -> PyResult> { Ok(PyIterator::from_object(self.py(), self)?) } - fn get_type(&self) -> &PyType { + fn get_type(&self) -> &PyType<'py> { unsafe { PyType::from_type_ptr(self.py(), (*self.as_ptr()).ob_type) } } @@ -470,7 +470,7 @@ where D: PyTryFrom<'a>, Self: AsRef>, { - D::try_from(self) + D::try_from(self.as_ref()) } fn extract<'a, D>(&'a self) -> PyResult @@ -478,7 +478,7 @@ where D: FromPyObject<'a>, Self: AsRef>, { - FromPyObject::extract(self.into()) + FromPyObject::extract(self.as_ref()) } fn get_refcnt(&self) -> isize { diff --git a/src/pycell.rs b/src/pycell.rs index 28f12b916a8..6e7f66420ea 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -3,11 +3,13 @@ use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject}; use crate::pyclass_init::PyClassInitializer; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout, PyTypeInfo}; -use crate::{ffi, FromPy, PyAny, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python}; -use std::cell::{Cell, UnsafeCell}; +use crate::{gil, ffi, FromPy, PyAny, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python}; +use std::cell::{Cell, UnsafeCell, RefCell}; use std::fmt; +use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; +use std::ptr::NonNull; /// Base layout of PyCell. /// This is necessary for sharing BorrowFlag between parents and children. @@ -18,25 +20,25 @@ pub struct PyCellBase { borrow_flag: Cell, } -unsafe impl PyLayout for PyCellBase +unsafe impl<'py, T> PyLayout for PyCellBase where - T: PyTypeInfo + PyNativeType, + T: PyTypeInfo + PyNativeType<'py>, T::Layout: PySizedLayout, { const IS_NATIVE_TYPE: bool = true; } // Thes impls ensures `PyCellBase` can be a base type. -impl PySizedLayout for PyCellBase +impl<'py, T> PySizedLayout for PyCellBase where - T: PyTypeInfo + PyNativeType, + T: PyTypeInfo + PyNativeType<'py>, T::Layout: PySizedLayout, { } -unsafe impl PyBorrowFlagLayout for PyCellBase +unsafe impl<'py, T> PyBorrowFlagLayout for PyCellBase where - T: PyTypeInfo + PyNativeType, + T: PyTypeInfo + PyNativeType<'py>, T::Layout: PySizedLayout, { } @@ -89,6 +91,48 @@ impl PyCellInner { unsafe { (*base).borrow_flag.set(flag) } } } +#[repr(C)] +pub struct PyCellLayout { + inner: PyCellInner, + dict: T::Dict, + weakref: T::WeakRef, +} + +impl PyCellLayout { + /// Allocates new PyCell without initilizing value. + /// Requires `T::BaseLayout: PyBorrowFlagLayout` to ensure `self` has a borrow flag. + pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self> + where + T::BaseLayout: PyBorrowFlagLayout, + { + let base = T::alloc(py); + if base.is_null() { + return Err(PyErr::fetch(py)); + } + let base = base as *mut PyCellBase; + (*base).borrow_flag = Cell::new(BorrowFlag::UNUSED); + let self_ = base as *mut Self; + (*self_).dict = T::Dict::new(); + (*self_).weakref = T::WeakRef::new(); + Ok(self_) + } +} + +unsafe impl PyLayout for PyCellLayout { + const IS_NATIVE_TYPE: bool = false; + fn get_super(&mut self) -> Option<&mut T::BaseLayout> { + Some(&mut self.inner.ob_base) + } + unsafe fn py_init(&mut self, value: T) { + self.inner.value = ManuallyDrop::new(UnsafeCell::new(value)); + } + unsafe fn py_drop(&mut self, py: Python) { + ManuallyDrop::drop(&mut self.inner.value); + self.dict.clear_dict(py); + self.weakref.clear_weakrefs(self as *mut _ as _, py); + self.inner.ob_base.py_drop(py); + } +} /// `PyCell` is the container type for [`PyClass`](../pyclass/trait.PyClass.html). /// @@ -152,17 +196,13 @@ impl PyCellInner { /// # let counter = PyCell::new(py, Counter::default()).unwrap(); /// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1"); /// ``` -#[repr(C)] -pub struct PyCell { - inner: PyCellInner, - dict: T::Dict, - weakref: T::WeakRef, -} +#[repr(transparent)] +pub struct PyCell<'py, T: PyClass>(PyAny<'py>, PhantomData>); -impl PyCell { +impl<'py, T: PyClass> PyCell<'py, T> { /// Make new `PyCell` on the Python heap and returns the reference of it. /// - pub fn new(py: Python, value: impl Into>) -> PyResult<&Self> + pub fn new(py: Python<'py>, value: impl Into>) -> PyResult where T::BaseLayout: PyBorrowFlagLayout, { @@ -218,12 +258,13 @@ impl PyCell { /// } /// ``` pub fn try_borrow(&self) -> Result, PyBorrowError> { - let flag = self.inner.get_borrow_flag(); + let inner = self.inner(); + let flag = inner.get_borrow_flag(); if flag == BorrowFlag::HAS_MUTABLE_BORROW { Err(PyBorrowError { _private: () }) } else { - self.inner.set_borrow_flag(flag.increment()); - Ok(PyRef { inner: &self.inner }) + inner.set_borrow_flag(flag.increment()); + Ok(PyRef { inner: &inner }) } } @@ -249,11 +290,12 @@ impl PyCell { /// assert!(c.try_borrow_mut().is_ok()); /// ``` pub fn try_borrow_mut(&self) -> Result, PyBorrowMutError> { - if self.inner.get_borrow_flag() != BorrowFlag::UNUSED { + let inner = self.inner(); + if inner.get_borrow_flag() != BorrowFlag::UNUSED { Err(PyBorrowMutError { _private: () }) } else { - self.inner.set_borrow_flag(BorrowFlag::HAS_MUTABLE_BORROW); - Ok(PyRefMut { inner: &self.inner }) + inner.set_borrow_flag(BorrowFlag::HAS_MUTABLE_BORROW); + Ok(PyRefMut { inner: &inner }) } } @@ -287,10 +329,11 @@ impl PyCell { /// } /// ``` pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> { - if self.inner.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW { + let inner = self.inner(); + if inner.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW { Err(PyBorrowError { _private: () }) } else { - Ok(&*self.inner.value.get()) + Ok(&*inner.value.get()) } } @@ -325,64 +368,50 @@ impl PyCell { std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut()) } - /// Allocates new PyCell without initilizing value. - /// Requires `T::BaseLayout: PyBorrowFlagLayout` to ensure `self` has a borrow flag. - pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self> - where - T::BaseLayout: PyBorrowFlagLayout, - { - let base = T::alloc(py); - if base.is_null() { - return Err(PyErr::fetch(py)); - } - let base = base as *mut PyCellBase; - (*base).borrow_flag = Cell::new(BorrowFlag::UNUSED); - let self_ = base as *mut Self; - (*self_).dict = T::Dict::new(); - (*self_).weakref = T::WeakRef::new(); - Ok(self_) + #[inline] + fn inner(&self) -> &PyCellInner { + unsafe { &*(self.as_ptr() as *const PyCellInner) } } } -unsafe impl PyLayout for PyCell { - const IS_NATIVE_TYPE: bool = false; - fn get_super(&mut self) -> Option<&mut T::BaseLayout> { - Some(&mut self.inner.ob_base) - } - unsafe fn py_init(&mut self, value: T) { - self.inner.value = ManuallyDrop::new(UnsafeCell::new(value)); +unsafe impl<'p, T> FromPyPointer<'p> for PyCell<'p, T> +where + T: PyClass, +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| Self(PyAny::from_not_null(py, p))) } - unsafe fn py_drop(&mut self, py: Python) { - ManuallyDrop::drop(&mut self.inner.value); - self.dict.clear_dict(py); - self.weakref.clear_weakrefs(self.as_ptr(), py); - self.inner.ob_base.py_drop(py); + unsafe fn from_borrowed_ptr_or_opt( + py: Python<'p>, + ptr: *mut ffi::PyObject, + ) -> Option<&'p Self> { + NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell)) } } -unsafe impl<'py, T: PyClass> PyDowncastImpl<'py> for PyCell { +unsafe impl<'py, T: PyClass> PyDowncastImpl<'py> for PyCell<'py, T> { unsafe fn unchecked_downcast<'a>(obj: &'a PyAny) -> &'a Self { &*(obj.as_ptr() as *const Self) } private_impl! {} } -impl AsPyPointer for PyCell { +impl AsPyPointer for PyCell<'_, T> { fn as_ptr(&self) -> *mut ffi::PyObject { self.inner.as_ptr() } } -impl ToPyObject for &PyCell { +impl ToPyObject for &PyCell<'_, T> { fn to_object(&self, py: Python<'_>) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } } } -impl fmt::Debug for PyCell { +impl fmt::Debug for PyCell<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.try_borrow() { - Ok(borrow) => f.debug_struct("RefCell").field("value", &borrow).finish(), + Ok(borrow) => f.debug_struct("PyCell").field("value", &borrow).finish(), Err(_) => { struct BorrowedPlaceholder; impl fmt::Debug for BorrowedPlaceholder { @@ -390,7 +419,7 @@ impl fmt::Debug for PyCell { f.write_str("") } } - f.debug_struct("RefCell") + f.debug_struct("PyCell") .field("value", &BorrowedPlaceholder) .finish() } @@ -530,7 +559,7 @@ impl<'p, T: PyClass> FromPy> for PyObject { } } -impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell> for crate::PyRef<'a, T> { +impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<'_, T>> for crate::PyRef<'a, T> { type Error = PyBorrowError; fn try_from(cell: &'a crate::PyCell) -> Result { cell.try_borrow() @@ -634,7 +663,7 @@ impl<'a, T: PyClass> AsPyPointer for PyRefMut<'a, T> { } } -impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell> for crate::PyRefMut<'a, T> { +impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<'_, T>> for crate::PyRefMut<'a, T> { type Error = PyBorrowMutError; fn try_from(cell: &'a crate::PyCell) -> Result { cell.try_borrow_mut() diff --git a/src/pyclass.rs b/src/pyclass.rs index 4f0f9ec194e..5cc3cd73aa8 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -2,13 +2,14 @@ use crate::class::methods::{PyMethodDefType, PyMethodsProtocol}; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; use crate::type_object::{type_flags, PyLayout}; -use crate::{class, ffi, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python}; +use crate::pycell::PyCellLayout; +use crate::{class, ffi, PyErr, PyNativeType, PyResult, PyTypeInfo, Python}; use std::ffi::CString; use std::os::raw::c_void; use std::ptr; #[inline] -pub(crate) unsafe fn default_alloc() -> *mut ffi::PyObject { +pub(crate) unsafe fn default_alloc PyTypeInfo<'py>>() -> *mut ffi::PyObject { let type_obj = T::type_object(); // if the class derives native types(e.g., PyDict), call special new if T::FLAGS & type_flags::EXTENDED != 0 && T::BaseLayout::IS_NATIVE_TYPE { @@ -22,12 +23,12 @@ pub(crate) unsafe fn default_alloc() -> *mut ffi::PyObject { } /// This trait enables custom alloc/dealloc implementations for `T: PyClass`. -pub trait PyClassAlloc: PyTypeInfo + Sized { +pub trait PyClassAlloc<'py>: PyTypeInfo<'py> + Sized { /// Allocate the actual field for `#[pyclass]`. /// /// # Safety /// This function must return a valid pointer to the Python heap. - unsafe fn alloc(_py: Python) -> *mut Self::Layout { + unsafe fn alloc(_py: Python<'py>) -> *mut Self::Layout { default_alloc::() as _ } @@ -35,7 +36,7 @@ pub trait PyClassAlloc: PyTypeInfo + Sized { /// /// # Safety /// `self_` must be a valid pointer to the Python heap. - unsafe fn dealloc(py: Python, self_: *mut Self::Layout) { + unsafe fn dealloc(py: Python<'py>, self_: *mut Self::Layout) { (*self_).py_drop(py); let obj = self_ as _; if ffi::PyObject_CallFinalizerFromDealloc(obj) < 0 { @@ -70,8 +71,8 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) { /// /// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you don't have to use this trait directly. -pub trait PyClass: - PyTypeInfo> + Sized + PyClassAlloc + PyMethodsProtocol +pub trait PyClass<'py>: + PyTypeInfo<'py, Layout = PyCellLayout> + Sized + PyClassAlloc<'py> + PyMethodsProtocol { /// Specify this class has `#[pyclass(dict)]` or not. type Dict: PyClassDict; @@ -79,7 +80,7 @@ pub trait PyClass: type WeakRef: PyClassWeakRef; /// The closest native ancestor. This is `PyAny` by default, and when you declare /// `#[pyclass(extends=PyDict)]`, it's `PyDict`. - type BaseNativeType: PyTypeInfo + PyNativeType; + type BaseNativeType: PyTypeInfo<'py> + PyNativeType<'static>; } #[cfg(not(Py_LIMITED_API))] @@ -89,7 +90,7 @@ pub(crate) fn initialize_type_object( type_object: &mut ffi::PyTypeObject, ) -> PyResult<()> where - T: PyClass, + T: for<'py> PyClass<'py>, { type_object.tp_doc = match T::DESCRIPTION { // PyPy will segfault if passed only a nul terminator as `tp_doc`, ptr::null() is OK though. @@ -109,7 +110,7 @@ where // dealloc unsafe extern "C" fn tp_dealloc_callback(obj: *mut ffi::PyObject) where - T: PyClassAlloc, + T: for<'py> PyClassAlloc<'py>, { let pool = crate::GILPool::new(); let py = pool.python(); diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index 3be018f241c..70db7227748 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -1,6 +1,7 @@ //! Initialization utilities for `#[pyclass]`. +use crate::pycell::PyCellLayout; use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo}; -use crate::{PyCell, PyClass, PyResult, Python}; +use crate::{PyClass, PyResult, Python}; use std::marker::PhantomData; /// Initializer for Python types. @@ -116,12 +117,12 @@ impl PyClassInitializer { // Create a new PyCell + initialize it #[doc(hidden)] - pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCell> + pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCellLayout> where T: PyClass, T::BaseLayout: PyBorrowFlagLayout, { - let cell = PyCell::internal_new(py)?; + let cell = PyCellLayout::new(py)?; self.init_class(&mut *cell); Ok(cell) } diff --git a/src/python.rs b/src/python.rs index 452c461061b..db71e76faad 100644 --- a/src/python.rs +++ b/src/python.rs @@ -5,11 +5,10 @@ use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; use crate::gil::{self, GILGuard}; -use crate::instance::AsPyRef; use crate::object::PyObject; use crate::type_object::{PyDowncastImpl, PyTypeInfo, PyTypeObject}; use crate::types::{PyAny, PyDict, PyModule, PyType}; -use crate::{AsPyPointer, FromPyPointer, IntoPyPointer, PyTryFrom}; +use crate::{AsPyPointer, FromPyPointer, IntoPyPointer, PyTryFrom, AsPyRef}; use std::ffi::CString; use std::marker::PhantomData; use std::os::raw::c_int; @@ -199,7 +198,7 @@ impl<'p> Python<'p> { ) -> PyResult<()> { let res = self.run_code(code, ffi::Py_file_input, globals, locals); res.map(|obj| { - debug_assert!(crate::ObjectProtocol::is_none(obj)); + debug_assert!(crate::ObjectProtocol::is_none(&obj)); }) } @@ -250,7 +249,7 @@ impl<'p> Python<'p> { } /// Imports the Python module with the specified name. - pub fn import(self, name: &str) -> PyResult<&'p PyModule> { + pub fn import(self, name: &str) -> PyResult> { PyModule::import(self, name) } @@ -293,7 +292,7 @@ impl<'p> Python<'p> { where T: PyTryFrom<'p>, { - let obj = unsafe { gil::register_owned(self, obj.into_nonnull()) }; + let obj = unsafe { gil::register_owned(self, obj.into_non_null()) }; ::try_from(obj) } @@ -301,9 +300,9 @@ impl<'p> Python<'p> { /// to the specific type. pub unsafe fn cast_as(self, obj: PyObject) -> &'p T where - T: PyDowncastImpl<'p> + PyTypeInfo, + T: PyDowncastImpl<'p> + PyTypeInfo<'p>, { - let obj = gil::register_owned(self, obj.into_nonnull()); + let obj = gil::register_owned(self, obj.into_non_null()); T::unchecked_downcast(obj) } @@ -319,7 +318,7 @@ impl<'p> Python<'p> { /// Registers the object pointer in the release pool, /// and does an unchecked downcast to the specific type. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_owned_ptr(self, ptr: *mut ffi::PyObject) -> &'p T + pub unsafe fn from_owned_ptr(self, ptr: *mut ffi::PyObject) -> T where T: FromPyPointer<'p>, { @@ -331,7 +330,7 @@ impl<'p> Python<'p> { /// Returns `Err(PyErr)` if the pointer is NULL. /// Does an unchecked downcast to the specific type. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_owned_ptr_or_err(self, ptr: *mut ffi::PyObject) -> PyResult<&'p T> + pub unsafe fn from_owned_ptr_or_err(self, ptr: *mut ffi::PyObject) -> PyResult where T: FromPyPointer<'p>, { @@ -343,7 +342,7 @@ impl<'p> Python<'p> { /// Returns `None` if the pointer is NULL. /// Does an unchecked downcast to the specific type. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_owned_ptr_or_opt(self, ptr: *mut ffi::PyObject) -> Option<&'p T> + pub unsafe fn from_owned_ptr_or_opt(self, ptr: *mut ffi::PyObject) -> Option where T: FromPyPointer<'p>, { @@ -438,7 +437,7 @@ mod test { // Inject our own global namespace let v: i32 = py - .eval("foo + 29", Some(d), None) + .eval("foo + 29", Some(&d), None) .unwrap() .extract() .unwrap(); @@ -446,7 +445,7 @@ mod test { // Inject our own local namespace let v: i32 = py - .eval("foo + 29", None, Some(d)) + .eval("foo + 29", None, Some(&d)) .unwrap() .extract() .unwrap(); @@ -454,7 +453,7 @@ mod test { // Make sure builtin names are still accessible when using a local namespace let v: i32 = py - .eval("min(foo, 2)", None, Some(d)) + .eval("min(foo, 2)", None, Some(&d)) .unwrap() .extract() .unwrap(); diff --git a/src/type_object.rs b/src/type_object.rs index 203c331e15e..10273f38e11 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -14,7 +14,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; /// is of `PyAny`. /// /// This trait is intended to be used internally. -pub unsafe trait PyLayout { +pub unsafe trait PyLayout<'py, T: PyTypeInfo<'py>> { const IS_NATIVE_TYPE: bool = true; fn get_super(&mut self) -> Option<&mut T::BaseLayout> { None @@ -26,7 +26,7 @@ pub unsafe trait PyLayout { /// `T: PySizedLayout` represents `T` is not a instance of /// [`PyVarObject`](https://docs.python.org/3.8/c-api/structures.html?highlight=pyvarobject#c.PyVarObject). /// , in addition that `T` is a concrete representaion of `U`. -pub trait PySizedLayout: PyLayout + Sized {} +pub trait PySizedLayout<'py, T: PyTypeInfo<'py>>: PyLayout<'py, T> + Sized {} /// Marker type indicates that `Self` can be a base layout of `PyClass`. /// @@ -42,7 +42,7 @@ pub trait PySizedLayout: PyLayout + Sized {} /// } /// ``` /// Otherwise, implementing this trait is undefined behavior. -pub unsafe trait PyBorrowFlagLayout: PyLayout + Sized {} +pub unsafe trait PyBorrowFlagLayout<'py, T: PyTypeInfo<'py>>: PyLayout<'py, T> + Sized {} /// Our custom type flags #[doc(hidden)] @@ -81,7 +81,7 @@ pub unsafe trait PyDowncastImpl<'py> { unsafe impl<'py, T> PyDowncastImpl<'py> for T where - T: 'py + crate::PyNativeType, + T: crate::PyNativeType<'py>, { unsafe fn unchecked_downcast<'a>(obj: &'a PyAny<'py>) -> &'a Self { &*(obj as *const _ as *const Self) @@ -95,7 +95,7 @@ where /// This trait is marked unsafe because: /// - specifying the incorrect layout can lead to memory errors /// - the return value of type_object must always point to the same PyTypeObject instance -pub unsafe trait PyTypeInfo: Sized { +pub unsafe trait PyTypeInfo<'py>: Sized { /// Type of objects to store in PyObject struct type Type; @@ -112,19 +112,19 @@ pub unsafe trait PyTypeInfo: Sized { const FLAGS: usize = 0; /// Base class - type BaseType: PyTypeInfo + PyTypeObject; + type BaseType: PyTypeInfo<'py> + PyTypeObject; /// Layout - type Layout: PyLayout; + type Layout: PyLayout<'py, Self>; /// Layout of Basetype. - type BaseLayout: PySizedLayout; + type BaseLayout: PySizedLayout<'py, Self::BaseType>; /// Initializer for layout type Initializer: PyObjectInit; /// Utility type to make AsPyRef work - type AsRefTarget: for<'py> PyDowncastImpl<'py>; + type AsRefTarget: PyDowncastImpl<'py>; /// PyTypeObject instance for this type. fn type_object() -> &'static ffi::PyTypeObject; @@ -150,15 +150,15 @@ pub unsafe trait PyTypeInfo: Sized { /// See [PyTypeInfo::type_object] pub unsafe trait PyTypeObject { /// Returns the safe abstraction over the type object. - fn type_object(py: Python) -> &PyType; + fn type_object() -> Py>; } -unsafe impl PyTypeObject for T +unsafe impl<'py, T> PyTypeObject for T where - T: PyTypeInfo, + T: PyTypeInfo<'py>, { - fn type_object(py: Python) -> &PyType { - unsafe { py.from_borrowed_ptr(::type_object() as *const _ as _) } + fn type_object() -> Py> { + unsafe { Py::from_borrowed_ptr(::type_object() as *const _ as _) } } } @@ -216,7 +216,7 @@ impl LazyStaticType { } } - pub fn get_or_init(&self) -> &ffi::PyTypeObject { + pub fn get_or_init PyClass<'py>>(&self) -> &ffi::PyTypeObject { if !self .initialized .compare_and_swap(false, true, Ordering::Acquire) diff --git a/src/types/any.rs b/src/types/any.rs index 26fbba9776d..42bf622952d 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -1,6 +1,10 @@ -use crate::conversion::PyTryFrom; +use crate::conversion::{FromPyPointer, PyTryFrom}; use crate::err::PyDowncastError; use crate::ffi; +use crate::gil; +use crate::python::Python; +use crate::type_object::PyTypeInfo; +use crate::pyclass_init::PyNativeTypeInitializer; use std::marker::PhantomData; use std::ptr::NonNull; @@ -30,23 +34,71 @@ use std::ptr::NonNull; /// ``` #[repr(transparent)] pub struct PyAny<'a>(NonNull, PhantomData<&'a ffi::PyObject>); -unsafe impl crate::type_object::PyLayout> for ffi::PyObject {} + impl crate::type_object::PySizedLayout> for ffi::PyObject {} pyobject_native_type_named!(PyAny); -pyobject_native_type_convert!( +pyobject_native_type_info!( PyAny, ffi::PyObject, ffi::PyBaseObject_Type, - Some("builtins"), ffi::PyObject_Check ); pyobject_native_type_extract!(PyAny); -impl PyAny { +impl<'py> PyAny<'py> { pub fn downcast(&self) -> Result<&T, PyDowncastError> where - for<'py> T: PyTryFrom<'py>, + T: PyTryFrom<'py>, { ::try_from(self) } + + /// Create a PyAny from an owned non-null raw PyObject pointer. + /// + /// # Safety + /// + /// It must be ensured that the pointer is an owned reference. + pub unsafe fn from_non_null(py: Python<'py>, ptr: NonNull) -> Self { + Self(ptr, PhantomData) + } + + /// Create an owned non-null raw PyObject pointer from this PyAny. + pub fn into_non_null(self) -> NonNull { + // Destructure self so that Drop(self) is not called. + // (Alternative would be to call std::mem::forget(self).) + let PyAny(ptr, _) = self; + ptr + } +} + +impl Clone for PyAny<'_> { + fn clone(&self) -> Self { + unsafe { ffi::Py_INCREF(self.0.as_ptr()); }; + Self(self.0, PhantomData) + } +} + +impl std::convert::AsRef for PyAny<'_> { + fn as_ref(&self) -> &Self { + self + } +} + +impl Drop for PyAny<'_> { + fn drop(&mut self) { + unsafe { ffi::Py_DECREF(self.0.as_ptr()); }; + } +} + +unsafe impl<'py> FromPyPointer<'py> for PyAny<'py> +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'py>, ptr: *mut ffi::PyObject) -> Option { + Some(Self::from_non_null(py, NonNull::new(ptr)?)) + } + unsafe fn from_borrowed_ptr_or_opt( + py: Python<'py>, + ptr: *mut ffi::PyObject, + ) -> Option<&'py Self> { + Some(gil::register_borrowed(py, NonNull::new(ptr)?)) + } } diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 70a9056d8b0..ae28d50bbd8 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -7,14 +7,14 @@ use crate::{ /// Represents a Python `bool`. #[repr(transparent)] -pub struct PyBool<'a>(PyAny<'a>); +pub struct PyBool<'py>(PyAny<'py>); pyobject_native_type!(PyBool, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check); -impl PyBool { +impl<'py> PyBool<'py> { /// Depending on `val`, returns `true` or `false`. #[inline] - pub fn new(py: Python, val: bool) -> &PyBool { + pub fn new(py: Python<'py>, val: bool) -> &'py Self { unsafe { py.from_borrowed_ptr(if val { ffi::Py_True() } else { ffi::Py_False() }) } } diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 4f8faf2b3a8..9200363ea68 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -4,6 +4,7 @@ use crate::ffi; use crate::instance::PyNativeType; use crate::internal_tricks::Unsendable; use crate::object::PyObject; +use crate::types::PyAny; use crate::AsPyPointer; use crate::Python; use std::os::raw::c_char; @@ -11,15 +12,15 @@ use std::slice; /// Represents a Python `bytearray`. #[repr(transparent)] -pub struct PyByteArray(PyObject, Unsendable); +pub struct PyByteArray<'py>(PyAny<'py>); pyobject_native_var_type!(PyByteArray, ffi::PyByteArray_Type, ffi::PyByteArray_Check); -impl PyByteArray { +impl<'py> PyByteArray<'py> { /// Creates a new Python bytearray object. /// /// The byte string is initialized by copying the data from the `&[u8]`. - pub fn new<'p>(py: Python<'p>, src: &[u8]) -> &'p PyByteArray { + pub fn new(py: Python<'py>, src: &[u8]) -> Self { let ptr = src.as_ptr() as *const c_char; let len = src.len() as ffi::Py_ssize_t; unsafe { py.from_owned_ptr::(ffi::PyByteArray_FromStringAndSize(ptr, len)) } @@ -27,7 +28,7 @@ impl PyByteArray { /// Creates a new Python bytearray object from another PyObject that /// implements the buffer protocol. - pub fn from<'p, I>(py: Python<'p>, src: &'p I) -> PyResult<&'p PyByteArray> + pub fn from(py: Python<'py>, src: &I) -> PyResult where I: AsPyPointer, { diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 50603270d2c..b6ba3d35c79 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -12,16 +12,16 @@ use std::str; /// /// This type is immutable. #[repr(transparent)] -pub struct PyBytes(PyObject, Unsendable); +pub struct PyBytes<'py>(PyAny<'py>); pyobject_native_var_type!(PyBytes, ffi::PyBytes_Type, ffi::PyBytes_Check); -impl PyBytes { +impl<'py> PyBytes<'py> { /// Creates a new Python bytestring object. /// The bytestring is initialized by copying the data from the `&[u8]`. /// /// Panics if out of memory. - pub fn new<'p>(py: Python<'p>, s: &[u8]) -> &'p PyBytes { + pub fn new(py: Python<'py>, s: &[u8]) -> Self { let ptr = s.as_ptr() as *const c_char; let len = s.len() as ffi::Py_ssize_t; unsafe { py.from_owned_ptr(ffi::PyBytes_FromStringAndSize(ptr, len)) } @@ -30,7 +30,7 @@ impl PyBytes { /// Creates a new Python byte string object from a raw pointer and length. /// /// Panics if out of memory. - pub unsafe fn from_ptr(py: Python<'_>, ptr: *const u8, len: usize) -> &PyBytes { + pub unsafe fn from_ptr(py: Python<'py>, ptr: *const u8, len: usize) -> Self { py.from_owned_ptr(ffi::PyBytes_FromStringAndSize( ptr as *const _, len as isize, @@ -50,7 +50,7 @@ impl PyBytes { } /// This is the same way [Vec] is indexed. -impl> Index for PyBytes { +impl> Index for PyBytes<'_> { type Output = I::Output; fn index(&self, index: I) -> &Self::Output { diff --git a/src/types/complex.rs b/src/types/complex.rs index 86ac6f4388b..ff0f68d1da2 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -2,6 +2,7 @@ use crate::ffi; #[cfg(not(PyPy))] use crate::instance::PyNativeType; use crate::internal_tricks::Unsendable; +use crate::types::PyAny; use crate::AsPyPointer; use crate::PyObject; use crate::Python; @@ -11,7 +12,7 @@ use std::os::raw::c_double; /// Represents a Python `complex`. #[repr(transparent)] -pub struct PyComplex(PyObject, Unsendable); +pub struct PyComplex<'py>(PyAny<'py>); pyobject_native_type!( PyComplex, @@ -20,9 +21,9 @@ pyobject_native_type!( ffi::PyComplex_Check ); -impl PyComplex { +impl<'py> PyComplex<'py> { /// Creates a new Python `complex` object, from its real and imaginary values. - pub fn from_doubles(py: Python, real: c_double, imag: c_double) -> &PyComplex { + pub fn from_doubles(py: Python<'py>, real: c_double, imag: c_double) -> Self { unsafe { let ptr = ffi::PyComplex_FromDoubles(real, imag); py.from_owned_ptr(ptr) @@ -48,7 +49,7 @@ impl PyComplex { /// Returns `self ** other` #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] - pub fn pow(&self, other: &PyComplex) -> &PyComplex { + pub fn pow(&self, other: &PyComplex) -> Self { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_pow)) @@ -71,9 +72,9 @@ unsafe fn complex_operation( #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Add for &'py PyComplex { - type Output = &'py PyComplex; - fn add(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Add<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn add(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_sum)) @@ -83,9 +84,9 @@ impl<'py> Add for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Sub for &'py PyComplex { - type Output = &'py PyComplex; - fn sub(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Sub<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn sub(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_diff)) @@ -95,9 +96,9 @@ impl<'py> Sub for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Mul for &'py PyComplex { - type Output = &'py PyComplex; - fn mul(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Mul<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn mul(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_prod)) @@ -107,9 +108,9 @@ impl<'py> Mul for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Div for &'py PyComplex { - type Output = &'py PyComplex; - fn div(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Div<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn div(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_quot)) @@ -119,9 +120,9 @@ impl<'py> Div for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Neg for &'py PyComplex { - type Output = &'py PyComplex; - fn neg(self) -> &'py PyComplex { +impl<'py> Neg for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn neg(self) -> PyComplex<'py> { unsafe { let val = (*(self.as_ptr() as *mut ffi::PyComplexObject)).cval; self.py() diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 1946a30ec15..e8ba5b6945c 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -66,7 +66,7 @@ pub trait PyTimeAccess { } /// Bindings around `datetime.date` -pub struct PyDate<'a>(PyAny<'a>); +pub struct PyDate<'py>(PyAny<'py>); pyobject_native_type!( PyDate, crate::ffi::PyDateTime_Date, @@ -75,8 +75,8 @@ pyobject_native_type!( PyDate_Check ); -impl PyDate { - pub fn new<'p>(py: Python<'p>, year: i32, month: u8, day: u8) -> PyResult<&'p PyDate> { +impl<'py> PyDate<'py> { + pub fn new(py: Python<'py>, year: i32, month: u8, day: u8) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Date_FromDate)( year, @@ -91,7 +91,7 @@ impl PyDate { /// Construct a `datetime.date` from a POSIX timestamp /// /// This is equivalent to `datetime.date.fromtimestamp` - pub fn from_timestamp<'p>(py: Python<'p>, timestamp: i64) -> PyResult<&'p PyDate> { + pub fn from_timestamp(py: Python<'py>, timestamp: i64) -> PyResult { let time_tuple = PyTuple::new(py, &[timestamp]); unsafe { @@ -107,7 +107,7 @@ impl PyDate { } } -impl PyDateAccess for PyDate { +impl PyDateAccess for PyDate<'_> { fn get_year(&self) -> i32 { unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 } } @@ -122,7 +122,7 @@ impl PyDateAccess for PyDate { } /// Bindings for `datetime.datetime` -pub struct PyDateTime<'a>(PyAny<'a>); +pub struct PyDateTime<'py>(PyAny<'py>); pyobject_native_type!( PyDateTime, crate::ffi::PyDateTime_DateTime, @@ -131,9 +131,9 @@ pyobject_native_type!( PyDateTime_Check ); -impl PyDateTime { - pub fn new<'p>( - py: Python<'p>, +impl<'py> PyDateTime<'py> { + pub fn new( + py: Python<'py>, year: i32, month: u8, day: u8, @@ -142,7 +142,7 @@ impl PyDateTime { second: u8, microsecond: u32, tzinfo: Option<&PyObject>, - ) -> PyResult> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.DateTime_FromDateAndTime)( year, @@ -162,11 +162,11 @@ impl PyDateTime { /// Construct a `datetime` object from a POSIX timestamp /// /// This is equivalent to `datetime.datetime.from_timestamp` - pub fn from_timestamp<'p>( - py: Python<'p>, + pub fn from_timestamp( + py: Python<'py>, timestamp: f64, time_zone_info: Option<&PyTzInfo>, - ) -> PyResult> { + ) -> PyResult { let timestamp: PyObject = timestamp.to_object(py); let time_zone_info: PyObject = match time_zone_info { @@ -194,7 +194,7 @@ impl PyDateTime { } } -impl PyDateAccess for PyDateTime { +impl PyDateAccess for PyDateTime<'_> { fn get_year(&self) -> i32 { unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 } } @@ -208,7 +208,7 @@ impl PyDateAccess for PyDateTime { } } -impl PyTimeAccess for PyDateTime { +impl PyTimeAccess for PyDateTime<'_> { fn get_hour(&self) -> u8 { unsafe { PyDateTime_DATE_GET_HOUR(self.as_ptr()) as u8 } } @@ -232,7 +232,7 @@ impl PyTimeAccess for PyDateTime { } /// Bindings for `datetime.time` -pub struct PyTime<'a>(PyAny<'a>); +pub struct PyTime<'py>(PyAny<'py>); pyobject_native_type!( PyTime, crate::ffi::PyDateTime_Time, @@ -241,15 +241,15 @@ pyobject_native_type!( PyTime_Check ); -impl PyTime { - pub fn new<'p>( - py: Python<'p>, +impl<'py> PyTime<'py> { + pub fn new( + py: Python<'py>, hour: u8, minute: u8, second: u8, microsecond: u32, tzinfo: Option<&PyObject>, - ) -> PyResult> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Time_FromTime)( c_int::from(hour), @@ -267,15 +267,15 @@ impl PyTime { /// Alternate constructor that takes a `fold` argument /// /// First available in Python 3.6. - pub fn new_with_fold<'p>( - py: Python<'p>, + pub fn new_with_fold( + py: Python<'py>, hour: u8, minute: u8, second: u8, microsecond: u32, tzinfo: Option<&PyObject>, fold: bool, - ) -> PyResult> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Time_FromTimeAndFold)( c_int::from(hour), @@ -291,7 +291,7 @@ impl PyTime { } } -impl PyTimeAccess for PyTime { +impl PyTimeAccess for PyTime<'_> { fn get_hour(&self) -> u8 { unsafe { PyDateTime_TIME_GET_HOUR(self.as_ptr()) as u8 } } @@ -317,7 +317,7 @@ impl PyTimeAccess for PyTime { /// Bindings for `datetime.tzinfo` /// /// This is an abstract base class and should not be constructed directly. -pub struct PyTzInfo<'a>(PyAny<'a>); +pub struct PyTzInfo<'py>(PyAny<'py>); pyobject_native_type!( PyTzInfo, crate::ffi::PyObject, @@ -327,7 +327,7 @@ pyobject_native_type!( ); /// Bindings for `datetime.timedelta` -pub struct PyDelta<'a>(PyAny<'a>); +pub struct PyDelta<'py>(PyAny<'py>); pyobject_native_type!( PyDelta, crate::ffi::PyDateTime_Delta, @@ -336,14 +336,14 @@ pyobject_native_type!( PyDelta_Check ); -impl PyDelta { - pub fn new<'p>( - py: Python<'p>, +impl<'py> PyDelta<'py> { + pub fn new( + py: Python<'py>, days: i32, seconds: i32, microseconds: i32, normalize: bool, - ) -> PyResult<&'p PyDelta> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Delta_FromDelta)( days as c_int, @@ -357,7 +357,7 @@ impl PyDelta { } } -impl PyDeltaAccess for PyDelta { +impl PyDeltaAccess for PyDelta<'_> { fn get_days(&self) -> i32 { unsafe { PyDateTime_DELTA_GET_DAYS(self.as_ptr()) as i32 } } diff --git a/src/types/dict.rs b/src/types/dict.rs index 3593863a4b5..82c9a437038 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -17,7 +17,7 @@ use std::{cmp, collections, hash}; /// Represents a Python `dict`. #[repr(transparent)] -pub struct PyDict(PyObject, Unsendable); +pub struct PyDict<'py>(PyAny<'py>); pyobject_native_type!( PyDict, @@ -26,10 +26,10 @@ pyobject_native_type!( ffi::PyDict_Check ); -impl PyDict { +impl<'py> PyDict<'py> { /// Creates a new empty dictionary. - pub fn new(py: Python) -> &PyDict { - unsafe { py.from_owned_ptr::(ffi::PyDict_New()) } + pub fn new(py: Python<'py>) -> Self { + unsafe { py.from_owned_ptr(ffi::PyDict_New()) } } /// Creates a new dictionary from the sequence given. @@ -40,7 +40,7 @@ impl PyDict { /// Returns an error on invalid input. In the case of key collisions, /// this keeps the last entry seen. #[cfg(not(PyPy))] - pub fn from_sequence(py: Python, seq: PyObject) -> PyResult<&PyDict> { + pub fn from_sequence(py: Python<'py>, seq: &PyAny) -> PyResult { unsafe { let dict = py.from_owned_ptr::(ffi::PyDict_New()); match ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1i32) { @@ -54,7 +54,7 @@ impl PyDict { /// Returns a new dictionary that contains the same key-value pairs as self. /// /// This is equivalent to the Python expression `dict(self)`. - pub fn copy(&self) -> PyResult<&PyDict> { + pub fn copy(&self) -> PyResult { unsafe { self.py() .from_owned_ptr_or_err::(ffi::PyDict_Copy(self.as_ptr())) @@ -139,30 +139,30 @@ impl PyDict { /// Returns a list of dict keys. /// /// This is equivalent to the Python expression `list(dict.keys())`. - pub fn keys(&self) -> &PyList { + pub fn keys(&self) -> PyList<'py> { unsafe { self.py() - .from_owned_ptr::(ffi::PyDict_Keys(self.as_ptr())) + .from_owned_ptr(ffi::PyDict_Keys(self.as_ptr())) } } /// Returns a list of dict values. /// /// This is equivalent to the Python expression `list(dict.values())`. - pub fn values(&self) -> &PyList { + pub fn values(&self) -> PyList<'py> { unsafe { self.py() - .from_owned_ptr::(ffi::PyDict_Values(self.as_ptr())) + .from_owned_ptr(ffi::PyDict_Values(self.as_ptr())) } } /// Returns a list of dict items. /// /// This is equivalent to the Python expression `list(dict.items())`. - pub fn items(&self) -> &PyList { + pub fn items(&self) -> PyList<'py> { unsafe { self.py() - .from_owned_ptr::(ffi::PyDict_Items(self.as_ptr())) + .from_owned_ptr(ffi::PyDict_Items(self.as_ptr())) } } @@ -170,21 +170,21 @@ impl PyDict { /// /// Note that it's unsafe to use when the dictionary might be changed by /// other code. - pub fn iter(&self) -> PyDictIterator { + pub fn iter<'a>(&'a self) -> PyDictIterator<'a, 'py> { PyDictIterator { - dict: self.as_ref(), + dict: self, pos: 0, } } } -pub struct PyDictIterator<'py> { - dict: &'py PyAny<'py>, +pub struct PyDictIterator<'a, 'py> { + dict: &'a PyDict<'py>, pos: isize, } -impl<'py> Iterator for PyDictIterator<'py> { - type Item = (&'py PyAny<'py>, &'py PyAny<'py>); +impl<'a, 'py> Iterator for PyDictIterator<'a, 'py> { + type Item = (&'a PyAny<'py>, &'a PyAny<'py>); #[inline] fn next(&mut self) -> Option { @@ -201,9 +201,9 @@ impl<'py> Iterator for PyDictIterator<'py> { } } -impl<'a> std::iter::IntoIterator for &'a PyDict { - type Item = (&'a PyAny<'a>, &'a PyAny<'a>); - type IntoIter = PyDictIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PyDict<'py> { + type Item = (&'a PyAny<'py>, &'a PyAny<'py>); + type IntoIter = PyDictIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { self.iter() @@ -263,7 +263,7 @@ where pub trait IntoPyDict { /// Converts self into a `PyDict` object pointer. Whether pointer owned or borrowed /// depends on implementation. - fn into_py_dict(self, py: Python) -> &PyDict; + fn into_py_dict(self, py: Python) -> PyDict; } impl IntoPyDict for I @@ -271,7 +271,7 @@ where T: PyDictItem, I: IntoIterator, { - fn into_py_dict(self, py: Python) -> &PyDict { + fn into_py_dict(self, py: Python) -> PyDict { let dict = PyDict::new(py); for item in self { dict.set_item(item.key(), item.value()) @@ -379,7 +379,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let items = PyList::new(py, &vec![("a", 1), ("b", 2)]); - let dict = PyDict::from_sequence(py, items.to_object(py)).unwrap(); + let dict = PyDict::from_sequence(py, &items).unwrap(); assert_eq!(1, dict.get_item("a").unwrap().extract::().unwrap()); assert_eq!(2, dict.get_item("b").unwrap().extract::().unwrap()); let map: HashMap<&str, i32> = [("a", 1), ("b", 2)].iter().cloned().collect(); diff --git a/src/types/floatob.rs b/src/types/floatob.rs index 7629d562774..c49586bffd5 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -15,7 +15,7 @@ use std::os::raw::c_double; /// and [extract](struct.PyObject.html#method.extract) /// with `f32`/`f64`. #[repr(transparent)] -pub struct PyFloat(PyObject, Unsendable); +pub struct PyFloat<'py>(PyAny<'py>); pyobject_native_type!( PyFloat, @@ -24,9 +24,9 @@ pyobject_native_type!( ffi::PyFloat_Check ); -impl PyFloat { +impl<'py> PyFloat<'py> { /// Creates a new Python `float` object. - pub fn new(py: Python<'_>, val: c_double) -> &PyFloat { + pub fn new(py: Python<'py>, val: c_double) -> Self { unsafe { py.from_owned_ptr(ffi::PyFloat_FromDouble(val)) } } diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 11501f72a98..0a717e2a8c7 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -42,8 +42,7 @@ impl<'p> PyIterator<'p> { } if ffi::PyIter_Check(ptr) != 0 { - // this is not right, but this cause of segfault check #71 - Ok(PyIterator(py.from_borrowed_ptr(ptr))) + Ok(PyIterator(py.from_owned_ptr(ptr))) } else { Err(PyDowncastError) } diff --git a/src/types/list.rs b/src/types/list.rs index 437010a95a1..93b6f77c549 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -12,13 +12,13 @@ use crate::{ /// Represents a Python `list`. #[repr(transparent)] -pub struct PyList(PyObject, Unsendable); +pub struct PyList<'py>(PyAny<'py>); pyobject_native_var_type!(PyList, ffi::PyList_Type, ffi::PyList_Check); -impl PyList { +impl<'py> PyList<'py> { /// Constructs a new list with the given elements. - pub fn new(py: Python<'_>, elements: impl IntoIterator) -> &PyList + pub fn new(py: Python<'py>, elements: impl IntoIterator) -> Self where T: ToPyObject, U: ExactSizeIterator, @@ -36,7 +36,7 @@ impl PyList { } /// Constructs a new empty list. - pub fn empty(py: Python) -> &PyList { + pub fn empty(py: Python<'py>) -> Self { unsafe { py.from_owned_ptr::(ffi::PyList_New(0)) } } @@ -131,7 +131,7 @@ impl PyList { /// Used by `PyList::iter()`. pub struct PyListIterator<'a> { - list: &'a PyList, + list: &'a PyList<'a>, index: isize, } @@ -150,7 +150,7 @@ impl<'a> Iterator for PyListIterator<'a> { } } -impl<'a> std::iter::IntoIterator for &'a PyList { +impl<'a> std::iter::IntoIterator for &'a PyList<'a> { type Item = &'a PyAny<'a>; type IntoIter = PyListIterator<'a>; diff --git a/src/types/mod.rs b/src/types/mod.rs index 95f2e65826f..59ae7ce983f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -28,14 +28,7 @@ pub use self::typeobject::PyType; #[macro_export] macro_rules! pyobject_native_type_named ( ($name: ident $(,$type_param: ident)*) => { - impl<'a, $($type_param,)*> ::std::convert::AsRef<$crate::PyAny<'a>> for $name<'a> { - #[inline] - fn as_ref(&self) -> &$crate::PyAny<'a> { - unsafe{&*(self as *const $name as *const $crate::PyAny)} - } - } - - unsafe impl<$($type_param,)*> $crate::PyNativeType for $name<'_> {} + unsafe impl<'py, $($type_param,)*> $crate::PyNativeType<'py> for $name<'py> {} impl<$($type_param,)*> $crate::AsPyPointer for $name<'_> { /// Gets the underlying FFI pointer, returns a borrowed pointer. @@ -53,13 +46,48 @@ macro_rules! pyobject_native_type_named ( self.as_ptr() == o.as_ptr() } } + + impl<$($type_param,)*> $crate::ToPyObject for $name<'_> + { + #[inline] + fn to_object(&self, py: $crate::Python) -> $crate::PyObject { + use $crate::AsPyPointer; + unsafe {$crate::PyObject::from_borrowed_ptr(py, self.as_ptr())} + } + } + + impl std::convert::From<$name<'_>> for $crate::PyObject + { + fn from(ob: $name<'_>) -> Self { + Self::from_non_null(ob.into_non_null()) + } + } + + impl<$($type_param,)*> ::std::fmt::Debug for $name<'_> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> + { + use $crate::ObjectProtocol; + let s = self.repr().map_err(|_| ::std::fmt::Error)?; + f.write_str(&s.to_string_lossy()) + } + } + + impl<$($type_param,)*> ::std::fmt::Display for $name<'_> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> + { + use $crate::ObjectProtocol; + let s = self.str().map_err(|_| ::std::fmt::Error)?; + f.write_str(&s.to_string_lossy()) + } + } }; ); #[macro_export] macro_rules! pyobject_native_type { ($name: ident, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name<'_>> for $layout {} impl $crate::type_object::PySizedLayout<$name<'_>> for $layout {} impl $crate::derive_utils::PyBaseTypeUtils for $name<'_> { type Dict = $crate::pyclass_slots::PyClassDummySlot; @@ -68,16 +96,13 @@ macro_rules! pyobject_native_type { type BaseNativeType = Self; } pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_type_convert!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); + pyobject_native_newtype!($name, $(,$type_param)*); + pyobject_native_type_info!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); pyobject_native_type_extract!($name $(,$type_param)*); - impl<'a, $($type_param,)*> ::std::convert::From<&'a $name> for &'a $crate::PyAny { - fn from(ob: &'a $name) -> Self { - unsafe{&*(ob as *const $name as *const $crate::PyAny)} - } - } + }; - ($name: ty, $layout: path, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ident, $layout: path, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { pyobject_native_type! { $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* } @@ -86,32 +111,26 @@ macro_rules! pyobject_native_type { #[macro_export] macro_rules! pyobject_native_var_type { - ($name: ty, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name> for $crate::ffi::PyObject {} + ($name: ident, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_type_convert!($name, $crate::ffi::PyObject, - $typeobject, $module, $checkfunction $(,$type_param)*); + pyobject_native_newtype!($name, $(,$type_param)*); + pyobject_native_type_info!($name, $crate::ffi::PyObject, + $typeobject, $module, $checkfunction $(,$type_param)*); pyobject_native_type_extract!($name $(,$type_param)*); - - impl<'a, $($type_param,)*> ::std::convert::From<&'a $name> for &'a $crate::PyAny { - fn from(ob: &'a $name) -> Self { - unsafe{&*(ob as *const $name as *const $crate::PyAny)} - } - } }; - ($name: ty, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ident, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { pyobject_native_var_type! { $name, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* } }; } -// NOTE: This macro is not included in pyobject_native_type_convert! +// NOTE: This macro is not included in pyobject_native_newtype! // because rust-numpy has a special implementation. macro_rules! pyobject_native_type_extract { - ($name: ty $(,$type_param: ident)*) => { - impl<'py, $($type_param,)*> $crate::FromPyObject<'py> for &'py $name { - fn extract(obj: &'py $crate::PyAny) -> $crate::PyResult { + ($name: ident $(,$type_param: ident)*) => { + impl<'a, 'py, $($type_param,)*> $crate::FromPyObject<'py> for &'a $name<'py> { + fn extract(obj: &'a $crate::PyAny<'py>) -> $crate::PyResult { $crate::PyTryFrom::try_from(obj).map_err(Into::into) } } @@ -119,12 +138,14 @@ macro_rules! pyobject_native_type_extract { } #[macro_export] -macro_rules! pyobject_native_type_convert( +macro_rules! pyobject_native_type_info( ($name: ident, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl<'a, $($type_param,)*> $crate::type_object::PyTypeInfo for $name<'a> { + unsafe impl $crate::type_object::PyLayout<$name<'_>> for $layout {} + + unsafe impl<'a, $($type_param,)*> $crate::type_object::PyTypeInfo for $name<'_> { type Type = (); - type BaseType = $crate::PyAny<'a>; + type BaseType = $crate::PyAny<'static>; type Layout = $layout; type BaseLayout = ffi::PyObject; type Initializer = $crate::pyclass_init::PyNativeTypeInitializer; @@ -144,33 +165,57 @@ macro_rules! pyobject_native_type_convert( unsafe { $checkfunction(ptr.as_ptr()) > 0 } } } + }; - impl<$($type_param,)*> $crate::ToPyObject for $name - { + ($name: ident, $layout: path, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + pyobject_native_type_info! { + $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + } + }; +); + +#[macro_export] +macro_rules! pyobject_native_newtype( + ($name: ident, $(,$type_param: ident)*) => { + impl<'a, $($type_param,)*> ::std::convert::From<&'a $name<'a>> for &'a $crate::PyAny<'a> { + fn from(ob: &'a $name) -> Self { + unsafe{&*(ob as *const $name as *const $crate::PyAny)} + } + } + + impl Clone for $name<'_> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + + impl<'a, $($type_param,)*> ::std::convert::AsRef<$crate::PyAny<'a>> for $name<'a> { #[inline] - fn to_object(&self, py: $crate::Python) -> $crate::PyObject { - use $crate::AsPyPointer; - unsafe {$crate::PyObject::from_borrowed_ptr(py, self.0.as_ptr())} + fn as_ref(&self) -> &$crate::PyAny<'a> { + &self.0 } } - impl<$($type_param,)*> ::std::fmt::Debug for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) - -> Result<(), ::std::fmt::Error> - { - use $crate::ObjectProtocol; - let s = self.repr().map_err(|_| ::std::fmt::Error)?; - f.write_str(&s.to_string_lossy()) + impl<'a, $($type_param,)*> ::std::ops::Deref for $name<'a> { + type Target = $crate::PyAny<'a>; + + #[inline] + fn deref(&self) -> &$crate::PyAny<'a> { + &self.0 } } - impl<$($type_param,)*> ::std::fmt::Display for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) - -> Result<(), ::std::fmt::Error> - { - use $crate::ObjectProtocol; - let s = self.str().map_err(|_| ::std::fmt::Error)?; - f.write_str(&s.to_string_lossy()) + unsafe impl<'p> $crate::FromPyPointer<'p> for $name<'p> + { + unsafe fn from_owned_ptr_or_opt(py: $crate::Python<'p>, ptr: *mut $crate::ffi::PyObject) -> Option { + ::std::ptr::NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p))) + } + unsafe fn from_borrowed_ptr_or_opt( + py: $crate::Python<'p>, + ptr: *mut $crate::ffi::PyObject, + ) -> Option<&'p Self> { + use $crate::type_object::PyDowncastImpl; + ::std::ptr::NonNull::new(ptr).map(|p| Self::unchecked_downcast($crate::gil::register_borrowed(py, p))) } } }; diff --git a/src/types/module.rs b/src/types/module.rs index 77532d9801f..1f45b5cd401 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -20,19 +20,19 @@ use std::str; /// Represents a Python `module` object. #[repr(transparent)] -pub struct PyModule(PyObject, Unsendable); +pub struct PyModule<'py>(PyAny<'py>); pyobject_native_var_type!(PyModule, ffi::PyModule_Type, ffi::PyModule_Check); -impl PyModule { +impl<'py> PyModule<'py> { /// Creates a new module object with the `__name__` attribute set to name. - pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> { + pub fn new(py: Python<'py>, name: &str) -> PyResult { let name = CString::new(name)?; unsafe { py.from_owned_ptr_or_err(ffi::PyModule_New(name.as_ptr())) } } /// Imports the Python module with the specified name. - pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> { + pub fn import(py: Python<'py>, name: &str) -> PyResult { let name = CString::new(name)?; unsafe { py.from_owned_ptr_or_err(ffi::PyImport_ImportModule(name.as_ptr())) } } @@ -43,12 +43,12 @@ impl PyModule { /// `file_name` is the file name to associate with the module /// (this is used when Python reports errors, for example). /// `module_name` is the name to give the module. - pub fn from_code<'p>( - py: Python<'p>, + pub fn from_code( + py: Python<'py>, code: &str, file_name: &str, module_name: &str, - ) -> PyResult<&'p PyModule> { + ) -> PyResult { let data = CString::new(code)?; let filename = CString::new(file_name)?; let module = CString::new(module_name)?; @@ -64,7 +64,7 @@ impl PyModule { return Err(PyErr::fetch(py)); } - <&PyModule as crate::FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?) + py.from_owned_ptr_or_err(mptr) } } @@ -78,9 +78,9 @@ impl PyModule { } /// Return the index (`__all__`) of the module, creating one if needed. - pub fn index(&self) -> PyResult<&PyList> { + pub fn index(&self) -> PyResult> { match self.getattr("__all__") { - Ok(idx) => idx.downcast().map_err(PyErr::from), + Ok(idx) => idx.downcast().map(Clone::clone).map_err(PyErr::from), Err(err) => { if err.is_instance::(self.py()) { let l = PyList::empty(self.py()); @@ -101,7 +101,7 @@ impl PyModule { match str::from_utf8(slice) { Ok(s) => Ok(s), Err(e) => Err(PyErr::from_instance( - exceptions::UnicodeDecodeError::new_utf8(self.py(), slice, e)?, + &exceptions::UnicodeDecodeError::new_utf8(self.py(), slice, e)?, )), } } @@ -127,30 +127,30 @@ impl PyModule { pub fn call( &self, name: &str, - args: impl IntoPy>, + args: impl IntoPy>>, kwargs: Option<&PyDict>, - ) -> PyResult<&PyAny> { + ) -> PyResult> { self.getattr(name)?.call(args, kwargs) } /// Calls a function in the module with only positional arguments. /// /// This is equivalent to the Python expression `module.name(*args)`. - pub fn call1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyAny> { + pub fn call1(&self, name: &str, args: impl IntoPy>>) -> PyResult> { self.getattr(name)?.call1(args) } /// Calls a function in the module without arguments. /// /// This is equivalent to the Python expression `module.name()`. - pub fn call0(&self, name: &str) -> PyResult<&PyAny> { + pub fn call0(&self, name: &str) -> PyResult> { self.getattr(name)?.call0() } /// Gets a member from the module. /// /// This is equivalent to the Python expression `module.name`. - pub fn get(&self, name: &str) -> PyResult<&PyAny> { + pub fn get(&self, name: &str) -> PyResult> { self.getattr(name) } diff --git a/src/types/num.rs b/src/types/num.rs index 10396f37683..6d6ff5385eb 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -111,7 +111,7 @@ macro_rules! int_convert_128 { /// and [extract](struct.PyObject.html#method.extract) /// with the primitive Rust integer types. #[repr(transparent)] -pub struct PyLong(PyObject, Unsendable); +pub struct PyLong<'py>(PyAny<'py>); pyobject_native_var_type!(PyLong, ffi::PyLong_Type, ffi::PyLong_Check); diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 7063ce8dab1..a7d41edd121 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -1,24 +1,28 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::buffer; +use crate::conversion::FromPyPointer; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions; +use crate::gil; use crate::ffi::{self, Py_ssize_t}; use crate::instance::PyNativeType; use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::types::{PyAny, PyList, PyTuple}; +use crate::type_object::PyDowncastImpl; use crate::AsPyPointer; -use crate::{FromPyObject, PyTryFrom, ToBorrowedObject}; +use crate::{FromPyObject, PyTryFrom, ToBorrowedObject, Python}; +use std::ptr::NonNull; /// Represents a reference to a Python object supporting the sequence protocol. #[repr(transparent)] -pub struct PySequence<'a>(PyAny<'a>); +pub struct PySequence<'py>(PyAny<'py>); pyobject_native_type_named!(PySequence); pyobject_native_type_extract!(PySequence); -impl PySequence { +impl<'py> PySequence<'py> { /// Returns the number of objects in sequence. /// /// This is equivalent to the Python expression `len(self)`. @@ -41,15 +45,14 @@ impl PySequence { /// /// This is equivalent to the Python expression `self + other`. #[inline] - pub fn concat(&self, other: &PySequence) -> PyResult<&PySequence> { + pub fn concat(&self, other: &PySequence) -> PyResult { unsafe { - let ptr = self + self .py() - .from_owned_ptr_or_err::(ffi::PySequence_Concat( + .from_owned_ptr_or_err(ffi::PySequence_Concat( self.as_ptr(), other.as_ptr(), - ))?; - Ok(&*(ptr as *const PyAny as *const PySequence)) + )) } } @@ -58,15 +61,14 @@ impl PySequence { /// This is equivalent to the Python expression `self * count`. /// NB: Python accepts negative counts; it returns an empty Sequence. #[inline] - pub fn repeat(&self, count: isize) -> PyResult<&PySequence> { + pub fn repeat(&self, count: isize) -> PyResult { unsafe { - let ptr = self + self .py() - .from_owned_ptr_or_err::(ffi::PySequence_Repeat( + .from_owned_ptr_or_err(ffi::PySequence_Repeat( self.as_ptr(), count as Py_ssize_t, - ))?; - Ok(&*(ptr as *const PyAny as *const PySequence)) + )) } } @@ -105,7 +107,7 @@ impl PySequence { /// /// This is equivalent to the Python expression `self[index]`. #[inline] - pub fn get_item(&self, index: isize) -> PyResult<&PyAny> { + pub fn get_item(&self, index: isize) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t)) @@ -116,7 +118,7 @@ impl PySequence { /// /// This is equivalent to the Python expression `self[begin:end]`. #[inline] - pub fn get_slice(&self, begin: isize, end: isize) -> PyResult<&PyAny> { + pub fn get_slice(&self, begin: isize, end: isize) -> PyResult> { unsafe { self.py().from_owned_ptr_or_err(ffi::PySequence_GetSlice( self.as_ptr(), @@ -244,7 +246,7 @@ impl PySequence { /// Returns a fresh list based on the Sequence. #[inline] - pub fn list(&self) -> PyResult<&PyList> { + pub fn list(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PySequence_List(self.as_ptr())) @@ -253,7 +255,7 @@ impl PySequence { /// Returns a fresh tuple based on the Sequence. #[inline] - pub fn tuple(&self) -> PyResult<&PyTuple> { + pub fn tuple(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PySequence_Tuple(self.as_ptr())) @@ -360,9 +362,8 @@ where Ok(()) } -impl<'v> PyTryFrom<'v> for PySequence<'v> { - fn try_from>>(value: V) -> Result<&'v PySequence<'v>, PyDowncastError> { - let value = value.into(); +impl<'py> PyTryFrom<'py> for PySequence<'py> { + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a PySequence<'py>, PyDowncastError> { unsafe { if ffi::PySequence_Check(value.as_ptr()) != 0 { Ok(::try_from_unchecked(value)) @@ -372,17 +373,30 @@ impl<'v> PyTryFrom<'v> for PySequence<'v> { } } - fn try_from_exact>>(value: V) -> Result<&'v PySequence<'v>, PyDowncastError> { + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a PySequence<'py>, PyDowncastError> { ::try_from(value) } #[inline] - unsafe fn try_from_unchecked>>(value: V) -> &'v PySequence<'v> { - let ptr = value.into() as *const _ as *const PySequence; + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a PySequence<'py> { + let ptr = value as *const _ as *const PySequence; &*ptr } } +unsafe impl<'py> FromPyPointer<'py> for PySequence<'py> +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'py>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p))) + } + unsafe fn from_borrowed_ptr_or_opt( + py: Python<'py>, + ptr: *mut ffi::PyObject, + ) -> Option<&'py Self> { + NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p))) + } +} + #[cfg(test)] mod test { use crate::instance::AsPyRef; diff --git a/src/types/set.rs b/src/types/set.rs index b7f2745b223..8a850a6b49a 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -13,11 +13,11 @@ use std::{collections, hash, ptr}; /// Represents a Python `set` #[repr(transparent)] -pub struct PySet(PyObject, Unsendable); +pub struct PySet<'py>(PyAny<'py>); -/// Represents a Python `frozenset` +/// Represents a Python `frozenset` #[repr(transparent)] -pub struct PyFrozenSet(PyObject, Unsendable); +pub struct PyFrozenSet<'py>(PyAny<'py>); pyobject_native_type!(PySet, ffi::PySetObject, ffi::PySet_Type, ffi::PySet_Check); pyobject_native_type!( @@ -27,17 +27,17 @@ pyobject_native_type!( ffi::PyFrozenSet_Check ); -impl PySet { +impl<'py> PySet<'py> { /// Creates a new set with elements from the given slice. /// /// Returns an error if some element is not hashable. - pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> PyResult<&'p PySet> { + pub fn new(py: Python<'py>, elements: &[T]) -> PyResult { let list = elements.to_object(py); unsafe { py.from_owned_ptr_or_err(ffi::PySet_New(list.as_ptr())) } } /// Creates a new empty set. - pub fn empty<'p>(py: Python<'p>) -> PyResult<&'p PySet> { + pub fn empty(py: Python<'py>) -> PyResult { unsafe { py.from_owned_ptr_or_err(ffi::PySet_New(ptr::null_mut())) } } @@ -112,7 +112,7 @@ impl PySet { /// /// Note that it can be unsafe to use when the set might be changed by other code. #[cfg(not(Py_LIMITED_API))] - pub fn iter(&self) -> PySetIterator { + pub fn iter<'a>(&'a self) -> PySetIterator<'a, 'py> { PySetIterator { set: self.as_ref(), pos: 0, @@ -121,14 +121,14 @@ impl PySet { } #[cfg(not(Py_LIMITED_API))] -pub struct PySetIterator<'py> { - set: PyAny<'py>, +pub struct PySetIterator<'a, 'py> { + set: &'a PyAny<'py>, pos: isize, } #[cfg(not(Py_LIMITED_API))] -impl<'py> Iterator for PySetIterator<'py> { - type Item = &'py PyAny<'py>; +impl<'a, 'py> Iterator for PySetIterator<'a, 'py> { + type Item = &'a PyAny<'py>; #[inline] fn next(&mut self) -> Option { @@ -145,9 +145,9 @@ impl<'py> Iterator for PySetIterator<'py> { } #[cfg(not(Py_LIMITED_API))] -impl<'a> std::iter::IntoIterator for &'a PySet { - type Item = &'a PyAny<'a>; - type IntoIter = PySetIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PySet<'py> { + type Item = &'a PyAny<'py>; + type IntoIter = PySetIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { self.iter() @@ -236,17 +236,17 @@ where } } -impl PyFrozenSet { +impl<'py> PyFrozenSet<'py> { /// Creates a new frozenset. /// /// May panic when running out of memory. - pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> PyResult<&'p PyFrozenSet> { + pub fn new(py: Python<'py>, elements: &[T]) -> PyResult { let list = elements.to_object(py); unsafe { py.from_owned_ptr_or_err(ffi::PyFrozenSet_New(list.as_ptr())) } } /// Creates a new empty frozen set - pub fn empty<'p>(py: Python<'p>) -> PyResult<&'p PySet> { + pub fn empty(py: Python<'py>) -> PyResult { unsafe { py.from_owned_ptr_or_err(ffi::PyFrozenSet_New(ptr::null_mut())) } } @@ -287,9 +287,9 @@ impl PyFrozenSet { } #[cfg(not(Py_LIMITED_API))] -impl<'a> std::iter::IntoIterator for &'a PyFrozenSet { - type Item = &'a PyAny<'a>; - type IntoIter = PySetIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PyFrozenSet<'py> { + type Item = &'a PyAny<'py>; + type IntoIter = PySetIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { PySetIterator { diff --git a/src/types/slice.rs b/src/types/slice.rs index 7a0cdf71c23..2a8c01f1f39 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -5,6 +5,7 @@ use crate::ffi::{self, Py_ssize_t}; use crate::instance::PyNativeType; use crate::internal_tricks::Unsendable; use crate::object::PyObject; +use crate::types::PyAny; use crate::Python; use crate::{AsPyPointer, ToPyObject}; use std::os::raw::c_long; @@ -13,7 +14,7 @@ use std::os::raw::c_long; /// /// Only `c_long` indices supported at the moment by the `PySlice` object. #[repr(transparent)] -pub struct PySlice(PyObject, Unsendable); +pub struct PySlice<'py>(PyAny<'py>); pyobject_native_type!( PySlice, @@ -41,9 +42,9 @@ impl PySliceIndices { } } -impl PySlice { +impl<'py> PySlice<'py> { /// Constructs a new slice with the given elements. - pub fn new(py: Python, start: isize, stop: isize, step: isize) -> &PySlice { + pub fn new(py: Python<'py>, start: isize, stop: isize, step: isize) -> Self { unsafe { let ptr = ffi::PySlice_New( ffi::PyLong_FromLong(start as c_long), diff --git a/src/types/string.rs b/src/types/string.rs index 51d519ff0a0..1f5af3bb083 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -15,21 +15,21 @@ use std::str; /// /// This type is immutable. #[repr(transparent)] -pub struct PyString(PyObject, Unsendable); +pub struct PyString<'py>(PyAny<'py>); pyobject_native_var_type!(PyString, ffi::PyUnicode_Type, ffi::PyUnicode_Check); -impl PyString { +impl<'py> PyString<'py> { /// Creates a new Python string object. /// /// Panics if out of memory. - pub fn new<'p>(py: Python<'p>, s: &str) -> &'p PyString { + pub fn new(py: Python<'py>, s: &str) -> Self { let ptr = s.as_ptr() as *const c_char; let len = s.len() as ffi::Py_ssize_t; unsafe { py.from_owned_ptr(ffi::PyUnicode_FromStringAndSize(ptr, len)) } } - pub fn from_object<'p>(src: &'p PyAny, encoding: &str, errors: &str) -> PyResult<&'p PyString> { + pub fn from_object(src: &'_ PyAny<'py>, encoding: &str, errors: &str) -> PyResult { unsafe { src.py() .from_owned_ptr_or_err::(ffi::PyUnicode_FromEncodedObject( diff --git a/src/types/tuple.rs b/src/types/tuple.rs index b692b11dbba..564d0740ea9 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -12,13 +12,13 @@ use std::slice; /// /// This type is immutable. #[repr(transparent)] -pub struct PyTuple(PyObject, Unsendable); +pub struct PyTuple<'py>(PyAny<'py>); pyobject_native_var_type!(PyTuple, ffi::PyTuple_Type, ffi::PyTuple_Check); -impl PyTuple { +impl<'py> PyTuple<'py> { /// Constructs a new tuple with the given elements. - pub fn new(py: Python, elements: impl IntoIterator) -> &PyTuple + pub fn new(py: Python<'py>, elements: impl IntoIterator) -> Self where T: ToPyObject, U: ExactSizeIterator, @@ -35,7 +35,7 @@ impl PyTuple { } /// Constructs an empty tuple (on the Python side, a singleton object). - pub fn empty(py: Python) -> &PyTuple { + pub fn empty(py: Python<'py>) -> Self { unsafe { py.from_owned_ptr(ffi::PyTuple_New(0)) } } @@ -53,12 +53,12 @@ impl PyTuple { } /// Takes a slice of the tuple pointed from `low` to `high` and returns it as a new tuple. - pub fn slice(&self, low: isize, high: isize) -> Py { + pub fn slice(&self, low: isize, high: isize) -> Py> { unsafe { Py::from_owned_ptr_or_panic(ffi::PyTuple_GetSlice(self.as_ptr(), low, high)) } } /// Takes a slice of the tuple from `low` to the end and returns it as a new tuple. - pub fn split_from(&self, low: isize) -> Py { + pub fn split_from(&self, low: isize) -> Py> { unsafe { let ptr = ffi::PyTuple_GetSlice(self.as_ptr(), low, ffi::PyTuple_GET_SIZE(self.as_ptr())); @@ -69,7 +69,7 @@ impl PyTuple { /// Gets the tuple item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: usize) -> &PyAny { + pub fn get_item(&self, index: usize) -> &PyAny<'py> { // TODO: reconsider whether we should panic // It's quite inconsistent that this method takes `Python` when `len()` does not. assert!(index < self.len()); @@ -112,7 +112,7 @@ impl<'a> Iterator for PyTupleIterator<'a> { type Item = &'a PyAny<'a>; #[inline] - fn next(&mut self) -> Option<&'a PyAny> { + fn next(&mut self) -> Option<&'a PyAny<'a>> { if self.index < self.slice.len() { let item = self.slice[self.index].as_ref(self.py); self.index += 1; @@ -123,17 +123,17 @@ impl<'a> Iterator for PyTupleIterator<'a> { } } -impl<'a> IntoIterator for &'a PyTuple { - type Item = &'a PyAny<'a>; - type IntoIter = PyTupleIterator<'a>; +impl<'py> IntoIterator for &'py PyTuple<'py> { + type Item = &'py PyAny<'py>; + type IntoIter = PyTupleIterator<'py>; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl<'a> FromPy<&'a PyTuple> for Py { - fn from_py(tuple: &'a PyTuple, _py: Python) -> Py { +impl<'py> FromPy<&'_ PyTuple<'py>> for Py> { + fn from_py(tuple: &PyTuple<'py>, _py: Python) -> Py> { unsafe { Py::from_borrowed_ptr(tuple.as_ptr()) } } } @@ -167,8 +167,8 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ } } - impl <$($T: IntoPy),+> IntoPy> for ($($T,)+) { - fn into_py(self, py: Python) -> Py { + impl <$($T: IntoPy),+> IntoPy>> for ($($T,)+) { + fn into_py(self, py: Python) -> Py> { unsafe { let ptr = ffi::PyTuple_New($length); $(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_py(py).into_ptr());)+ diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index d6da963ebd1..b2910f6f765 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -7,7 +7,7 @@ use crate::ffi; use crate::instance::{Py, PyNativeType}; use crate::internal_tricks::Unsendable; use crate::object::PyObject; -use crate::type_object::PyTypeObject; +use crate::type_object::PyTypeInfo; use crate::types::PyAny; use crate::AsPyPointer; use crate::Python; @@ -23,8 +23,8 @@ pyobject_native_var_type!(PyType, ffi::PyType_Type, ffi::PyType_Check); impl<'py> PyType<'py> { /// Creates a new type object. #[inline] - pub fn new(py: Python<'py>) -> Self { - T::type_object(py).clone() + pub fn new(py: Python<'py>) -> Self { + py.from_owned_ptr(T::type_object() as *const _ as *mut ffi::PyTypeObject as _) } /// Retrieves the underlying FFI pointer associated with this Python object. @@ -37,7 +37,7 @@ impl<'py> PyType<'py> { /// This increments the reference count on the type object. /// Undefined behavior if the pointer is NULL or invalid. #[inline] - pub unsafe fn from_type_ptr(py: Python, p: *mut ffi::PyTypeObject) -> &PyType { + pub unsafe fn from_type_ptr(py: Python<'py>, p: *mut ffi::PyTypeObject) -> &Self { py.from_borrowed_ptr(p as *mut ffi::PyObject) } @@ -51,9 +51,9 @@ impl<'py> PyType<'py> { /// Equivalent to Python's `issubclass` function. pub fn is_subclass(&self) -> PyResult where - T: PyTypeObject, + T: PyTypeInfo, { - let result = unsafe { ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object().as_ptr()) }; + let result = unsafe { ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object() as *const _ as *mut ffi::PyTypeObject as _)}; if result == -1 { Err(PyErr::fetch(self.py())) } else if result == 1 { From cd416b0b9245b048bf883d7399514946b7853337 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 29 Apr 2020 09:35:53 +0100 Subject: [PATCH 03/11] After many trait lifetimes --- src/class/basic.rs | 2 +- src/class/buffer.rs | 6 +- src/class/context.rs | 2 +- src/class/descr.rs | 2 +- src/class/gc.rs | 2 +- src/class/iter.rs | 6 +- src/class/mapping.rs | 2 +- src/class/number.rs | 2 +- src/class/pyasync.rs | 2 +- src/conversion.rs | 28 ++++---- src/derive_utils.rs | 26 +++---- src/freelist.rs | 4 +- src/instance.rs | 36 +++++----- src/pycell.rs | 154 ++++++++++++++++++++-------------------- src/pyclass.rs | 6 +- src/pyclass_init.rs | 56 +++++++-------- src/type_object.rs | 2 +- src/types/any.rs | 2 +- src/types/mod.rs | 14 ++-- src/types/module.rs | 2 +- src/types/typeobject.rs | 4 +- 21 files changed, 180 insertions(+), 180 deletions(-) diff --git a/src/class/basic.rs b/src/class/basic.rs index 74057bb57c5..eb8aecee92b 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -29,7 +29,7 @@ pub enum CompareOp { /// Basic Python class customization #[allow(unused_variables)] -pub trait PyObjectProtocol<'p>: PyClass { +pub trait PyObjectProtocol<'p>: PyClass<'p> { fn __getattr__(&'p self, name: Self::Name) -> Self::Result where Self: PyObjectGetAttrProtocol<'p>, diff --git a/src/class/buffer.rs b/src/class/buffer.rs index d812cbfbe92..ffc4fc77211 100644 --- a/src/class/buffer.rs +++ b/src/class/buffer.rs @@ -14,15 +14,15 @@ use std::os::raw::c_int; /// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html) /// c-api #[allow(unused_variables)] -pub trait PyBufferProtocol<'p>: PyClass { - fn bf_getbuffer(slf: PyRefMut, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result +pub trait PyBufferProtocol<'p>: PyClass<'p> { + fn bf_getbuffer(slf: PyRefMut<'_, 'p, Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result where Self: PyBufferGetBufferProtocol<'p>, { unimplemented!() } - fn bf_releasebuffer(slf: PyRefMut, view: *mut ffi::Py_buffer) -> Self::Result + fn bf_releasebuffer(slf: PyRefMut<'_, 'p, Self>, view: *mut ffi::Py_buffer) -> Self::Result where Self: PyBufferReleaseBufferProtocol<'p>, { diff --git a/src/class/context.rs b/src/class/context.rs index 9a9e0e98167..649ea75134d 100644 --- a/src/class/context.rs +++ b/src/class/context.rs @@ -10,7 +10,7 @@ use crate::{PyClass, PyObject}; /// Context manager interface #[allow(unused_variables)] -pub trait PyContextProtocol<'p>: PyClass { +pub trait PyContextProtocol<'p>: PyClass<'p> { fn __enter__(&'p mut self) -> Self::Result where Self: PyContextEnterProtocol<'p>, diff --git a/src/class/descr.rs b/src/class/descr.rs index fb36b72a23e..b4cc24e3ac7 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -13,7 +13,7 @@ use std::os::raw::c_int; /// Descriptor interface #[allow(unused_variables)] -pub trait PyDescrProtocol<'p>: PyClass { +pub trait PyDescrProtocol<'p>: PyClass<'p> { fn __get__(&'p self, instance: &'p PyAny, owner: Option<&'p PyType>) -> Self::Result where Self: PyDescrGetProtocol<'p>, diff --git a/src/class/gc.rs b/src/class/gc.rs index 040a6352410..4f1c9ea9340 100644 --- a/src/class/gc.rs +++ b/src/class/gc.rs @@ -10,7 +10,7 @@ use std::os::raw::{c_int, c_void}; pub struct PyTraverseError(c_int); /// GC support -pub trait PyGCProtocol<'p>: PyClass { +pub trait PyGCProtocol<'p>: PyClass<'p> { fn __traverse__(&'p self, visit: PyVisit) -> Result<(), PyTraverseError>; fn __clear__(&'p mut self); } diff --git a/src/class/iter.rs b/src/class/iter.rs index 08c12963df3..9bf8ebd35fc 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -12,7 +12,7 @@ use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python}; /// Check [CPython doc](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter) /// for more. #[allow(unused_variables)] -pub trait PyIterProtocol<'p>: PyClass { +pub trait PyIterProtocol<'p>: PyClass<'p> { fn __iter__(slf: Self::Receiver) -> Self::Result where Self: PyIterIterProtocol<'p>, @@ -29,13 +29,13 @@ pub trait PyIterProtocol<'p>: PyClass { } pub trait PyIterIterProtocol<'p>: PyIterProtocol<'p> { - type Receiver: TryFromPyCell<'p, Self>; + type Receiver: for<'a> TryFromPyCell<'a, 'p, Self>; type Success: crate::IntoPy; type Result: Into>; } pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> { - type Receiver: TryFromPyCell<'p, Self>; + type Receiver: for<'a> TryFromPyCell<'a, 'p, Self>; type Success: crate::IntoPy; type Result: Into>>; } diff --git a/src/class/mapping.rs b/src/class/mapping.rs index 4d82a9dd5fc..dd0841fbf0a 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -9,7 +9,7 @@ use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject}; /// Mapping interface #[allow(unused_variables)] -pub trait PyMappingProtocol<'p>: PyClass { +pub trait PyMappingProtocol<'p>: PyClass<'p> { fn __len__(&'p self) -> Self::Result where Self: PyMappingLenProtocol<'p>, diff --git a/src/class/number.rs b/src/class/number.rs index 207a5b3a6a0..5bcc047c4e0 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -10,7 +10,7 @@ use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject}; /// Number interface #[allow(unused_variables)] -pub trait PyNumberProtocol<'p>: PyClass { +pub trait PyNumberProtocol<'p>: PyClass<'p> { fn __add__(lhs: Self::Left, rhs: Self::Right) -> Self::Result where Self: PyNumberAddProtocol<'p>, diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index a43dc57cd85..4ea76cc32d7 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -16,7 +16,7 @@ use crate::{ffi, PyClass, PyObject}; /// /// Each method in this trait corresponds to Python async/await implementation. #[allow(unused_variables)] -pub trait PyAsyncProtocol<'p>: PyClass { +pub trait PyAsyncProtocol<'p>: PyClass<'p> { fn __await__(&'p self) -> Self::Result where Self: PyAsyncAwaitProtocol<'p>, diff --git a/src/conversion.rs b/src/conversion.rs index a330fab18ac..8a42ed3fe9a 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -252,40 +252,40 @@ where } } -impl<'a, T> FromPyObject<'a> for &'a PyCell<'a, T> +impl<'py, T> FromPyObject<'py> for &PyCell<'py, T> where - T: PyClass, + T: PyClass<'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &PyAny<'py>) -> PyResult { PyTryFrom::try_from(obj).map_err(Into::into) } } -impl<'a, T> FromPyObject<'a> for T +impl<'py, T> FromPyObject<'py> for T where - T: PyClass + Clone, + T: PyClass<'py> + Clone, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &PyAny<'py>) -> PyResult { let cell: &PyCell = PyTryFrom::try_from(obj)?; Ok(unsafe { cell.try_borrow_unguarded()?.clone() }) } } -impl<'a, T> FromPyObject<'a> for PyRef<'a, T> +impl<'a, 'py, T> FromPyObject<'py> for PyRef<'a, 'py, T> where - T: PyClass, + T: PyClass<'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { let cell: &PyCell = PyTryFrom::try_from(obj)?; cell.try_borrow().map_err(Into::into) } } -impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T> +impl<'a, 'py, T> FromPyObject<'a> for PyRefMut<'a, 'py, T> where - T: PyClass, + T: PyClass<'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { let cell: &PyCell = PyTryFrom::try_from(obj)?; cell.try_borrow_mut().map_err(Into::into) } @@ -348,7 +348,7 @@ where impl<'py, T> PyTryFrom<'py> for T where - T: PyDowncastImpl<'py> + PyTypeInfo + PyNativeType<'py>, + T: PyDowncastImpl<'py> + PyTypeInfo<'py> + PyNativeType<'py>, { fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { @@ -378,7 +378,7 @@ where impl<'py, T> PyTryFrom<'py> for PyCell<'py, T> where - T: 'py + PyClass, + T: 'py + PyClass<'py>, { fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { let value = value.into(); diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 61d3f637af7..7cacb425895 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -179,17 +179,17 @@ impl> IntoPyResult for PyResult { /// Variant of IntoPyResult for the specific case of `#[new]`. In the case of returning (Sub, Base) /// from `#[new]`, IntoPyResult can't apply because (Sub, Base) doesn't implement IntoPy. -pub trait IntoPyNewResult>> { +pub trait IntoPyNewResult<'py, T: PyClass<'py>, I: Into>> { fn into_pynew_result(self) -> PyResult; } -impl>> IntoPyNewResult for I { +impl<'py, T: PyClass<'py>, I: Into>> IntoPyNewResult<'py, T, I> for I { fn into_pynew_result(self) -> PyResult { Ok(self) } } -impl>> IntoPyNewResult for PyResult { +impl<'py, T: PyClass<'py>, I: Into>> IntoPyNewResult<'py, T, I> for PyResult { fn into_pynew_result(self) -> PyResult { self } @@ -223,17 +223,17 @@ impl GetPropertyValue for Py { /// Utilities for basetype #[doc(hidden)] -pub trait PyBaseTypeUtils { +pub trait PyBaseTypeUtils<'py> { type Dict; type WeakRef; type LayoutAsBase; type BaseNativeType; } -impl PyBaseTypeUtils for T { +impl<'py, T: PyClass<'py>> PyBaseTypeUtils<'py> for T { type Dict = T::Dict; type WeakRef = T::WeakRef; - type LayoutAsBase = crate::pycell::PyCellInner; + type LayoutAsBase = crate::pycell::PyCellInner<'py, T>; type BaseNativeType = T::BaseNativeType; } @@ -255,19 +255,19 @@ where /// This serves to unify the use of `PyRef` and `PyRefMut` in automatically /// derived code, since both types can be obtained from a `PyCell`. #[doc(hidden)] -pub trait TryFromPyCell<'a, T: PyClass>: Sized { +pub trait TryFromPyCell<'a, 'py: 'a, T: PyClass<'py>>: Sized { type Error: Into; - fn try_from_pycell(cell: &'a crate::PyCell) -> Result; + fn try_from_pycell(cell: &'a crate::PyCell<'py, T>) -> Result; } -impl<'a, T, R> TryFromPyCell<'a, T> for R +impl<'a, 'py: 'a, T, R> TryFromPyCell<'a, 'py, T> for R where - T: 'a + PyClass, - R: std::convert::TryFrom<&'a PyCell<'a, T>>, + T: 'py + PyClass<'py>, + R: std::convert::TryFrom<&'a PyCell<'py, T>>, R::Error: Into, { type Error = R::Error; - fn try_from_pycell(cell: &'a crate::PyCell) -> Result { - >>::try_from(cell) + fn try_from_pycell(cell: &'a crate::PyCell<'py, T>) -> Result { + >>::try_from(cell) } } diff --git a/src/freelist.rs b/src/freelist.rs index d3a4ae4e413..aa5caf26f9c 100644 --- a/src/freelist.rs +++ b/src/freelist.rs @@ -68,9 +68,9 @@ impl FreeList { } } -impl PyClassAlloc for T +impl<'py, T> PyClassAlloc<'py> for T where - T: PyTypeInfo + PyClassWithFreeList, + T: PyTypeInfo<'py> + PyClassWithFreeList, { unsafe fn alloc(_py: Python) -> *mut Self::Layout { if let Some(obj) = ::get_free_list().pop() { diff --git a/src/instance.rs b/src/instance.rs index 6fa644b6e8b..709da13cfc2 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -47,10 +47,10 @@ impl Py { /// This method is **soft-duplicated** since PyO3 0.9.0. /// Use [`PyCell::new`](../pycell/struct.PyCell.html#method.new) and /// `Py::from` instead. - pub fn new(py: Python, value: impl Into>) -> PyResult> + pub fn new<'py>(py: Python<'py>, value: impl Into>) -> PyResult> where - T: PyClass, - T::BaseLayout: PyBorrowFlagLayout, + T: PyClass<'py>, + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { let initializer = value.into(); let obj = unsafe { initializer.create_cell(py)? }; @@ -172,7 +172,7 @@ pub trait AsPyRef<'p>: Sized { impl<'p, T> AsPyRef<'p> for Py where - T: PyTypeInfo, + T: PyTypeInfo<'p>, T::AsRefTarget: 'p, { type Target = T::AsRefTarget; @@ -226,29 +226,29 @@ where } // `&PyCell` can be converted to `Py` -impl<'a, T> std::convert::From<&PyCell<'_, T>> for Py +impl<'py, T> std::convert::From<&PyCell<'py, T>> for Py where - T: PyClass, + T: PyClass<'py>, { - fn from(cell: &PyCell) -> Self { + fn from(cell: &PyCell<'py, T>) -> Self { unsafe { Py::from_borrowed_ptr(cell.as_ptr()) } } } -impl<'a, T> std::convert::From> for Py +impl<'py, T> std::convert::From> for Py where - T: PyClass, + T: PyClass<'py>, { - fn from(pyref: PyRef<'a, T>) -> Self { + fn from(pyref: PyRef<'_, 'py, T>) -> Self { unsafe { Py::from_borrowed_ptr(pyref.as_ptr()) } } } -impl<'a, T> std::convert::From> for Py +impl<'py, T> std::convert::From> for Py where - T: PyClass, + T: PyClass<'py>, { - fn from(pyref: PyRefMut<'a, T>) -> Self { + fn from(pyref: PyRefMut<'_, 'py, T>) -> Self { unsafe { Py::from_borrowed_ptr(pyref.as_ptr()) } } } @@ -276,14 +276,14 @@ impl std::convert::From> for PyObject { } } -impl<'a, T> FromPyObject<'a> for Py +impl<'a, 'py, T> FromPyObject<'py> for Py where - T: PyTypeInfo, - &'a T::AsRefTarget: FromPyObject<'a>, - T::AsRefTarget: 'a + AsPyPointer, + T: PyTypeInfo<'py>, + &'a T::AsRefTarget: FromPyObject<'py>, + T::AsRefTarget: 'py + AsPyPointer, { /// Extracts `Self` from the source `PyObject`. - fn extract(ob: &'a PyAny) -> PyResult { + fn extract(ob: &PyAny<'py>) -> PyResult { unsafe { ob.extract::<&T::AsRefTarget>() .map(|val| Py::from_borrowed_ptr(val.as_ptr())) diff --git a/src/pycell.rs b/src/pycell.rs index 6e7f66420ea..8d4bba3e07f 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -15,31 +15,31 @@ use std::ptr::NonNull; /// This is necessary for sharing BorrowFlag between parents and children. #[doc(hidden)] #[repr(C)] -pub struct PyCellBase { +pub struct PyCellBase<'py, T: PyTypeInfo<'py>> { ob_base: T::Layout, borrow_flag: Cell, } -unsafe impl<'py, T> PyLayout for PyCellBase +unsafe impl<'py, T> PyLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo + PyNativeType<'py>, - T::Layout: PySizedLayout, + T: PyTypeInfo<'py> + PyNativeType<'py>, + T::Layout: PySizedLayout<'py, T>, { const IS_NATIVE_TYPE: bool = true; } // Thes impls ensures `PyCellBase` can be a base type. -impl<'py, T> PySizedLayout for PyCellBase +impl<'py, T> PySizedLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo + PyNativeType<'py>, - T::Layout: PySizedLayout, + T: PyTypeInfo<'py> + PyNativeType<'py>, + T::Layout: PySizedLayout<'py, T>, { } -unsafe impl<'py, T> PyBorrowFlagLayout for PyCellBase +unsafe impl<'py, T> PyBorrowFlagLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo + PyNativeType<'py>, - T::Layout: PySizedLayout, + T: PyTypeInfo<'py> + PyNativeType<'py>, + T::Layout: PySizedLayout<'py, T>, { } @@ -49,18 +49,18 @@ where /// 2. When `#[pyclass(extends=Base)]` is specified, `PyCellInner` is used as a base layout. #[doc(hidden)] #[repr(C)] -pub struct PyCellInner { +pub struct PyCellInner<'py, T: PyClass<'py>> { ob_base: T::BaseLayout, value: ManuallyDrop>, } -impl AsPyPointer for PyCellInner { +impl<'py, T: PyClass<'py>> AsPyPointer for PyCellInner<'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { (self as *const _) as *mut _ } } -unsafe impl PyLayout for PyCellInner { +unsafe impl<'py, T: PyClass<'py>> PyLayout<'py, T> for PyCellInner<'py, T> { const IS_NATIVE_TYPE: bool = false; fn get_super(&mut self) -> Option<&mut T::BaseLayout> { Some(&mut self.ob_base) @@ -75,10 +75,10 @@ unsafe impl PyLayout for PyCellInner { } // These impls ensures `PyCellInner` can be a base type. -impl PySizedLayout for PyCellInner {} -unsafe impl PyBorrowFlagLayout for PyCellInner {} +impl<'py, T: PyClass<'py>> PySizedLayout<'py, T> for PyCellInner<'py, T> {} +unsafe impl<'py, T: PyClass<'py>> PyBorrowFlagLayout<'py, T> for PyCellInner<'py, T> {} -impl PyCellInner { +impl<'py, T: PyClass<'py>> PyCellInner<'py, T> { unsafe fn get_ptr(&self) -> *mut T { self.value.get() } @@ -92,18 +92,18 @@ impl PyCellInner { } } #[repr(C)] -pub struct PyCellLayout { - inner: PyCellInner, +pub struct PyCellLayout<'py, T: PyClass<'py>> { + inner: PyCellInner<'py, T>, dict: T::Dict, weakref: T::WeakRef, } -impl PyCellLayout { +impl<'py, T: PyClass<'py>> PyCellLayout<'py, T> { /// Allocates new PyCell without initilizing value. /// Requires `T::BaseLayout: PyBorrowFlagLayout` to ensure `self` has a borrow flag. pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self> where - T::BaseLayout: PyBorrowFlagLayout, + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { let base = T::alloc(py); if base.is_null() { @@ -118,7 +118,7 @@ impl PyCellLayout { } } -unsafe impl PyLayout for PyCellLayout { +unsafe impl<'py, T: PyClass<'py>> PyLayout<'py, T> for PyCellLayout<'py, T> { const IS_NATIVE_TYPE: bool = false; fn get_super(&mut self) -> Option<&mut T::BaseLayout> { Some(&mut self.inner.ob_base) @@ -197,14 +197,14 @@ unsafe impl PyLayout for PyCellLayout { /// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1"); /// ``` #[repr(transparent)] -pub struct PyCell<'py, T: PyClass>(PyAny<'py>, PhantomData>); +pub struct PyCell<'py, T: PyClass<'py>>(PyAny<'py>, PhantomData>); -impl<'py, T: PyClass> PyCell<'py, T> { +impl<'py, T: PyClass<'py>> PyCell<'py, T> { /// Make new `PyCell` on the Python heap and returns the reference of it. /// - pub fn new(py: Python<'py>, value: impl Into>) -> PyResult + pub fn new(py: Python<'py>, value: impl Into>) -> PyResult where - T::BaseLayout: PyBorrowFlagLayout, + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { unsafe { let initializer = value.into(); @@ -219,7 +219,7 @@ impl<'py, T: PyClass> PyCell<'py, T> { /// /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use /// [`try_borrow`](#method.try_borrow). - pub fn borrow(&self) -> PyRef<'_, T> { + pub fn borrow(&self) -> PyRef<'_, 'py, T> { self.try_borrow().expect("Already mutably borrowed") } @@ -229,7 +229,7 @@ impl<'py, T: PyClass> PyCell<'py, T> { /// /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use /// [`try_borrow_mut`](#method.try_borrow_mut). - pub fn borrow_mut(&self) -> PyRefMut<'_, T> { + pub fn borrow_mut(&self) -> PyRefMut<'_, 'py, T> { self.try_borrow_mut().expect("Already borrowed") } @@ -257,7 +257,7 @@ impl<'py, T: PyClass> PyCell<'py, T> { /// assert!(c.try_borrow().is_ok()); /// } /// ``` - pub fn try_borrow(&self) -> Result, PyBorrowError> { + pub fn try_borrow(&self) -> Result, PyBorrowError> { let inner = self.inner(); let flag = inner.get_borrow_flag(); if flag == BorrowFlag::HAS_MUTABLE_BORROW { @@ -289,7 +289,7 @@ impl<'py, T: PyClass> PyCell<'py, T> { /// /// assert!(c.try_borrow_mut().is_ok()); /// ``` - pub fn try_borrow_mut(&self) -> Result, PyBorrowMutError> { + pub fn try_borrow_mut(&self) -> Result, PyBorrowMutError> { let inner = self.inner(); if inner.get_borrow_flag() != BorrowFlag::UNUSED { Err(PyBorrowMutError { _private: () }) @@ -369,14 +369,14 @@ impl<'py, T: PyClass> PyCell<'py, T> { } #[inline] - fn inner(&self) -> &PyCellInner { + fn inner(&self) -> &PyCellInner<'py, T> { unsafe { &*(self.as_ptr() as *const PyCellInner) } } } unsafe impl<'p, T> FromPyPointer<'p> for PyCell<'p, T> where - T: PyClass, + T: PyClass<'p>, { unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { NonNull::new(ptr).map(|p| Self(PyAny::from_not_null(py, p))) @@ -389,26 +389,26 @@ where } } -unsafe impl<'py, T: PyClass> PyDowncastImpl<'py> for PyCell<'py, T> { +unsafe impl<'py, T: PyClass<'py>> PyDowncastImpl<'py> for PyCell<'py, T> { unsafe fn unchecked_downcast<'a>(obj: &'a PyAny) -> &'a Self { &*(obj.as_ptr() as *const Self) } private_impl! {} } -impl AsPyPointer for PyCell<'_, T> { +impl<'py, T: PyClass<'py>> AsPyPointer for PyCell<'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { self.inner.as_ptr() } } -impl ToPyObject for &PyCell<'_, T> { +impl<'py, T: PyClass<'py>> ToPyObject for &PyCell<'py, T> { fn to_object(&self, py: Python<'_>) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } } } -impl fmt::Debug for PyCell<'_, T> { +impl<'py, T: PyClass<'py> + fmt::Debug> fmt::Debug for PyCell<'py, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.try_borrow() { Ok(borrow) => f.debug_struct("PyCell").field("value", &borrow).finish(), @@ -464,32 +464,32 @@ impl fmt::Debug for PyCell<'_, T> { /// # let sub = PyCell::new(py, Child::new()).unwrap(); /// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'"); /// ``` -pub struct PyRef<'p, T: PyClass> { - inner: &'p PyCellInner, +pub struct PyRef<'a, 'py, T: PyClass<'py>> { + inner: &'a PyCellInner<'py, T>, } -impl<'p, T: PyClass> PyRef<'p, T> { +impl<'py, T: PyClass<'py>> PyRef<'_, 'py, T> { /// Returns `Python` token. /// This function is safe since PyRef has the same lifetime as a `GILGuard`. - pub fn py(&self) -> Python { + pub fn py(&self) -> Python<'py> { unsafe { Python::assume_gil_acquired() } } } -impl<'p, T, U> AsRef for PyRef<'p, T> +impl<'py, T, U> AsRef for PyRef<'_, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + U: PyClass<'py>, { fn as_ref(&self) -> &T::BaseType { unsafe { &*self.inner.ob_base.get_ptr() } } } -impl<'p, T, U> PyRef<'p, T> +impl<'a, 'py, T, U> PyRef<'a, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + U: PyClass<'py>, { /// Get `PyRef`. /// You can use this method to get super class of super class. @@ -528,7 +528,7 @@ where /// # let sub = PyCell::new(py, Sub::new()).unwrap(); /// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'") /// ``` - pub fn into_super(self) -> PyRef<'p, U> { + pub fn into_super(self) -> PyRef<'a, 'py, U> { let PyRef { inner } = self; std::mem::forget(self); PyRef { @@ -537,7 +537,7 @@ where } } -impl<'p, T: PyClass> Deref for PyRef<'p, T> { +impl<'py, T: PyClass<'py>> Deref for PyRef<'_, 'py, T> { type Target = T; #[inline] @@ -546,33 +546,33 @@ impl<'p, T: PyClass> Deref for PyRef<'p, T> { } } -impl<'p, T: PyClass> Drop for PyRef<'p, T> { +impl<'py, T: PyClass<'py>> Drop for PyRef<'_, 'py, T> { fn drop(&mut self) { let flag = self.inner.get_borrow_flag(); self.inner.set_borrow_flag(flag.decrement()) } } -impl<'p, T: PyClass> FromPy> for PyObject { - fn from_py(pyref: PyRef<'p, T>, py: Python<'_>) -> PyObject { +impl<'py, T: PyClass<'py>> FromPy> for PyObject { + fn from_py(pyref: PyRef<'_, 'py, T>, py: Python<'_>) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) } } } -impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<'_, T>> for crate::PyRef<'a, T> { +impl<'a, 'py, T: PyClass<'py>> std::convert::TryFrom<&'a PyCell<'py, T>> for PyRef<'a, 'py, T> { type Error = PyBorrowError; - fn try_from(cell: &'a crate::PyCell) -> Result { + fn try_from(cell: &'a PyCell<'py, T>) -> Result { cell.try_borrow() } } -impl<'a, T: PyClass> AsPyPointer for PyRef<'a, T> { +impl<'a, 'py, T: PyClass<'py>> AsPyPointer for PyRef<'a, 'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { self.inner.as_ptr() } } -impl fmt::Debug for PyRef<'_, T> { +impl<'py, T: PyClass<'py> + fmt::Debug> fmt::Debug for PyRef<'_, 'py, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } @@ -581,46 +581,46 @@ impl fmt::Debug for PyRef<'_, T> { /// Wraps a mutable borrowed reference to a value in a `PyCell`. /// /// See the [`PyCell`](struct.PyCell.html) and [`PyRef`](struct.PyRef.html) documentations for more. -pub struct PyRefMut<'p, T: PyClass> { - inner: &'p PyCellInner, +pub struct PyRefMut<'a, 'py, T: PyClass<'py>> { + inner: &'a PyCellInner<'py, T>, } -impl<'p, T: PyClass> PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> PyRefMut<'_, 'py, T> { /// Returns `Python` token. /// This function is safe since PyRefMut has the same lifetime as a `GILGuard`. - pub fn py(&self) -> Python { + pub fn py(&self) -> Python<'py> { unsafe { Python::assume_gil_acquired() } } } -impl<'p, T, U> AsRef for PyRefMut<'p, T> +impl<'py, T, U> AsRef for PyRefMut<'_, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + U: PyClass<'py>, { fn as_ref(&self) -> &T::BaseType { unsafe { &*self.inner.ob_base.get_ptr() } } } -impl<'p, T, U> AsMut for PyRefMut<'p, T> +impl<'py, T, U> AsMut for PyRefMut<'_, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + U: PyClass<'py>, { fn as_mut(&mut self) -> &mut T::BaseType { unsafe { &mut *self.inner.ob_base.get_ptr() } } } -impl<'p, T, U> PyRefMut<'p, T> +impl<'a, 'py, T, U> PyRefMut<'a, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + U: PyClass<'py>, { /// Get `PyRef`. /// See [`PyRef::into_super`](struct.PyRef.html#method.into_super) for more. - pub fn into_super(self) -> PyRefMut<'p, U> { + pub fn into_super(self) -> PyRefMut<'a, 'py, U> { let PyRefMut { inner } = self; std::mem::forget(self); PyRefMut { @@ -629,7 +629,7 @@ where } } -impl<'p, T: PyClass> Deref for PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> Deref for PyRefMut<'_, 'py, T> { type Target = T; #[inline] @@ -638,39 +638,39 @@ impl<'p, T: PyClass> Deref for PyRefMut<'p, T> { } } -impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> DerefMut for PyRefMut<'_, 'py, T> { #[inline] fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.inner.get_ptr() } } } -impl<'p, T: PyClass> Drop for PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> Drop for PyRefMut<'_, 'py, T> { fn drop(&mut self) { self.inner.set_borrow_flag(BorrowFlag::UNUSED) } } -impl<'p, T: PyClass> FromPy> for PyObject { - fn from_py(pyref: PyRefMut<'p, T>, py: Python<'_>) -> PyObject { +impl<'py, T: PyClass<'py>> FromPy> for PyObject { + fn from_py(pyref: PyRefMut<'_, 'py, T>, py: Python<'_>) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) } } } -impl<'a, T: PyClass> AsPyPointer for PyRefMut<'a, T> { +impl<'py, T: PyClass<'py>> AsPyPointer for PyRefMut<'_, 'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { self.inner.as_ptr() } } -impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<'_, T>> for crate::PyRefMut<'a, T> { +impl<'a, 'py, T: PyClass<'py>> std::convert::TryFrom<&'a PyCell<'py, T>> for PyRefMut<'a, 'py, T> { type Error = PyBorrowMutError; - fn try_from(cell: &'a crate::PyCell) -> Result { + fn try_from(cell: &'a PyCell<'py, T>) -> Result { cell.try_borrow_mut() } } -impl fmt::Debug for PyRefMut<'_, T> { +impl<'py, T: PyClass<'py> + fmt::Debug> fmt::Debug for PyRefMut<'_, 'py, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&*(self.deref()), f) } diff --git a/src/pyclass.rs b/src/pyclass.rs index 5cc3cd73aa8..a75104bc79d 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -72,7 +72,7 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) { /// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you don't have to use this trait directly. pub trait PyClass<'py>: - PyTypeInfo<'py, Layout = PyCellLayout> + Sized + PyClassAlloc<'py> + PyMethodsProtocol + PyTypeInfo<'py, Layout = PyCellLayout<'py, Self>> + Sized + PyClassAlloc<'py> + PyMethodsProtocol { /// Specify this class has `#[pyclass(dict)]` or not. type Dict: PyClassDict; @@ -80,7 +80,7 @@ pub trait PyClass<'py>: type WeakRef: PyClassWeakRef; /// The closest native ancestor. This is `PyAny` by default, and when you declare /// `#[pyclass(extends=PyDict)]`, it's `PyDict`. - type BaseNativeType: PyTypeInfo<'py> + PyNativeType<'static>; + type BaseNativeType: PyTypeInfo<'py> + PyNativeType<'py>; } #[cfg(not(Py_LIMITED_API))] @@ -202,7 +202,7 @@ where } } -fn py_class_flags(type_object: &mut ffi::PyTypeObject) { +fn py_class_flags PyTypeInfo<'py>>(type_object: &mut ffi::PyTypeObject) { if type_object.tp_traverse != None || type_object.tp_clear != None || T::FLAGS & type_flags::GC != 0 diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index 70db7227748..e19d6e102e3 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -8,16 +8,16 @@ use std::marker::PhantomData; /// /// This trait is intended to use internally for distinguishing `#[pyclass]` and /// Python native types. -pub trait PyObjectInit: Sized { - fn init_class>(self, layout: &mut L); +pub trait PyObjectInit<'py, T: PyTypeInfo<'py>>: Sized { + fn init_class>(self, layout: &mut L); private_decl! {} } /// Initializer for Python native type, like `PyDict`. -pub struct PyNativeTypeInitializer(PhantomData); +pub struct PyNativeTypeInitializer<'py, T: PyTypeInfo<'py>>(PhantomData, PhantomData>); -impl PyObjectInit for PyNativeTypeInitializer { - fn init_class>(self, _layout: &mut L) {} +impl<'py, T: PyTypeInfo<'py>> PyObjectInit<'py, T> for PyNativeTypeInitializer<'py, T> { + fn init_class>(self, _layout: &mut L) {} private_impl! {} } @@ -64,16 +64,16 @@ impl PyObjectInit for PyNativeTypeInitializer { /// assert inst.subname == 'sub' /// assert inst.subsubname == 'subsub'"#); /// ``` -pub struct PyClassInitializer { +pub struct PyClassInitializer<'py, T: PyClass<'py>> { init: T, - super_init: ::Initializer, + super_init: >::Initializer, } -impl PyClassInitializer { +impl<'py, T: PyClass<'py>> PyClassInitializer<'py, T> { /// Constract new initialzer from value `T` and base class' initializer. /// /// We recommend to mainly use `add_subclass`, instead of directly call `new`. - pub fn new(init: T, super_init: ::Initializer) -> Self { + pub fn new(init: T, super_init: >::Initializer) -> Self { Self { init, super_init } } @@ -106,21 +106,21 @@ impl PyClassInitializer { /// } /// } /// ``` - pub fn add_subclass(self, subclass_value: S) -> PyClassInitializer + pub fn add_subclass(self, subclass_value: S) -> PyClassInitializer<'py, S> where - S: PyClass + PyTypeInfo, - S::BaseLayout: PySizedLayout, - S::BaseType: PyTypeInfo, + S: PyClass<'py> + PyTypeInfo<'py, BaseType = T>, + S::BaseLayout: PySizedLayout<'py, T>, + S::BaseType: PyTypeInfo<'py, Initializer = Self>, { PyClassInitializer::new(subclass_value, self) } // Create a new PyCell + initialize it #[doc(hidden)] - pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCellLayout> + pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCellLayout<'py, T>> where - T: PyClass, - T::BaseLayout: PyBorrowFlagLayout, + T: PyClass<'py>, + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { let cell = PyCellLayout::new(py)?; self.init_class(&mut *cell); @@ -128,8 +128,8 @@ impl PyClassInitializer { } } -impl PyObjectInit for PyClassInitializer { - fn init_class>(self, layout: &mut L) { +impl<'py, T: PyClass<'py>> PyObjectInit<'py, T> for PyClassInitializer<'py, T> { + fn init_class>(self, layout: &mut L) { let Self { init, super_init } = self; unsafe { layout.py_init(init); @@ -141,24 +141,24 @@ impl PyObjectInit for PyClassInitializer { private_impl! {} } -impl From for PyClassInitializer +impl<'py, T> From for PyClassInitializer<'py, T> where - T: PyClass, - T::BaseType: PyTypeInfo>, + T: PyClass<'py>, + T::BaseType: PyTypeInfo<'py, Initializer = PyNativeTypeInitializer<'py, T::BaseType>>, { - fn from(value: T) -> PyClassInitializer { + fn from(value: T) -> PyClassInitializer<'py, T> { Self::new(value, PyNativeTypeInitializer(PhantomData)) } } -impl From<(S, B)> for PyClassInitializer +impl<'py, S, B> From<(S, B)> for PyClassInitializer<'py, S> where - S: PyClass + PyTypeInfo, - S::BaseLayout: PySizedLayout, - B: PyClass + PyTypeInfo>, - B::BaseType: PyTypeInfo>, + S: PyClass<'py> + PyTypeInfo<'py, BaseType = B>, + S::BaseLayout: PySizedLayout<'py, B>, + B: PyClass<'py> + PyTypeInfo<'py, Initializer = PyClassInitializer<'py, B>>, + B::BaseType: PyTypeInfo<'py, Initializer = PyNativeTypeInitializer<'py, B::BaseType>>, { - fn from(sub_and_base: (S, B)) -> PyClassInitializer { + fn from(sub_and_base: (S, B)) -> PyClassInitializer<'py, S> { let (sub, base) = sub_and_base; PyClassInitializer::from(base).add_subclass(sub) } diff --git a/src/type_object.rs b/src/type_object.rs index 10273f38e11..0f31a791047 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -121,7 +121,7 @@ pub unsafe trait PyTypeInfo<'py>: Sized { type BaseLayout: PySizedLayout<'py, Self::BaseType>; /// Initializer for layout - type Initializer: PyObjectInit; + type Initializer: PyObjectInit<'py, Self>; /// Utility type to make AsPyRef work type AsRefTarget: PyDowncastImpl<'py>; diff --git a/src/types/any.rs b/src/types/any.rs index 42bf622952d..232830b6882 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -35,7 +35,7 @@ use std::ptr::NonNull; #[repr(transparent)] pub struct PyAny<'a>(NonNull, PhantomData<&'a ffi::PyObject>); -impl crate::type_object::PySizedLayout> for ffi::PyObject {} +impl<'py> crate::type_object::PySizedLayout<'py, PyAny<'py>> for ffi::PyObject {} pyobject_native_type_named!(PyAny); pyobject_native_type_info!( PyAny, diff --git a/src/types/mod.rs b/src/types/mod.rs index 59ae7ce983f..c23b032d074 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -88,11 +88,11 @@ macro_rules! pyobject_native_type_named ( #[macro_export] macro_rules! pyobject_native_type { ($name: ident, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - impl $crate::type_object::PySizedLayout<$name<'_>> for $layout {} - impl $crate::derive_utils::PyBaseTypeUtils for $name<'_> { + impl<'py> $crate::type_object::PySizedLayout<'py, $name<'py>> for $layout {} + impl<'py> $crate::derive_utils::PyBaseTypeUtils<'py> for $name<'py> { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; - type LayoutAsBase = $crate::pycell::PyCellBase; + type LayoutAsBase = $crate::pycell::PyCellBase<'py, Self>; type BaseNativeType = Self; } pyobject_native_type_named!($name $(,$type_param)*); @@ -141,14 +141,14 @@ macro_rules! pyobject_native_type_extract { macro_rules! pyobject_native_type_info( ($name: ident, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name<'_>> for $layout {} + unsafe impl<'py> $crate::type_object::PyLayout<'py, $name<'py>> for $layout {} - unsafe impl<'a, $($type_param,)*> $crate::type_object::PyTypeInfo for $name<'_> { + unsafe impl<'py, $($type_param,)*> $crate::type_object::PyTypeInfo<'py> for $name<'py> { type Type = (); - type BaseType = $crate::PyAny<'static>; + type BaseType = $crate::PyAny<'py>; type Layout = $layout; type BaseLayout = ffi::PyObject; - type Initializer = $crate::pyclass_init::PyNativeTypeInitializer; + type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<'py, Self>; type AsRefTarget = Self; const NAME: &'static str = stringify!($name); diff --git a/src/types/module.rs b/src/types/module.rs index 1f45b5cd401..f3618b87b6a 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -174,7 +174,7 @@ impl<'py> PyModule<'py> { /// and adds the type to this module. pub fn add_class(&self) -> PyResult<()> where - T: PyClass, + T: PyClass<'py>, { self.add(T::NAME, ::type_object()) } diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index b2910f6f765..9eaf6fe6e2e 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -23,7 +23,7 @@ pyobject_native_var_type!(PyType, ffi::PyType_Type, ffi::PyType_Check); impl<'py> PyType<'py> { /// Creates a new type object. #[inline] - pub fn new(py: Python<'py>) -> Self { + pub fn new>(py: Python<'py>) -> Self { py.from_owned_ptr(T::type_object() as *const _ as *mut ffi::PyTypeObject as _) } @@ -51,7 +51,7 @@ impl<'py> PyType<'py> { /// Equivalent to Python's `issubclass` function. pub fn is_subclass(&self) -> PyResult where - T: PyTypeInfo, + T: PyTypeInfo<'py>, { let result = unsafe { ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object() as *const _ as *mut ffi::PyTypeObject as _)}; if result == -1 { From bf7736764e28029cb40579613044b76ca273e631 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 29 Apr 2020 12:44:26 +0100 Subject: [PATCH 04/11] Add borrow lifetime to FromPyObject --- src/class/basic.rs | 12 ++-- src/class/context.rs | 6 +- src/class/descr.rs | 12 ++-- src/class/mapping.rs | 8 +-- src/class/number.rs | 118 ++++++++++++++++++++-------------------- src/class/pyasync.rs | 6 +- src/class/sequence.rs | 18 +++--- src/conversion.rs | 22 ++++---- src/derive_utils.rs | 8 +-- src/instance.rs | 6 +- src/object.rs | 12 ++-- src/objectprotocol.rs | 10 ++-- src/types/boolobject.rs | 4 +- src/types/bytes.rs | 2 +- src/types/dict.rs | 16 +++--- src/types/floatob.rs | 8 +-- src/types/mod.rs | 2 +- src/types/num.rs | 16 +++--- src/types/sequence.rs | 30 +++++----- src/types/set.rs | 12 ++-- src/types/string.rs | 10 ++-- src/types/tuple.rs | 4 +- 22 files changed, 171 insertions(+), 171 deletions(-) diff --git a/src/class/basic.rs b/src/class/basic.rs index eb8aecee92b..6bd800a3e3e 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -102,17 +102,17 @@ pub trait PyObjectProtocol<'p>: PyClass<'p> { } pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: FromPyObject<'p>; + type Name: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: FromPyObject<'p>; - type Value: FromPyObject<'p>; + type Name: for<'a> FromPyObject<'a, 'p>; + type Value: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: FromPyObject<'p>; + type Name: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyObjectStrProtocol<'p>: PyObjectProtocol<'p> { @@ -124,7 +124,7 @@ pub trait PyObjectReprProtocol<'p>: PyObjectProtocol<'p> { type Result: Into>; } pub trait PyObjectFormatProtocol<'p>: PyObjectProtocol<'p> { - type Format: FromPyObject<'p>; + type Format: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } @@ -139,7 +139,7 @@ pub trait PyObjectBytesProtocol<'p>: PyObjectProtocol<'p> { type Result: Into>; } pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } diff --git a/src/class/context.rs b/src/class/context.rs index 649ea75134d..5c38201aa75 100644 --- a/src/class/context.rs +++ b/src/class/context.rs @@ -37,9 +37,9 @@ pub trait PyContextEnterProtocol<'p>: PyContextProtocol<'p> { } pub trait PyContextExitProtocol<'p>: PyContextProtocol<'p> { - type ExcType: crate::FromPyObject<'p>; - type ExcValue: crate::FromPyObject<'p>; - type Traceback: crate::FromPyObject<'p>; + type ExcType: for<'a> crate::FromPyObject<'a, 'p>; + type ExcValue: for<'a> crate::FromPyObject<'a, 'p>; + type Traceback: for<'a> crate::FromPyObject<'a, 'p>; type Success: crate::IntoPy; type Result: Into>; } diff --git a/src/class/descr.rs b/src/class/descr.rs index b4cc24e3ac7..d0a5da91543 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -44,25 +44,25 @@ pub trait PyDescrProtocol<'p>: PyClass<'p> { } pub trait PyDescrGetProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; - type Owner: FromPyObject<'p>; + type Inst: for<'a> FromPyObject<'a, 'p>; + type Owner: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyDescrSetProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; - type Value: FromPyObject<'p>; + type Inst: for<'a> FromPyObject<'a, 'p>; + type Value: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyDescrDeleteProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; + type Inst: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; + type Inst: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } diff --git a/src/class/mapping.rs b/src/class/mapping.rs index dd0841fbf0a..5e7e3d9120c 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -54,19 +54,19 @@ pub trait PyMappingLenProtocol<'p>: PyMappingProtocol<'p> { } pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: FromPyObject<'p>; + type Key: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: FromPyObject<'p>; - type Value: FromPyObject<'p>; + type Key: for<'a> FromPyObject<'a, 'p>; + type Value: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: FromPyObject<'p>; + type Key: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } diff --git a/src/class/number.rs b/src/class/number.rs index 5bcc047c4e0..62706cfe305 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -318,256 +318,256 @@ pub trait PyNumberProtocol<'p>: PyClass<'p> { } pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberMulProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberTruedivProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberModProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberPowProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; - type Modulo: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; + type Modulo: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberLShiftProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberAndProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberXorProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberOrProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: for<'a> FromPyObject<'a, 'p>; + type Right: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRAddProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRSubProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRMulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRTruedivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRModProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRPowProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; - type Modulo: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; + type Modulo: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRLShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRAndProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRXorProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } @@ -608,7 +608,7 @@ pub trait PyNumberFloatProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberRoundProtocol<'p>: PyNumberProtocol<'p> { type Success: IntoPy; - type NDigits: FromPyObject<'p>; + type NDigits: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index 4ea76cc32d7..8db56db7f94 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -79,9 +79,9 @@ pub trait PyAsyncAenterProtocol<'p>: PyAsyncProtocol<'p> { } pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> { - type ExcType: crate::FromPyObject<'p>; - type ExcValue: crate::FromPyObject<'p>; - type Traceback: crate::FromPyObject<'p>; + type ExcType: for<'a> crate::FromPyObject<'a, 'p>; + type ExcValue: for<'a> crate::FromPyObject<'a, 'p>; + type Traceback: for<'a> crate::FromPyObject<'a, 'p>; type Success: crate::IntoPy; type Result: Into>; } diff --git a/src/class/sequence.rs b/src/class/sequence.rs index 8472729db02..b26ff4d1583 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -85,46 +85,46 @@ pub trait PySequenceLenProtocol<'p>: PySequenceProtocol<'p> { } pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; + type Index: for<'a> FromPyObject<'a, 'p> + From; type Success: IntoPy; type Result: Into>; } pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; - type Value: FromPyObject<'p>; + type Index: for<'a> FromPyObject<'a, 'p> + From; + type Value: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; + type Index: for<'a> FromPyObject<'a, 'p> + From; type Result: Into>; } pub trait PySequenceContainsProtocol<'p>: PySequenceProtocol<'p> { - type Item: FromPyObject<'p>; + type Item: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PySequenceConcatProtocol<'p>: PySequenceProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; + type Index: for<'a> FromPyObject<'a, 'p> + From; type Success: IntoPy; type Result: Into>; } pub trait PySequenceInplaceConcatProtocol<'p>: PySequenceProtocol<'p> + IntoPy { - type Other: FromPyObject<'p>; + type Other: for<'a> FromPyObject<'a, 'p>; type Result: Into>; } pub trait PySequenceInplaceRepeatProtocol<'p>: PySequenceProtocol<'p> + IntoPy { - type Index: FromPyObject<'p> + From; + type Index: for<'a> FromPyObject<'a, 'p> + From; type Result: Into>; } diff --git a/src/conversion.rs b/src/conversion.rs index 8a42ed3fe9a..56d063e4d48 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -186,9 +186,9 @@ impl FromPy for T { /// /// The trait's conversion method takes a `&PyAny` argument but is called /// `FromPyObject` for historical reasons. -pub trait FromPyObject<'source>: Sized { +pub trait FromPyObject<'a, 'py>: Sized { /// Extracts `Self` from the source `PyObject`. - fn extract(ob: &'source PyAny) -> PyResult; + fn extract(ob: &'a PyAny<'py>) -> PyResult; } /// Identity conversion: allows using existing `PyObject` instances where @@ -252,26 +252,26 @@ where } } -impl<'py, T> FromPyObject<'py> for &PyCell<'py, T> +impl<'a, 'py, T> FromPyObject<'a, 'py> for &'a PyCell<'py, T> where T: PyClass<'py>, { - fn extract(obj: &PyAny<'py>) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { PyTryFrom::try_from(obj).map_err(Into::into) } } -impl<'py, T> FromPyObject<'py> for T +impl<'py, T> FromPyObject<'_, 'py> for T where T: PyClass<'py> + Clone, { - fn extract(obj: &PyAny<'py>) -> PyResult { + fn extract(obj: &'_ PyAny<'py>) -> PyResult { let cell: &PyCell = PyTryFrom::try_from(obj)?; Ok(unsafe { cell.try_borrow_unguarded()?.clone() }) } } -impl<'a, 'py, T> FromPyObject<'py> for PyRef<'a, 'py, T> +impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRef<'a, 'py, T> where T: PyClass<'py>, { @@ -281,7 +281,7 @@ where } } -impl<'a, 'py, T> FromPyObject<'a> for PyRefMut<'a, 'py, T> +impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRefMut<'a, 'py, T> where T: PyClass<'py>, { @@ -291,11 +291,11 @@ where } } -impl<'a, T> FromPyObject<'a> for Option +impl<'a, 'py, T> FromPyObject<'a, 'py> for Option where - T: FromPyObject<'a>, + T: FromPyObject<'a, 'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { if obj.as_ptr() == unsafe { ffi::Py_None() } { Ok(None) } else { diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 7cacb425895..929314a4318 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -239,13 +239,13 @@ impl<'py, T: PyClass<'py>> PyBaseTypeUtils<'py> for T { /// Utility trait to enable &PyClass as a pymethod/function argument #[doc(hidden)] -pub trait ExtractExt<'a> { - type Target: crate::FromPyObject<'a>; +pub trait ExtractExt<'a, 'py> { + type Target: crate::FromPyObject<'a, 'py>; } -impl<'a, T> ExtractExt<'a> for T +impl<'a, 'py, T> ExtractExt<'a, 'py> for T where - T: crate::FromPyObject<'a>, + T: crate::FromPyObject<'a, 'py>, { type Target = T; } diff --git a/src/instance.rs b/src/instance.rs index 709da13cfc2..33529f06720 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -276,11 +276,11 @@ impl std::convert::From> for PyObject { } } -impl<'a, 'py, T> FromPyObject<'py> for Py +impl<'a, 'py, T> FromPyObject<'a, 'py> for Py where T: PyTypeInfo<'py>, - &'a T::AsRefTarget: FromPyObject<'py>, - T::AsRefTarget: 'py + AsPyPointer, + &'a T::AsRefTarget: FromPyObject<'a, 'py>, + T::AsRefTarget: 'a + 'py + AsPyPointer, { /// Extracts `Self` from the source `PyObject`. fn extract(ob: &PyAny<'py>) -> PyResult { diff --git a/src/object.rs b/src/object.rs index 1d34a3bea8d..d3fb7aea8a9 100644 --- a/src/object.rs +++ b/src/object.rs @@ -156,9 +156,9 @@ impl PyObject { /// Casts the PyObject to a concrete Python object type. /// /// This can cast only to native Python types, not types implemented in Rust. - pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError> + pub fn cast_as<'a, 'py, D>(&'a self, py: Python<'py>) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom<'p>, + D: PyTryFrom<'py>, { D::try_from(self.as_ref(py)) } @@ -166,9 +166,9 @@ impl PyObject { /// Extracts some type from the Python object. /// /// This is a wrapper function around `FromPyObject::extract()`. - pub fn extract<'p, D>(&'p self, py: Python<'p>) -> PyResult + pub fn extract<'a, 'py, D>(&'a self, py: Python<'py>) -> PyResult where - D: FromPyObject<'p>, + D: FromPyObject<'a, 'py>, { FromPyObject::extract(self.as_ref(py)) } @@ -315,10 +315,10 @@ impl PartialEq for PyObject { } } -impl<'a> FromPyObject<'a> for PyObject { +impl<'py> FromPyObject<'_, 'py> for PyObject { #[inline] /// Extracts `Self` from the source `PyObject`. - fn extract(ob: &'a PyAny) -> PyResult { + fn extract(ob: &PyAny<'py>) -> PyResult { unsafe { Ok(PyObject::from_borrowed_ptr(ob.py(), ob.as_ptr())) } } } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 8fe17e29d3d..d8c007b4d13 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -206,8 +206,8 @@ pub trait ObjectProtocol<'py> { /// This is a wrapper function around `FromPyObject::extract()`. fn extract<'a, D>(&'a self) -> PyResult where - D: FromPyObject<'a>, - Self: AsRef>; + D: FromPyObject<'a, 'py>, + Self: AsRef>; /// Returns the reference count for the Python object. fn get_refcnt(&self) -> isize; @@ -468,15 +468,15 @@ where fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where D: PyTryFrom<'a>, - Self: AsRef>, + Self: AsRef>, { D::try_from(self.as_ref()) } fn extract<'a, D>(&'a self) -> PyResult where - D: FromPyObject<'a>, - Self: AsRef>, + D: FromPyObject<'a, 'py>, + Self: AsRef>, { FromPyObject::extract(self.as_ref()) } diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index ae28d50bbd8..2a6dc7895cb 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -52,8 +52,8 @@ impl FromPy for PyObject { /// Converts a Python `bool` to a Rust `bool`. /// /// Fails with `TypeError` if the input is not a Python `bool`. -impl<'source> FromPyObject<'source> for bool { - fn extract(obj: &'source PyAny) -> PyResult { +impl FromPyObject<'_, '_> for bool { + fn extract(obj: &PyAny) -> PyResult { Ok(::try_from(obj)?.is_true()) } } diff --git a/src/types/bytes.rs b/src/types/bytes.rs index b6ba3d35c79..8e23ba362c5 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -64,7 +64,7 @@ impl<'a> FromPy<&'a [u8]> for PyObject { } } -impl<'a> FromPyObject<'a> for &'a [u8] { +impl<'a> FromPyObject<'a, '_> for &'a [u8] { fn extract(obj: &'a PyAny) -> PyResult { Ok(::try_from(obj)?.as_bytes()) } diff --git a/src/types/dict.rs b/src/types/dict.rs index 82c9a437038..f54423e8576 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -319,13 +319,13 @@ where } } -impl<'source, K, V, S> FromPyObject<'source> for HashMap +impl<'a, 'py, K, V, S> FromPyObject<'a, 'py> for HashMap where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, - V: FromPyObject<'source>, + K: FromPyObject<'a, 'py> + cmp::Eq + hash::Hash, + V: FromPyObject<'a, 'py>, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> Result { + fn extract(ob: &'a PyAny<'py>) -> Result { let dict = ::try_from(ob)?; let mut ret = HashMap::default(); for (k, v) in dict.iter() { @@ -335,12 +335,12 @@ where } } -impl<'source, K, V> FromPyObject<'source> for BTreeMap +impl<'a, 'py, K, V> FromPyObject<'a, 'py> for BTreeMap where - K: FromPyObject<'source> + cmp::Ord, - V: FromPyObject<'source>, + K: FromPyObject<'a, 'py> + cmp::Ord, + V: FromPyObject<'a, 'py>, { - fn extract(ob: &'source PyAny) -> Result { + fn extract(ob: &'a PyAny<'py>) -> Result { let dict = ::try_from(ob)?; let mut ret = BTreeMap::new(); for (k, v) in dict.iter() { diff --git a/src/types/floatob.rs b/src/types/floatob.rs index c49586bffd5..d63c6f2f55a 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -48,10 +48,10 @@ impl FromPy for PyObject { } } -impl<'source> FromPyObject<'source> for f64 { +impl FromPyObject<'_, '_> for f64 { // PyFloat_AsDouble returns -1.0 upon failure #![cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp))] - fn extract(obj: &'source PyAny) -> PyResult { + fn extract(obj: &PyAny) -> PyResult { let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) }; if v == -1.0 && PyErr::occurred(obj.py()) { @@ -74,8 +74,8 @@ impl FromPy for PyObject { } } -impl<'source> FromPyObject<'source> for f32 { - fn extract(obj: &'source PyAny) -> PyResult { +impl FromPyObject<'_, '_> for f32 { + fn extract(obj: &PyAny) -> PyResult { Ok(obj.extract::()? as f32) } } diff --git a/src/types/mod.rs b/src/types/mod.rs index c23b032d074..41e1497a524 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -129,7 +129,7 @@ macro_rules! pyobject_native_var_type { // because rust-numpy has a special implementation. macro_rules! pyobject_native_type_extract { ($name: ident $(,$type_param: ident)*) => { - impl<'a, 'py, $($type_param,)*> $crate::FromPyObject<'py> for &'a $name<'py> { + impl<'a, 'py, $($type_param,)*> $crate::FromPyObject<'a, 'py> for &'a $name<'py> { fn extract(obj: &'a $crate::PyAny<'py>) -> $crate::PyResult { $crate::PyTryFrom::try_from(obj).map_err(Into::into) } diff --git a/src/types/num.rs b/src/types/num.rs index 6d6ff5385eb..45399c8f5ad 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -37,8 +37,8 @@ macro_rules! int_fits_larger_int { } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(obj: &'source PyAny) -> PyResult { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(obj: &PyAny) -> PyResult { let val = $crate::objectprotocol::ObjectProtocol::extract::<$larger_type>(obj)?; match cast::<$larger_type, $rust_type>(val) { Some(v) => Ok(v), @@ -78,8 +78,8 @@ macro_rules! int_convert_128 { } } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(ob: &PyAny) -> PyResult<$rust_type> { unsafe { let num = ffi::PyNumber_Index(ob.as_ptr()); if num.is_null() { @@ -134,8 +134,8 @@ macro_rules! int_fits_c_long { } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(obj: &'source PyAny) -> PyResult { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(obj: &PyAny) -> PyResult { let ptr = obj.as_ptr(); let val = unsafe { let num = ffi::PyNumber_Index(ptr); @@ -170,8 +170,8 @@ macro_rules! int_convert_u64_or_i64 { unsafe { PyObject::from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(self)) } } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(ob: &PyAny) -> PyResult<$rust_type> { let ptr = ob.as_ptr(); unsafe { let num = ffi::PyNumber_Index(ptr); diff --git a/src/types/sequence.rs b/src/types/sequence.rs index a7d41edd121..c22eea35e70 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -266,9 +266,9 @@ impl<'py> PySequence<'py> { macro_rules! array_impls { ($($N:expr),+) => { $( - impl<'a, T> FromPyObject<'a> for [T; $N] + impl<'a, 'py, T> FromPyObject<'a, 'py> for [T; $N] where - T: Copy + Default + FromPyObject<'a>, + T: Copy + Default + FromPyObject<'a, 'py>, { default fn extract(obj: &'a PyAny) -> PyResult { let mut array = [T::default(); $N]; @@ -277,11 +277,11 @@ macro_rules! array_impls { } } - impl<'source, T> FromPyObject<'source> for [T; $N] + impl<'a, 'py, T> FromPyObject<'a, 'py> for [T; $N] where - for<'a> T: Copy + Default + FromPyObject<'a> + buffer::Element, + T: Copy + Default + FromPyObject<'a, 'py> + buffer::Element, { - fn extract(obj: &'source PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { let mut array = [T::default(); $N]; // first try buffer protocol if let Ok(buf) = buffer::PyBuffer::get(obj.py(), obj) { @@ -305,20 +305,20 @@ array_impls!( 26, 27, 28, 29, 30, 31, 32 ); -impl<'a, T> FromPyObject<'a> for Vec +impl<'a, 'py, T> FromPyObject<'a, 'py> for Vec where - T: FromPyObject<'a>, + T: FromPyObject<'a, 'py>, { - default fn extract(obj: &'a PyAny) -> PyResult { + default fn extract(obj: &'a PyAny<'py>) -> PyResult { extract_sequence(obj) } } -impl<'source, T> FromPyObject<'source> for Vec +impl<'a, 'py, T> FromPyObject<'a, 'py> for Vec where - for<'a> T: FromPyObject<'a> + buffer::Element + Copy, + T: FromPyObject<'a, 'py> + buffer::Element + Copy, { - fn extract(obj: &'source PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { // first try buffer protocol if let Ok(buf) = buffer::PyBuffer::get(obj.py(), obj) { if buf.dimensions() == 1 { @@ -334,9 +334,9 @@ where } } -fn extract_sequence<'s, T>(obj: &'s PyAny) -> PyResult> +fn extract_sequence<'a, 'py, T>(obj: &'a PyAny<'py>) -> PyResult> where - T: FromPyObject<'s>, + T: FromPyObject<'a, 'py>, { let seq = ::try_from(obj)?; let mut v = Vec::with_capacity(seq.len().unwrap_or(0) as usize); @@ -346,9 +346,9 @@ where Ok(v) } -fn extract_sequence_into_slice<'s, T>(obj: &'s PyAny, slice: &mut [T]) -> PyResult<()> +fn extract_sequence_into_slice<'a, 'py, T>(obj: &'a PyAny<'py>, slice: &mut [T]) -> PyResult<()> where - T: FromPyObject<'s>, + T: FromPyObject<'a, 'py>, { let seq = ::try_from(obj)?; if seq.len()? as usize != slice.len() { diff --git a/src/types/set.rs b/src/types/set.rs index 8a850a6b49a..4e9d5acc885 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -200,12 +200,12 @@ where } } -impl<'source, K, S> FromPyObject<'source> for HashSet +impl<'a, 'py, K, S> FromPyObject<'a, 'py> for HashSet where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, + K: FromPyObject<'a, 'py> + cmp::Eq + hash::Hash, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract(ob: &'a PyAny<'py>) -> PyResult { let set: &PySet = ob.downcast()?; set.iter().map(K::extract).collect() } @@ -226,11 +226,11 @@ where } } -impl<'source, K> FromPyObject<'source> for BTreeSet +impl<'a, 'py, K> FromPyObject<'a, 'py> for BTreeSet where - K: FromPyObject<'source> + cmp::Ord, + K: FromPyObject<'a, 'py> + cmp::Ord, { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract(ob: &'a PyAny<'py>) -> PyResult { let set: &PySet = ob.downcast()?; set.iter().map(K::extract).collect() } diff --git a/src/types/string.rs b/src/types/string.rs index 1f5af3bb083..6a5824b7377 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -144,15 +144,15 @@ impl<'a> IntoPy for &'a String { /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'source> crate::FromPyObject<'source> for Cow<'source, str> { - fn extract(ob: &'source PyAny) -> PyResult { +impl<'a> crate::FromPyObject<'a, '_> for Cow<'a, str> { + fn extract(ob: &'a PyAny) -> PyResult { ::try_from(ob)?.to_string() } } /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'a> crate::FromPyObject<'a> for &'a str { +impl<'a> crate::FromPyObject<'a, '_> for &'a str { fn extract(ob: &'a PyAny) -> PyResult { let s: Cow<'a, str> = crate::FromPyObject::extract(ob)?; match s { @@ -167,8 +167,8 @@ impl<'a> crate::FromPyObject<'a> for &'a str { /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'source> FromPyObject<'source> for String { - fn extract(obj: &'source PyAny) -> PyResult { +impl FromPyObject<'_, '_> for String { + fn extract(obj: &PyAny) -> PyResult { ::try_from(obj)? .to_string() .map(Cow::into_owned) diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 564d0740ea9..32236e19dad 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -177,8 +177,8 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ } } - impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) { - fn extract(obj: &'s PyAny) -> PyResult + impl<'a, 'py, $($T: FromPyObject<'a, 'py>),+> FromPyObject<'a, 'py> for ($($T,)+) { + fn extract(obj: &'a PyAny<'py>) -> PyResult { let t = ::try_from(obj)?; let slice = t.as_slice(); From 3ad88481aa196fceb6953a3908792bdf3a244ab0 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 29 Apr 2020 17:34:11 +0100 Subject: [PATCH 05/11] Clean up many compilation failures --- src/buffer.rs | 2 +- src/conversion.rs | 4 ++-- src/derive_utils.rs | 4 ++-- src/err.rs | 3 +-- src/exceptions.rs | 12 ++++++------ src/instance.rs | 37 ++++++++++++++++++++----------------- src/marshal.rs | 4 ++-- src/object.rs | 10 +++++----- src/objectprotocol.rs | 14 +++++++++----- src/pycell.rs | 6 +++--- src/pyclass.rs | 4 ++-- src/pyclass_init.rs | 4 ++-- src/types/any.rs | 2 -- src/types/boolobject.rs | 1 - src/types/bytearray.rs | 2 -- src/types/bytes.rs | 3 +-- src/types/complex.rs | 14 ++++++-------- src/types/datetime.rs | 1 - src/types/dict.rs | 5 ++--- src/types/floatob.rs | 1 - src/types/iterator.rs | 4 ++-- src/types/list.rs | 21 ++++++++++----------- src/types/mod.rs | 14 +++++++++++--- src/types/module.rs | 1 - src/types/num.rs | 1 - src/types/sequence.rs | 24 +++--------------------- src/types/set.rs | 5 ++--- src/types/slice.rs | 1 - src/types/string.rs | 1 - src/types/tuple.rs | 2 -- src/types/typeobject.rs | 4 +--- 31 files changed, 93 insertions(+), 118 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index cf9b5c1c135..8a62ef16460 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -719,7 +719,7 @@ mod test { .unwrap() .call_method("array", ("f", (1.0, 1.5, 2.0, 2.5)), None) .unwrap(); - let buffer = PyBuffer::get(py, array).unwrap(); + let buffer = PyBuffer::get(py, &array).unwrap(); assert_eq!(buffer.dimensions(), 1); assert_eq!(buffer.item_count(), 4); assert_eq!(buffer.format().to_str().unwrap(), "f"); diff --git a/src/conversion.rs b/src/conversion.rs index 56d063e4d48..589f88f4add 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -5,8 +5,7 @@ use crate::err::{self, PyDowncastError, PyResult}; use crate::object::PyObject; use crate::type_object::{PyDowncastImpl, PyTypeInfo}; use crate::types::PyTuple; -use crate::{ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; -use std::ptr::NonNull; +use crate::{ffi, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; /// This trait represents that **we can do zero-cost conversion from the object /// to a FFI pointer**. @@ -254,6 +253,7 @@ where impl<'a, 'py, T> FromPyObject<'a, 'py> for &'a PyCell<'py, T> where + 'py: 'a, T: PyClass<'py>, { fn extract(obj: &'a PyAny<'py>) -> PyResult { diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 929314a4318..6ecf8a26685 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -40,7 +40,7 @@ pub fn parse_fn_args<'a, 'py>( accept_args: bool, accept_kwargs: bool, output: &mut [Option<&'a PyAny<'py>>], -) -> PyResult<(&'a PyTuple<'py>, Option<&'a PyDict<'py>>)> { +) -> PyResult<(&'a PyTuple<'py>, Option>)> { let nargs = args.len(); let mut used_args = 0; macro_rules! raise_error { @@ -151,7 +151,7 @@ impl ModuleDef { } let module = py.from_owned_ptr_or_err::(module)?; module.add("__doc__", doc)?; - initializer(py, module)?; + initializer(py, &module)?; Ok(crate::IntoPyPointer::into_ptr(module)) } } diff --git a/src/err.rs b/src/err.rs index 275fcb8a1ed..54df0c1daaf 100644 --- a/src/err.rs +++ b/src/err.rs @@ -3,7 +3,6 @@ use crate::type_object::PyTypeObject; use crate::types::PyType; use crate::{exceptions, ffi}; -use crate::instance::PyNativeType; use crate::{ AsPyPointer, FromPy, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToBorrowedObject, ToPyObject, @@ -152,7 +151,7 @@ impl PyErr { } } else { PyErr { - ptype: exceptions::TypeError::type_object(obj.py()).into(), + ptype: exceptions::TypeError::type_object(), pvalue: PyErrValue::ToObject(Box::new("exceptions must derive from BaseException")), ptraceback: None, } diff --git a/src/exceptions.rs b/src/exceptions.rs index 11bae0b8616..294d77384c6 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -89,7 +89,7 @@ macro_rules! import_exception { macro_rules! import_exception_type_object { ($module: expr, $name: ident) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object(py: $crate::Python) -> &$crate::types::PyType { + fn type_object() -> $crate::Py<$crate::types::PyType<'static>> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -111,7 +111,7 @@ macro_rules! import_exception_type_object { } }); - unsafe { py.from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } + unsafe { $crate::Py::from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } } } }; @@ -173,7 +173,7 @@ macro_rules! create_exception { macro_rules! create_exception_type_object { ($module: ident, $name: ident, $base: ty) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object(py: $crate::Python) -> &$crate::types::PyType { + fn type_object() -> $crate::Py<$crate::types::PyType<'static>> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -186,7 +186,7 @@ macro_rules! create_exception_type_object { ) }); - unsafe { py.from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } + unsafe { $crate::Py::from_borrowed_ptr(ptr.as_ptr() as *mut $crate::ffi::PyObject) } } } }; @@ -215,8 +215,8 @@ macro_rules! impl_native_exception ( } } unsafe impl PyTypeObject for $name { - fn type_object(py: Python) -> &$crate::types::PyType { - unsafe { py.from_borrowed_ptr(ffi::$exc_name) } + fn type_object() -> $crate::Py<$crate::types::PyType<'static>> { + unsafe { $crate::Py::from_borrowed_ptr(ffi::$exc_name) } } } ); diff --git a/src/instance.rs b/src/instance.rs index 33529f06720..9fb107a4438 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -2,10 +2,9 @@ use crate::err::{PyErr, PyResult}; use crate::gil; use crate::object::PyObject; -use crate::objectprotocol::ObjectProtocol; use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl}; use crate::{ - ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyCell, PyClass, + ffi, AsPyPointer, IntoPy, IntoPyPointer, PyAny, PyCell, PyClass, PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject, }; use std::marker::PhantomData; @@ -194,7 +193,7 @@ impl IntoPy for Py { /// Consumes `self` without calling `Py_DECREF()`. #[inline] fn into_py(self, _py: Python) -> PyObject { - unsafe { PyObject::from_not_null(self.into_non_null()) } + unsafe { PyObject::from_non_null(self.into_non_null()) } } } @@ -272,23 +271,27 @@ impl Drop for Py { impl std::convert::From> for PyObject { #[inline] fn from(ob: Py) -> Self { - unsafe { PyObject::from_not_null(ob.into_non_null()) } + unsafe { PyObject::from_non_null(ob.into_non_null()) } } } -impl<'a, 'py, T> FromPyObject<'a, 'py> for Py -where - T: PyTypeInfo<'py>, - &'a T::AsRefTarget: FromPyObject<'a, 'py>, - T::AsRefTarget: 'a + 'py + AsPyPointer, -{ - /// Extracts `Self` from the source `PyObject`. - fn extract(ob: &PyAny<'py>) -> PyResult { - unsafe { - ob.extract::<&T::AsRefTarget>() - .map(|val| Py::from_borrowed_ptr(val.as_ptr())) - } - } +// impl<'a, 'py, T> FromPyObject<'a, 'py> for Py +// where +// T: PyTypeInfo<'py>, +// &'a T::AsRefTarget: FromPyObject<'a, 'py>, +// T::AsRefTarget: 'a + 'py + AsPyPointer, +// { +// /// Extracts `Self` from the source `PyObject`. +// fn extract(ob: &PyAny<'py>) -> PyResult { +// unsafe { +// ob.extract::<&T::AsRefTarget>() +// .map(|val| Py::from_borrowed_ptr(val.as_ptr())) +// } +// } +// } + +pub trait Unscoped<'py> { + type NativeType: PyNativeType<'py>; } /// Reference to a converted [ToPyObject]. diff --git a/src/marshal.rs b/src/marshal.rs index a99ec974f79..7f3e0bc69f9 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -62,12 +62,12 @@ mod test { dict.set_item("mies", "wim").unwrap(); dict.set_item("zus", "jet").unwrap(); - let bytes = dumps(py, dict, VERSION) + let bytes = dumps(py, &dict, VERSION) .expect("marshalling failed") .as_bytes(); let deserialized = loads(py, bytes).expect("unmarshalling failed"); - assert!(equal(py, dict, &deserialized)); + assert!(equal(py, &*dict, &deserialized)); } fn equal(_py: Python, a: &impl AsPyPointer, b: &impl AsPyPointer) -> bool { diff --git a/src/object.rs b/src/object.rs index d3fb7aea8a9..15f5023650b 100644 --- a/src/object.rs +++ b/src/object.rs @@ -156,9 +156,9 @@ impl PyObject { /// Casts the PyObject to a concrete Python object type. /// /// This can cast only to native Python types, not types implemented in Rust. - pub fn cast_as<'a, 'py, D>(&'a self, py: Python<'py>) -> Result<&'a D, PyDowncastError> + pub fn cast_as<'a, 'py: 'a, D>(&'a self, py: Python<'py>) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom<'py>, + D: PyTryFrom<'py> { D::try_from(self.as_ref(py)) } @@ -166,9 +166,9 @@ impl PyObject { /// Extracts some type from the Python object. /// /// This is a wrapper function around `FromPyObject::extract()`. - pub fn extract<'a, 'py, D>(&'a self, py: Python<'py>) -> PyResult + pub fn extract<'a, 'py: 'a, D>(&'a self, py: Python<'py>) -> PyResult where - D: FromPyObject<'a, 'py>, + D: FromPyObject<'a, 'py> { FromPyObject::extract(self.as_ref(py)) } @@ -270,7 +270,7 @@ where T: AsPyPointer, { fn from(ob: &'a T) -> Self { - unsafe { PyObject::from_not_null(NonNull::new(ob.as_ptr()).expect("Null ptr")) } + unsafe { PyObject::from_non_null(NonNull::new(ob.as_ptr()).expect("Null ptr")) } } } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index d8c007b4d13..82e7db90f48 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -198,14 +198,16 @@ pub trait ObjectProtocol<'py> { /// This can cast only to native Python types, not types implemented in Rust. fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom<'a>, - Self: AsRef>; + 'py: 'a, + D: PyTryFrom<'py>, + Self: AsRef>; /// Extracts some type from the Python object. /// /// This is a wrapper function around `FromPyObject::extract()`. fn extract<'a, D>(&'a self) -> PyResult where + 'py: 'a, D: FromPyObject<'a, 'py>, Self: AsRef>; @@ -467,14 +469,16 @@ where fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom<'a>, - Self: AsRef>, + 'py: 'a, + D: PyTryFrom<'py>, + Self: AsRef> { D::try_from(self.as_ref()) } fn extract<'a, D>(&'a self) -> PyResult where + 'py: 'a, D: FromPyObject<'a, 'py>, Self: AsRef>, { @@ -534,7 +538,7 @@ mod test { let py = gil.python(); let list = vec![3, 6, 5, 4, 7].to_object(py); let dict = vec![("reverse", true)].into_py_dict(py); - list.call_method(py, "sort", (), Some(dict)).unwrap(); + list.call_method(py, "sort", (), Some(&dict)).unwrap(); assert_eq!(list.extract::>(py).unwrap(), vec![7, 6, 5, 4, 3]); } diff --git a/src/pycell.rs b/src/pycell.rs index 8d4bba3e07f..a7cb0ea238c 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -101,7 +101,7 @@ pub struct PyCellLayout<'py, T: PyClass<'py>> { impl<'py, T: PyClass<'py>> PyCellLayout<'py, T> { /// Allocates new PyCell without initilizing value. /// Requires `T::BaseLayout: PyBorrowFlagLayout` to ensure `self` has a borrow flag. - pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self> + pub(crate) unsafe fn new(py: Python<'py>) -> PyResult<*mut Self> where T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { @@ -379,7 +379,7 @@ where T: PyClass<'p>, { unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { - NonNull::new(ptr).map(|p| Self(PyAny::from_not_null(py, p))) + NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p), PhantomData)) } unsafe fn from_borrowed_ptr_or_opt( py: Python<'p>, @@ -398,7 +398,7 @@ unsafe impl<'py, T: PyClass<'py>> PyDowncastImpl<'py> for PyCell<'py, T> { impl<'py, T: PyClass<'py>> AsPyPointer for PyCell<'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { - self.inner.as_ptr() + self.inner().as_ptr() } } diff --git a/src/pyclass.rs b/src/pyclass.rs index a75104bc79d..27cd0dbf5d8 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -9,7 +9,7 @@ use std::os::raw::c_void; use std::ptr; #[inline] -pub(crate) unsafe fn default_alloc PyTypeInfo<'py>>() -> *mut ffi::PyObject { +pub(crate) unsafe fn default_alloc<'py, T: PyTypeInfo<'py>>() -> *mut ffi::PyObject { let type_obj = T::type_object(); // if the class derives native types(e.g., PyDict), call special new if T::FLAGS & type_flags::EXTENDED != 0 && T::BaseLayout::IS_NATIVE_TYPE { @@ -71,7 +71,7 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) { /// /// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you don't have to use this trait directly. -pub trait PyClass<'py>: +pub trait PyClass<'py>: 'static + PyTypeInfo<'py, Layout = PyCellLayout<'py, Self>> + Sized + PyClassAlloc<'py> + PyMethodsProtocol { /// Specify this class has `#[pyclass(dict)]` or not. diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index e19d6e102e3..a486706f7e5 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -117,7 +117,7 @@ impl<'py, T: PyClass<'py>> PyClassInitializer<'py, T> { // Create a new PyCell + initialize it #[doc(hidden)] - pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCellLayout<'py, T>> + pub unsafe fn create_cell(self, py: Python<'py>) -> PyResult<*mut PyCellLayout<'py, T>> where T: PyClass<'py>, T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, @@ -147,7 +147,7 @@ where T::BaseType: PyTypeInfo<'py, Initializer = PyNativeTypeInitializer<'py, T::BaseType>>, { fn from(value: T) -> PyClassInitializer<'py, T> { - Self::new(value, PyNativeTypeInitializer(PhantomData)) + Self::new(value, PyNativeTypeInitializer(PhantomData, PhantomData)) } } diff --git a/src/types/any.rs b/src/types/any.rs index 232830b6882..16f7ea7a53c 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -3,8 +3,6 @@ use crate::err::PyDowncastError; use crate::ffi; use crate::gil; use crate::python::Python; -use crate::type_object::PyTypeInfo; -use crate::pyclass_init::PyNativeTypeInitializer; use std::marker::PhantomData; use std::ptr::NonNull; diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 2a6dc7895cb..7891a98248b 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -1,5 +1,4 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, ToPyObject, diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 9200363ea68..7c6dffd8422 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -2,8 +2,6 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; -use crate::object::PyObject; use crate::types::PyAny; use crate::AsPyPointer; use crate::Python; diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 8e23ba362c5..fc01e08df48 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -1,4 +1,3 @@ -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, ToPyObject, @@ -81,7 +80,7 @@ mod test { let py = gil.python(); let py_bytes = py.eval("b'Hello Python'", None, None).unwrap(); - let bytes: &[u8] = FromPyObject::extract(py_bytes).unwrap(); + let bytes: &[u8] = FromPyObject::extract(&py_bytes).unwrap(); assert_eq!(bytes, b"Hello Python"); } diff --git a/src/types/complex.rs b/src/types/complex.rs index ff0f68d1da2..c348c2ea9ed 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -1,10 +1,8 @@ use crate::ffi; #[cfg(not(PyPy))] use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; use crate::types::PyAny; use crate::AsPyPointer; -use crate::PyObject; use crate::Python; #[cfg(not(PyPy))] use std::ops::*; @@ -251,7 +249,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l + r; + let res = &l + &r; assert_approx_eq!(res.real(), 4.0); assert_approx_eq!(res.imag(), 3.8); } @@ -263,7 +261,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l - r; + let res = &l - &r; assert_approx_eq!(res.real(), 2.0); assert_approx_eq!(res.imag(), -1.4); } @@ -275,7 +273,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l * r; + let res = &l * &r; assert_approx_eq!(res.real(), -0.12); assert_approx_eq!(res.imag(), 9.0); } @@ -287,7 +285,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l / r; + let res = &l / &r; assert_approx_eq!(res.real(), 0.788_659_793_814_432_9); assert_approx_eq!(res.imag(), -0.850_515_463_917_525_7); } @@ -298,7 +296,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let val = PyComplex::from_doubles(py, 3.0, 1.2); - let res = -val; + let res = -&val; assert_approx_eq!(res.real(), -3.0); assert_approx_eq!(res.imag(), -1.2); } @@ -319,7 +317,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.2, 2.6); - let val = l.pow(r); + let val = l.pow(&r); assert_approx_eq!(val.real(), -1.419_309_997_016_603_7); assert_approx_eq!(val.imag(), -0.541_297_466_033_544_6); } diff --git a/src/types/datetime.rs b/src/types/datetime.rs index e8ba5b6945c..58437edb12b 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -25,7 +25,6 @@ use crate::ffi::{ PyDateTime_TIME_GET_HOUR, PyDateTime_TIME_GET_MICROSECOND, PyDateTime_TIME_GET_MINUTE, PyDateTime_TIME_GET_SECOND, }; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::types::{PyAny, PyTuple}; use crate::AsPyPointer; diff --git a/src/types/dict.rs b/src/types/dict.rs index f54423e8576..bfc0185517b 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -2,7 +2,6 @@ use crate::err::{self, PyErr, PyResult}; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::types::{PyAny, PyList}; use crate::AsPyPointer; @@ -170,7 +169,7 @@ impl<'py> PyDict<'py> { /// /// Note that it's unsafe to use when the dictionary might be changed by /// other code. - pub fn iter<'a>(&'a self) -> PyDictIterator<'a, 'py> { + pub fn iter(&self) -> PyDictIterator<'_, 'py> { PyDictIterator { dict: self, pos: 0, @@ -393,7 +392,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let items = PyList::new(py, &vec!["a", "b"]); - assert!(PyDict::from_sequence(py, items.to_object(py)).is_err()); + assert!(PyDict::from_sequence(py, &items).is_err()); } #[test] diff --git a/src/types/floatob.rs b/src/types/floatob.rs index d63c6f2f55a..6bb0e9f8b51 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -1,7 +1,6 @@ // Copyright (c) 2017-present PyO3 Project and Contributors // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, ObjectProtocol, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject, diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 0a717e2a8c7..d9a0e18c661 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -173,9 +173,9 @@ mod tests { let py = gil.python(); let context = PyDict::new(py); - py.run(fibonacci_generator, None, Some(context)).unwrap(); + py.run(fibonacci_generator, None, Some(&context)).unwrap(); - let generator = py.eval("fibonacci(5)", None, Some(context)).unwrap(); + let generator = py.eval("fibonacci(5)", None, Some(&context)).unwrap(); for (actual, expected) in generator.iter().unwrap().zip(&[1, 1, 2, 3, 5]) { let actual = actual.unwrap().extract::().unwrap(); assert_eq!(actual, *expected) diff --git a/src/types/list.rs b/src/types/list.rs index 93b6f77c549..5caae0c2f13 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -4,7 +4,6 @@ use crate::err::{self, PyResult}; use crate::ffi::{self, Py_ssize_t}; -use crate::internal_tricks::Unsendable; use crate::{ AsPyPointer, IntoPy, IntoPyPointer, PyAny, PyNativeType, PyObject, Python, ToBorrowedObject, ToPyObject, @@ -54,7 +53,7 @@ impl<'py> PyList<'py> { /// Gets the item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: isize) -> &PyAny { + pub fn get_item(&self, index: isize) -> &PyAny<'py> { unsafe { self.py() .from_borrowed_ptr(ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t)) @@ -111,7 +110,7 @@ impl<'py> PyList<'py> { } /// Returns an iterator over this list's items. - pub fn iter(&self) -> PyListIterator { + pub fn iter(&self) -> PyListIterator<'_, 'py> { PyListIterator { list: self, index: 0, @@ -130,16 +129,16 @@ impl<'py> PyList<'py> { } /// Used by `PyList::iter()`. -pub struct PyListIterator<'a> { - list: &'a PyList<'a>, +pub struct PyListIterator<'a, 'py> { + list: &'a PyList<'py>, index: isize, } -impl<'a> Iterator for PyListIterator<'a> { - type Item = &'a PyAny<'a>; +impl<'a, 'py> Iterator for PyListIterator<'a, 'py> { + type Item = &'a PyAny<'py>; #[inline] - fn next(&mut self) -> Option<&'a PyAny> { + fn next(&mut self) -> Option<&'a PyAny<'py>> { if self.index < self.list.len() as isize { let item = self.list.get_item(self.index); self.index += 1; @@ -150,9 +149,9 @@ impl<'a> Iterator for PyListIterator<'a> { } } -impl<'a> std::iter::IntoIterator for &'a PyList<'a> { - type Item = &'a PyAny<'a>; - type IntoIter = PyListIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PyList<'py> { + type Item = &'a PyAny<'py>; + type IntoIter = PyListIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { self.iter() diff --git a/src/types/mod.rs b/src/types/mod.rs index 41e1497a524..ded8b5fd1d5 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -38,6 +38,14 @@ macro_rules! pyobject_native_type_named ( } } + impl<$($type_param,)*> $crate::IntoPyPointer for $name<'_> { + /// Gets the underlying FFI pointer, returns a borrowed pointer. + #[inline] + fn into_ptr(self) -> *mut $crate::ffi::PyObject { + self.into_non_null().as_ptr() + } + } + impl<$($type_param,)*> PartialEq for $name<'_> { #[inline] fn eq(&self, o: &$name) -> bool { @@ -96,7 +104,7 @@ macro_rules! pyobject_native_type { type BaseNativeType = Self; } pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_newtype!($name, $(,$type_param)*); + pyobject_native_newtype!($name $(,$type_param)*); pyobject_native_type_info!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); pyobject_native_type_extract!($name $(,$type_param)*); @@ -113,7 +121,7 @@ macro_rules! pyobject_native_type { macro_rules! pyobject_native_var_type { ($name: ident, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_newtype!($name, $(,$type_param)*); + pyobject_native_newtype!($name $(,$type_param)*); pyobject_native_type_info!($name, $crate::ffi::PyObject, $typeobject, $module, $checkfunction $(,$type_param)*); pyobject_native_type_extract!($name $(,$type_param)*); @@ -176,7 +184,7 @@ macro_rules! pyobject_native_type_info( #[macro_export] macro_rules! pyobject_native_newtype( - ($name: ident, $(,$type_param: ident)*) => { + ($name: ident $(,$type_param: ident)*) => { impl<'a, $($type_param,)*> ::std::convert::From<&'a $name<'a>> for &'a $crate::PyAny<'a> { fn from(ob: &'a $name) -> Self { unsafe{&*(ob as *const $name as *const $crate::PyAny)} diff --git a/src/types/module.rs b/src/types/module.rs index f3618b87b6a..35c43ec6a60 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -6,7 +6,6 @@ use crate::err::{PyErr, PyResult}; use crate::exceptions; use crate::ffi; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::pyclass::PyClass; diff --git a/src/types/num.rs b/src/types/num.rs index 45399c8f5ad..38279592886 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -2,7 +2,6 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::internal_tricks::Unsendable; use crate::{ exceptions, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject, diff --git a/src/types/sequence.rs b/src/types/sequence.rs index c22eea35e70..913a2ffeb4f 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -1,26 +1,21 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::buffer; -use crate::conversion::FromPyPointer; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions; -use crate::gil; use crate::ffi::{self, Py_ssize_t}; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; -use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::types::{PyAny, PyList, PyTuple}; -use crate::type_object::PyDowncastImpl; use crate::AsPyPointer; -use crate::{FromPyObject, PyTryFrom, ToBorrowedObject, Python}; -use std::ptr::NonNull; +use crate::{FromPyObject, PyTryFrom, ToBorrowedObject}; /// Represents a reference to a Python object supporting the sequence protocol. #[repr(transparent)] pub struct PySequence<'py>(PyAny<'py>); pyobject_native_type_named!(PySequence); pyobject_native_type_extract!(PySequence); +pyobject_native_newtype!(PySequence); impl<'py> PySequence<'py> { /// Returns the number of objects in sequence. @@ -270,7 +265,7 @@ macro_rules! array_impls { where T: Copy + Default + FromPyObject<'a, 'py>, { - default fn extract(obj: &'a PyAny) -> PyResult { + default fn extract(obj: &'a PyAny<'py>) -> PyResult { let mut array = [T::default(); $N]; extract_sequence_into_slice(obj, &mut array)?; Ok(array) @@ -384,19 +379,6 @@ impl<'py> PyTryFrom<'py> for PySequence<'py> { } } -unsafe impl<'py> FromPyPointer<'py> for PySequence<'py> -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'py>, ptr: *mut ffi::PyObject) -> Option { - NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p))) - } - unsafe fn from_borrowed_ptr_or_opt( - py: Python<'py>, - ptr: *mut ffi::PyObject, - ) -> Option<&'py Self> { - NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p))) - } -} - #[cfg(test)] mod test { use crate::instance::AsPyRef; diff --git a/src/types/set.rs b/src/types/set.rs index 4e9d5acc885..82f61e530e0 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -2,7 +2,6 @@ // use crate::err::{self, PyErr, PyResult}; -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyNativeType, PyObject, Python, ToBorrowedObject, ToPyObject, @@ -406,7 +405,7 @@ mod test { } // intoiterator iteration - for el in set { + for el in &set { assert_eq!(1i32, el.extract().unwrap()); } } @@ -452,7 +451,7 @@ mod test { } // intoiterator iteration - for el in set { + for el in &set { assert_eq!(1i32, el.extract::().unwrap()); } } diff --git a/src/types/slice.rs b/src/types/slice.rs index 2a8c01f1f39..1fe17929986 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -3,7 +3,6 @@ use crate::err::{PyErr, PyResult}; use crate::ffi::{self, Py_ssize_t}; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::types::PyAny; use crate::Python; diff --git a/src/types/string.rs b/src/types/string.rs index 6a5824b7377..5079e609236 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -1,6 +1,5 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::internal_tricks::Unsendable; use crate::{ ffi, gil, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, PyTryFrom, Python, ToPyObject, diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 32236e19dad..dc54f4f62bb 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -1,7 +1,6 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::ffi::{self, Py_ssize_t}; -use crate::internal_tricks::Unsendable; use crate::{ exceptions, AsPyPointer, AsPyRef, FromPy, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyNativeType, PyObject, PyResult, PyTryFrom, Python, ToPyObject, @@ -260,7 +259,6 @@ mod test { let py = gil.python(); let ob = PyTuple::new(py, &[1, 2, 3]); assert_eq!(3, ob.len()); - let ob: &PyAny = ob.into(); assert_eq!((1, 2, 3), ob.extract().unwrap()); let mut map = HashSet::new(); diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 9eaf6fe6e2e..931035f363e 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -4,9 +4,7 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; -use crate::instance::{Py, PyNativeType}; -use crate::internal_tricks::Unsendable; -use crate::object::PyObject; +use crate::instance::PyNativeType; use crate::type_object::PyTypeInfo; use crate::types::PyAny; use crate::AsPyPointer; From e099346497211c09fb63f5b698f7d3bbf837788a Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 29 Apr 2020 21:11:45 +0100 Subject: [PATCH 06/11] Main lib passing tests! --- src/conversion.rs | 9 ++-- src/derive_utils.rs | 106 +++++++++++++++++++++------------------- src/err.rs | 5 +- src/exceptions.rs | 13 ++--- src/instance.rs | 38 +++++++------- src/lib.rs | 1 + src/marshal.rs | 6 +-- src/object.rs | 21 ++++---- src/objectprotocol.rs | 19 +++---- src/pycell.rs | 3 +- src/python.rs | 6 +-- src/type_object.rs | 7 +-- src/types/any.rs | 4 +- src/types/dict.rs | 2 +- src/types/iterator.rs | 30 ++++++++++-- src/types/mod.rs | 8 ++- src/types/module.rs | 8 +-- src/types/sequence.rs | 32 ++++++------ src/types/tuple.rs | 17 ++++--- src/types/typeobject.rs | 4 +- src/unscoped.rs | 28 +++++++++++ 21 files changed, 221 insertions(+), 146 deletions(-) create mode 100644 src/unscoped.rs diff --git a/src/conversion.rs b/src/conversion.rs index 589f88f4add..18fc9fe0265 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -5,6 +5,7 @@ use crate::err::{self, PyDowncastError, PyResult}; use crate::object::PyObject; use crate::type_object::{PyDowncastImpl, PyTypeInfo}; use crate::types::PyTuple; +use crate::unscoped::Tuple; use crate::{ffi, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; /// This trait represents that **we can do zero-cost conversion from the object @@ -406,9 +407,9 @@ where } /// Converts `()` to an empty Python tuple. -impl FromPy<()> for Py> { - fn from_py(_: (), py: Python) -> Py> { - Py::from_py(PyTuple::empty(py), py) +impl FromPy<()> for Py { + fn from_py(_: (), py: Python) -> Py { + Py::from(PyTuple::empty(py)) } } @@ -465,6 +466,6 @@ mod test { let py = gil.python(); let list = PyList::new(py, &[1, 2, 3]); let val = unsafe { ::try_from_unchecked(list.as_ref()) }; - assert_eq!(list, val); + assert_eq!(&list, val); } } diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 6ecf8a26685..b4124c93d46 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -6,12 +6,12 @@ use crate::err::{PyErr, PyResult}; use crate::exceptions::TypeError; -use crate::instance::PyNativeType; use crate::pyclass::PyClass; use crate::pyclass_init::PyClassInitializer; use crate::types::{PyAny, PyDict, PyModule, PyTuple}; use crate::{ffi, GILPool, IntoPy, Py, PyCell, PyObject, Python}; use std::cell::UnsafeCell; +use std::borrow::Cow; /// Description of a python parameter; used for `parse_args()`. #[derive(Debug)] @@ -32,15 +32,15 @@ pub struct ParamDescription { /// * kwargs: Keyword arguments /// * output: Output array that receives the arguments. /// Must have same length as `params` and must be initialized to `None`. -pub fn parse_fn_args<'a, 'py>( +pub fn parse_fn_args<'py>( fname: Option<&str>, params: &[ParamDescription], - args: &'a PyTuple<'py>, - kwargs: Option<&'a PyDict<'py>>, + args: &'py PyTuple<'py>, + kwargs: Option<&'py PyDict<'py>>, accept_args: bool, accept_kwargs: bool, - output: &mut [Option<&'a PyAny<'py>>], -) -> PyResult<(&'a PyTuple<'py>, Option>)> { + output: &mut [Option<&'py PyAny<'py>>], +) -> PyResult<(Cow<'py, PyTuple<'py>>, Option>>)> { let nargs = args.len(); let mut used_args = 0; macro_rules! raise_error { @@ -48,45 +48,59 @@ pub fn parse_fn_args<'a, 'py>( concat!("{} ", $s), fname.unwrap_or("function") $(,$arg)* )))) } - // Copy kwargs not to modify it + let kwargs = match kwargs { - Some(k) => Some(k.copy()?), - None => None, - }; - // Iterate through the parameters and assign values to output: - for (i, (p, out)) in params.iter().zip(output).enumerate() { - *out = match kwargs.and_then(|d| d.get_item(p.name)) { - Some(kwarg) => { - if i < nargs { - raise_error!("got multiple values for argument: {}", p.name) - } - kwargs.as_ref().unwrap().del_item(p.name)?; - Some(kwarg) - } - None => { - if p.kw_only { - if !p.is_optional { - raise_error!("missing required keyword-only argument: {}", p.name) + Some(kwargs) => { + let mut unrecognised_kwargs = Cow::Borrowed(kwargs); + // Iterate through the parameters and assign values to output: + for (i, (p, out)) in params.iter().zip(output).enumerate() { + *out = match kwargs.get_item(p.name) { + Some(kwarg) => { + if i < nargs { + raise_error!("got multiple values for argument: {}", p.name) + } + + // Delete kwarg from unrecognised set (first making a copy if needed) + if let Cow::Borrowed(k) = &unrecognised_kwargs{ + unrecognised_kwargs = Cow::Owned(k.copy()?); + } + unrecognised_kwargs.del_item(p.name)?; + + Some(kwarg) } - None - } else if i < nargs { - used_args += 1; - Some(args.get_item(i)) - } else { - if !p.is_optional { - raise_error!("missing required positional argument: {}", p.name) + None => { + if p.kw_only { + if !p.is_optional { + raise_error!("missing required keyword-only argument: {}", p.name) + } + None + } else if i < nargs { + used_args += 1; + Some(args.get_item(i)) + } else { + if !p.is_optional { + raise_error!("missing required positional argument: {}", p.name) + } + None + } } - None } } - } - } - let is_kwargs_empty = kwargs.as_ref().map_or(true, |dict| dict.is_empty()); - // Raise an error when we get an unknown key - if !accept_kwargs && !is_kwargs_empty { - let (key, _) = kwargs.unwrap().iter().next().unwrap(); - raise_error!("got an unexpected keyword argument: {}", key) - } + + if unrecognised_kwargs.is_empty() { + None + } else if !accept_kwargs { + // Raise an error when we get an unknown key + let (key, _) = unrecognised_kwargs.iter().next().unwrap(); + raise_error!("got an unexpected keyword argument: {}", key) + } else { + Some(unrecognised_kwargs) + } + + }, + None => None + }; + // Raise an error when we get too many positional args if !accept_args && used_args < nargs { raise_error!( @@ -98,17 +112,11 @@ pub fn parse_fn_args<'a, 'py>( } // Adjust the remaining args let args = if accept_args { - let py = args.py(); - let slice = args.slice(used_args as isize, nargs as isize).into_py(py); - py.checked_cast_as(slice).unwrap() - } else { - args - }; - let kwargs = if accept_kwargs && is_kwargs_empty { - None + Cow::Owned(args.slice(used_args as isize, nargs as isize)) } else { - kwargs + Cow::Borrowed(args) }; + Ok((args, kwargs)) } diff --git a/src/err.rs b/src/err.rs index 54df0c1daaf..88a6170df19 100644 --- a/src/err.rs +++ b/src/err.rs @@ -2,6 +2,7 @@ use crate::type_object::PyTypeObject; use crate::types::PyType; +use crate::unscoped::Type; use crate::{exceptions, ffi}; use crate::{ AsPyPointer, FromPy, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToBorrowedObject, @@ -37,7 +38,7 @@ impl PyErrValue { /// Represents a Python exception that was raised. pub struct PyErr { /// The type of the exception. This should be either a `PyClass` or a `PyType`. - pub ptype: Py>, + pub ptype: Py, /// The value of the exception. /// @@ -102,7 +103,7 @@ impl PyErr { /// `exc` is the exception type; usually one of the standard exceptions /// like `exceptions::RuntimeError`. /// `args` is the a tuple of arguments to pass to the exception constructor. - pub fn from_type(exc: Py, args: A) -> PyErr + pub fn from_type(exc: Py, args: A) -> PyErr where A: ToPyObject + 'static, { diff --git a/src/exceptions.rs b/src/exceptions.rs index 294d77384c6..5addcd3c77f 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -2,12 +2,13 @@ //! Exception types defined by Python. +use crate::conversion::AsPyPointer; use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::type_object::PyTypeObject; use crate::types::{PyAny, PyTuple}; use crate::Python; -use crate::{AsPyPointer, ToPyObject}; +use crate::ToPyObject; use std::ffi::CStr; use std::ops; use std::os::raw::c_char; @@ -89,7 +90,7 @@ macro_rules! import_exception { macro_rules! import_exception_type_object { ($module: expr, $name: ident) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType<'static>> { + fn type_object() -> $crate::Py<$crate::unscoped::Type> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -173,7 +174,7 @@ macro_rules! create_exception { macro_rules! create_exception_type_object { ($module: ident, $name: ident, $base: ty) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType<'static>> { + fn type_object() -> $crate::Py<$crate::unscoped::Type> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -215,7 +216,7 @@ macro_rules! impl_native_exception ( } } unsafe impl PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType<'static>> { + fn type_object() -> $crate::Py<$crate::unscoped::Type> { unsafe { $crate::Py::from_borrowed_ptr(ffi::$exc_name) } } } @@ -380,7 +381,7 @@ mod test { .map_err(|e| e.print(py)) .expect("could not setitem"); - py.run("assert isinstance(exc, socket.gaierror)", None, Some(d)) + py.run("assert isinstance(exc, socket.gaierror)", None, Some(&d)) .map_err(|e| e.print(py)) .expect("assertion failed"); } @@ -407,7 +408,7 @@ mod test { py.run( "assert isinstance(exc, email.errors.MessageError)", None, - Some(d), + Some(&d), ) .map_err(|e| e.print(py)) .expect("assertion failed"); diff --git a/src/instance.rs b/src/instance.rs index 9fb107a4438..7eee94397c5 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,11 +1,13 @@ // Copyright (c) 2017-present PyO3 Project and Contributors +use crate::conversion::FromPyPointer; use crate::err::{PyErr, PyResult}; use crate::gil; use crate::object::PyObject; use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl}; +use crate::unscoped::Unscoped; use crate::{ - ffi, AsPyPointer, IntoPy, IntoPyPointer, PyAny, PyCell, PyClass, - PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject, + ffi, AsPyPointer, IntoPy, IntoPyPointer, PyCell, PyClass, + PyClassInitializer, PyRef, PyRefMut, Python, ToPyObject, }; use std::marker::PhantomData; use std::mem; @@ -132,6 +134,12 @@ impl Py { } } +impl<'py, T: Unscoped<'py>> Py { + pub fn into_scoped(self, py: Python<'py>) -> T::NativeType { + unsafe { T::NativeType::from_owned_ptr(py, self.into_ptr()) } + } +} + /// Retrieves `&'py` types from `Py` or `PyObject`. /// /// # Examples @@ -163,21 +171,21 @@ impl Py { /// let py = gil.python(); /// assert_eq!(obj.as_ref(py).len().unwrap(), 0); // PyAny implements ObjectProtocol /// ``` -pub trait AsPyRef<'p>: Sized { - type Target: 'p; +pub trait AsPyRef<'py>: Sized { + type Target: 'py; /// Return reference to object. - fn as_ref(&self, py: Python<'p>) -> &Self::Target; + fn as_ref<'a>(&'a self, py: Python<'py>) -> &'a Self::Target where 'py: 'a; } -impl<'p, T> AsPyRef<'p> for Py +impl<'py, T> AsPyRef<'py> for Py where - T: PyTypeInfo<'p>, - T::AsRefTarget: 'p, + T: Unscoped<'py> { - type Target = T::AsRefTarget; - fn as_ref(&self, _py: Python<'p>) -> &Self::Target { - let any = self as *const Py as *const PyAny; - unsafe { PyDowncastImpl::unchecked_downcast(&*any) } + type Target = T::NativeType; + fn as_ref<'a>(&'a self, _py: Python<'py>) -> &'a Self::Target + where 'py: 'a + { + unsafe { PyDowncastImpl::unchecked_downcast(std::mem::transmute(self)) } } } @@ -290,10 +298,6 @@ impl std::convert::From> for PyObject { // } // } -pub trait Unscoped<'py> { - type NativeType: PyNativeType<'py>; -} - /// Reference to a converted [ToPyObject]. /// /// Many methods want to take anything that can be converted into a Python object. This type @@ -417,7 +421,7 @@ mod test { let py = gil.python(); let native = PyDict::new(py); let ref_count = unsafe { ffi::Py_REFCNT(native.as_ptr()) }; - let borrowed = ManagedPyRef::from_to_pyobject(py, native); + let borrowed = ManagedPyRef::from_to_pyobject(py, &native); assert_eq!(native.as_ptr(), borrowed.data); assert_eq!(ref_count, unsafe { ffi::Py_REFCNT(borrowed.data) }); drop(borrowed); diff --git a/src/lib.rs b/src/lib.rs index 883b43622dc..77faf30d112 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -197,6 +197,7 @@ pub mod pyclass_slots; mod python; pub mod type_object; pub mod types; +pub mod unscoped; /// The proc macros, which are also part of the prelude. pub mod proc_macro { diff --git a/src/marshal.rs b/src/marshal.rs index 7f3e0bc69f9..7150fbedd2f 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -63,9 +63,9 @@ mod test { dict.set_item("zus", "jet").unwrap(); let bytes = dumps(py, &dict, VERSION) - .expect("marshalling failed") - .as_bytes(); - let deserialized = loads(py, bytes).expect("unmarshalling failed"); + .expect("marshalling failed"); + + let deserialized = loads(py, bytes.as_bytes()).expect("unmarshalling failed"); assert!(equal(py, &*dict, &deserialized)); } diff --git a/src/object.rs b/src/object.rs index 15f5023650b..8c5ff37e7f3 100644 --- a/src/object.rs +++ b/src/object.rs @@ -4,7 +4,8 @@ use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; use crate::gil; use crate::instance::{AsPyRef, PyNativeType}; -use crate::types::{PyAny, PyDict, PyTuple}; +use crate::types::{PyAny, PyDict}; +use crate::unscoped::Tuple; use crate::{AsPyPointer, Py, Python}; use crate::{FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, ToBorrowedObject, ToPyObject}; use std::ptr::NonNull; @@ -191,7 +192,7 @@ impl PyObject { pub fn call( &self, py: Python, - args: impl IntoPy>>, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult { let args = args.into_py(py).into_ptr(); @@ -209,7 +210,7 @@ impl PyObject { /// Calls the object with only positional arguments. /// /// This is equivalent to the Python expression `self(*args)`. - pub fn call1(&self, py: Python, args: impl IntoPy>>) -> PyResult { + pub fn call1(&self, py: Python, args: impl IntoPy>) -> PyResult { self.call(py, args, None) } @@ -227,7 +228,7 @@ impl PyObject { &self, py: Python, name: &str, - args: impl IntoPy>>, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult { name.with_borrowed_ptr(py, |name| unsafe { @@ -252,7 +253,7 @@ impl PyObject { &self, py: Python, name: &str, - args: impl IntoPy>>, + args: impl IntoPy>, ) -> PyResult { self.call_method(py, name, args, None) } @@ -274,10 +275,12 @@ where } } -impl<'p> AsPyRef<'p> for PyObject { - type Target = PyAny<'p>; - fn as_ref(&self, _py: Python<'p>) -> &PyAny<'p> { - unsafe { &*(self as *const _ as *const PyAny) } +impl<'py> AsPyRef<'py> for PyObject { + type Target = PyAny<'py>; + fn as_ref<'a>(&'a self, _py: Python<'py>) -> &'a PyAny<'py> + where 'py: 'a + { + unsafe { std::mem::transmute(self) } } } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 82e7db90f48..5612f7ab2a3 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -3,7 +3,8 @@ use crate::class::basic::CompareOp; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions::TypeError; -use crate::types::{PyAny, PyDict, PyIterator, PyString, PyTuple, PyType}; +use crate::types::{PyAny, PyDict, PyIterator, PyString, PyType}; +use crate::unscoped::Tuple; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyNativeType, PyObject, PyTryFrom, Python, ToBorrowedObject, ToPyObject, @@ -89,12 +90,12 @@ pub trait ObjectProtocol<'py> { /// Calls the object. /// /// This is equivalent to the Python expression `self(*args, **kwargs)`. - fn call(&self, args: impl IntoPy>>, kwargs: Option<&PyDict>) -> PyResult>; + fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult>; /// Calls the object with only positional arguments. /// /// This is equivalent to the Python expression `self(*args)`. - fn call1(&self, args: impl IntoPy>>) -> PyResult>; + fn call1(&self, args: impl IntoPy>) -> PyResult>; /// Calls the object without arguments. /// @@ -120,14 +121,14 @@ pub trait ObjectProtocol<'py> { fn call_method( &self, name: &str, - args: impl IntoPy>>, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult>; /// Calls a method on the object with only positional arguments. /// /// This is equivalent to the Python expression `self.name(*args)`. - fn call_method1(&self, name: &str, args: impl IntoPy>>) -> PyResult>; + fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult>; /// Calls a method on the object without arguments. /// @@ -335,7 +336,7 @@ where unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 } } - fn call(&self, args: impl IntoPy>>, kwargs: Option<&PyDict>) -> PyResult> { + fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult> { let args = args.into_py(self.py()).into_ptr(); let kwargs = kwargs.into_ptr(); let result = unsafe { @@ -353,14 +354,14 @@ where self.call((), None) } - fn call1(&self, args: impl IntoPy>>) -> PyResult> { + fn call1(&self, args: impl IntoPy>) -> PyResult> { self.call(args, None) } fn call_method( &self, name: &str, - args: impl IntoPy>>, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult> { name.with_borrowed_ptr(self.py(), |name| unsafe { @@ -384,7 +385,7 @@ where self.call_method(name, (), None) } - fn call_method1(&self, name: &str, args: impl IntoPy>>) -> PyResult> { + fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult> { self.call_method(name, args, None) } diff --git a/src/pycell.rs b/src/pycell.rs index a7cb0ea238c..36f18197740 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -129,7 +129,8 @@ unsafe impl<'py, T: PyClass<'py>> PyLayout<'py, T> for PyCellLayout<'py, T> { unsafe fn py_drop(&mut self, py: Python) { ManuallyDrop::drop(&mut self.inner.value); self.dict.clear_dict(py); - self.weakref.clear_weakrefs(self as *mut _ as _, py); + let ptr = self as *mut _ as _; + self.weakref.clear_weakrefs(ptr, py); self.inner.ob_base.py_drop(py); } } diff --git a/src/python.rs b/src/python.rs index db71e76faad..06ee5c10132 100644 --- a/src/python.rs +++ b/src/python.rs @@ -265,10 +265,10 @@ impl<'p> Python<'p> { /// This is equivalent to the Python `issubclass` function. pub fn is_subclass(self) -> PyResult where - T: PyTypeObject, - U: PyTypeObject, + T: PyTypeInfo<'p>, + U: PyTypeInfo<'p>, { - T::type_object().as_ref(self).is_subclass::() + PyType::new::(self).is_subclass::() } /// Gets the Python builtin value `None`. diff --git a/src/type_object.rs b/src/type_object.rs index 0f31a791047..591e4ec561d 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -3,7 +3,8 @@ use crate::pyclass::{initialize_type_object, PyClass}; use crate::pyclass_init::PyObjectInit; -use crate::types::{PyAny, PyType}; +use crate::types::PyAny; +use crate::unscoped::Type; use crate::{ffi, AsPyPointer, Py, Python}; use std::cell::UnsafeCell; use std::ptr::NonNull; @@ -150,14 +151,14 @@ pub unsafe trait PyTypeInfo<'py>: Sized { /// See [PyTypeInfo::type_object] pub unsafe trait PyTypeObject { /// Returns the safe abstraction over the type object. - fn type_object() -> Py>; + fn type_object() -> Py; } unsafe impl<'py, T> PyTypeObject for T where T: PyTypeInfo<'py>, { - fn type_object() -> Py> { + fn type_object() -> Py { unsafe { Py::from_borrowed_ptr(::type_object() as *const _ as _) } } } diff --git a/src/types/any.rs b/src/types/any.rs index 16f7ea7a53c..595a169fac7 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -31,7 +31,7 @@ use std::ptr::NonNull; /// assert!(any.downcast::().is_err()); /// ``` #[repr(transparent)] -pub struct PyAny<'a>(NonNull, PhantomData<&'a ffi::PyObject>); +pub struct PyAny<'a>(NonNull, PhantomData>); impl<'py> crate::type_object::PySizedLayout<'py, PyAny<'py>> for ffi::PyObject {} pyobject_native_type_named!(PyAny); @@ -56,7 +56,7 @@ impl<'py> PyAny<'py> { /// # Safety /// /// It must be ensured that the pointer is an owned reference. - pub unsafe fn from_non_null(py: Python<'py>, ptr: NonNull) -> Self { + pub unsafe fn from_non_null(_py: Python<'py>, ptr: NonNull) -> Self { Self(ptr, PhantomData) } diff --git a/src/types/dict.rs b/src/types/dict.rs index bfc0185517b..d5e91138658 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -42,7 +42,7 @@ impl<'py> PyDict<'py> { pub fn from_sequence(py: Python<'py>, seq: &PyAny) -> PyResult { unsafe { let dict = py.from_owned_ptr::(ffi::PyDict_New()); - match ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1i32) { + match ffi::PyDict_MergeFromSeq2(dict.as_ptr(), seq.into_ptr(), 1i32) { 0 => Ok(dict), -1 => Err(PyErr::fetch(py)), _ => unreachable!(), diff --git a/src/types/iterator.rs b/src/types/iterator.rs index d9a0e18c661..e57c37b961d 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -2,6 +2,7 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython +use crate::conversion::PyTryFrom; use crate::{ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyResult, Python}; /// A Python iterator object. @@ -27,6 +28,10 @@ use crate::{ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyRes /// ``` pub struct PyIterator<'p>(PyAny<'p>); +pyobject_native_type_named!(PyIterator); +pyobject_native_type_extract!(PyIterator); +pyobject_native_newtype!(PyIterator); + impl<'p> PyIterator<'p> { /// Constructs a `PyIterator` from a Python iterator object. pub fn from_object(py: Python<'p>, obj: &T) -> Result, PyDowncastError> @@ -42,7 +47,7 @@ impl<'p> PyIterator<'p> { } if ffi::PyIter_Check(ptr) != 0 { - Ok(PyIterator(py.from_owned_ptr(ptr))) + Ok(py.from_owned_ptr(ptr)) } else { Err(PyDowncastError) } @@ -75,10 +80,25 @@ impl<'p> Iterator for PyIterator<'p> { } } -/// Dropping a `PyIterator` instance decrements the reference count on the object by 1. -impl<'p> Drop for PyIterator<'p> { - fn drop(&mut self) { - unsafe { ffi::Py_DECREF(self.0.as_ptr()) } +impl<'py> PyTryFrom<'py> for PyIterator<'py> { + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a PyIterator<'py>, PyDowncastError> { + unsafe { + if ffi::PyIter_Check(value.as_ptr()) != 0 { + Ok(::try_from_unchecked(value)) + } else { + Err(PyDowncastError) + } + } + } + + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a PyIterator<'py>, PyDowncastError> { + ::try_from(value) + } + + #[inline] + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a PyIterator<'py> { + let ptr = value as *const _ as *const PyIterator; + &*ptr } } diff --git a/src/types/mod.rs b/src/types/mod.rs index ded8b5fd1d5..87efc31e2ca 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -42,7 +42,10 @@ macro_rules! pyobject_native_type_named ( /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] fn into_ptr(self) -> *mut $crate::ffi::PyObject { - self.into_non_null().as_ptr() + use $crate::AsPyPointer; + let ptr = self.as_ptr(); + std::mem::forget(self); + ptr } } @@ -67,7 +70,8 @@ macro_rules! pyobject_native_type_named ( impl std::convert::From<$name<'_>> for $crate::PyObject { fn from(ob: $name<'_>) -> Self { - Self::from_non_null(ob.into_non_null()) + use $crate::{IntoPyPointer, PyNativeType}; + unsafe { Self::from_owned_ptr(ob.py(), ob.into_ptr()) } } } diff --git a/src/types/module.rs b/src/types/module.rs index 35c43ec6a60..b2986ea5e0a 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -10,8 +10,8 @@ use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::pyclass::PyClass; use crate::type_object::PyTypeObject; -use crate::types::PyTuple; use crate::types::{PyAny, PyDict, PyList}; +use crate::unscoped::Tuple; use crate::{AsPyPointer, IntoPy, Py, Python, ToPyObject}; use std::ffi::{CStr, CString}; use std::os::raw::c_char; @@ -83,7 +83,7 @@ impl<'py> PyModule<'py> { Err(err) => { if err.is_instance::(self.py()) { let l = PyList::empty(self.py()); - self.setattr("__all__", l).map_err(PyErr::from)?; + self.setattr("__all__", &l).map_err(PyErr::from)?; Ok(l) } else { Err(err) @@ -126,7 +126,7 @@ impl<'py> PyModule<'py> { pub fn call( &self, name: &str, - args: impl IntoPy>>, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult> { self.getattr(name)?.call(args, kwargs) @@ -135,7 +135,7 @@ impl<'py> PyModule<'py> { /// Calls a function in the module with only positional arguments. /// /// This is equivalent to the Python expression `module.name(*args)`. - pub fn call1(&self, name: &str, args: impl IntoPy>>) -> PyResult> { + pub fn call1(&self, name: &str, args: impl IntoPy>) -> PyResult> { self.getattr(name)?.call1(args) } diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 913a2ffeb4f..4dbda06efe0 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -261,22 +261,22 @@ impl<'py> PySequence<'py> { macro_rules! array_impls { ($($N:expr),+) => { $( - impl<'a, 'py, T> FromPyObject<'a, 'py> for [T; $N] + impl<'py, T> FromPyObject<'_, 'py> for [T; $N] where - T: Copy + Default + FromPyObject<'a, 'py>, + T: Copy + Default + for<'a> FromPyObject<'a, 'py>, { - default fn extract(obj: &'a PyAny<'py>) -> PyResult { + default fn extract(obj: &PyAny<'py>) -> PyResult { let mut array = [T::default(); $N]; extract_sequence_into_slice(obj, &mut array)?; Ok(array) } } - impl<'a, 'py, T> FromPyObject<'a, 'py> for [T; $N] + impl<'py, T> FromPyObject<'_, 'py> for [T; $N] where - T: Copy + Default + FromPyObject<'a, 'py> + buffer::Element, + T: Copy + Default + for<'a> FromPyObject<'a, 'py> + buffer::Element, { - fn extract(obj: &'a PyAny<'py>) -> PyResult { + fn extract(obj: &PyAny<'py>) -> PyResult { let mut array = [T::default(); $N]; // first try buffer protocol if let Ok(buf) = buffer::PyBuffer::get(obj.py(), obj) { @@ -300,20 +300,20 @@ array_impls!( 26, 27, 28, 29, 30, 31, 32 ); -impl<'a, 'py, T> FromPyObject<'a, 'py> for Vec +impl<'py, T> FromPyObject<'_, 'py> for Vec where - T: FromPyObject<'a, 'py>, + T: for<'a> FromPyObject<'a, 'py>, { - default fn extract(obj: &'a PyAny<'py>) -> PyResult { + default fn extract(obj: &PyAny<'py>) -> PyResult { extract_sequence(obj) } } -impl<'a, 'py, T> FromPyObject<'a, 'py> for Vec +impl<'py, T> FromPyObject<'_, 'py> for Vec where - T: FromPyObject<'a, 'py> + buffer::Element + Copy, + T: for<'a> FromPyObject<'a, 'py> + buffer::Element + Copy, { - fn extract(obj: &'a PyAny<'py>) -> PyResult { + fn extract(obj: &PyAny<'py>) -> PyResult { // first try buffer protocol if let Ok(buf) = buffer::PyBuffer::get(obj.py(), obj) { if buf.dimensions() == 1 { @@ -329,9 +329,9 @@ where } } -fn extract_sequence<'a, 'py, T>(obj: &'a PyAny<'py>) -> PyResult> +fn extract_sequence<'py, T>(obj: &PyAny<'py>) -> PyResult> where - T: FromPyObject<'a, 'py>, + T: for<'a> FromPyObject<'a, 'py>, { let seq = ::try_from(obj)?; let mut v = Vec::with_capacity(seq.len().unwrap_or(0) as usize); @@ -341,9 +341,9 @@ where Ok(v) } -fn extract_sequence_into_slice<'a, 'py, T>(obj: &'a PyAny<'py>, slice: &mut [T]) -> PyResult<()> +fn extract_sequence_into_slice<'py, T>(obj: &PyAny<'py>, slice: &mut [T]) -> PyResult<()> where - T: FromPyObject<'a, 'py>, + T: for<'a> FromPyObject<'a, 'py>, { let seq = ::try_from(obj)?; if seq.len()? as usize != slice.len() { diff --git a/src/types/tuple.rs b/src/types/tuple.rs index dc54f4f62bb..ef860475c1e 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -1,6 +1,7 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::ffi::{self, Py_ssize_t}; +use crate::unscoped::Tuple; use crate::{ exceptions, AsPyPointer, AsPyRef, FromPy, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyNativeType, PyObject, PyResult, PyTryFrom, Python, ToPyObject, @@ -52,16 +53,16 @@ impl<'py> PyTuple<'py> { } /// Takes a slice of the tuple pointed from `low` to `high` and returns it as a new tuple. - pub fn slice(&self, low: isize, high: isize) -> Py> { - unsafe { Py::from_owned_ptr_or_panic(ffi::PyTuple_GetSlice(self.as_ptr(), low, high)) } + pub fn slice(&self, low: isize, high: isize) -> Self { + unsafe { self.py().from_owned_ptr(ffi::PyTuple_GetSlice(self.as_ptr(), low, high)) } } /// Takes a slice of the tuple from `low` to the end and returns it as a new tuple. - pub fn split_from(&self, low: isize) -> Py> { + pub fn split_from(&self, low: isize) -> Self { unsafe { let ptr = ffi::PyTuple_GetSlice(self.as_ptr(), low, ffi::PyTuple_GET_SIZE(self.as_ptr())); - Py::from_owned_ptr_or_panic(ptr) + self.py().from_owned_ptr(ptr) } } @@ -131,8 +132,8 @@ impl<'py> IntoIterator for &'py PyTuple<'py> { } } -impl<'py> FromPy<&'_ PyTuple<'py>> for Py> { - fn from_py(tuple: &PyTuple<'py>, _py: Python) -> Py> { +impl<'py> FromPy<&'_ PyTuple<'py>> for Py { + fn from_py(tuple: &PyTuple<'py>, _py: Python) -> Py { unsafe { Py::from_borrowed_ptr(tuple.as_ptr()) } } } @@ -166,8 +167,8 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ } } - impl <$($T: IntoPy),+> IntoPy>> for ($($T,)+) { - fn into_py(self, py: Python) -> Py> { + impl <$($T: IntoPy),+> IntoPy> for ($($T,)+) { + fn into_py(self, py: Python) -> Py { unsafe { let ptr = ffi::PyTuple_New($length); $(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_py(py).into_ptr());)+ diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 931035f363e..803782081de 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -5,7 +5,7 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::instance::PyNativeType; -use crate::type_object::PyTypeInfo; +use crate::type_object::{PyTypeInfo, PyTypeObject}; use crate::types::PyAny; use crate::AsPyPointer; use crate::Python; @@ -22,7 +22,7 @@ impl<'py> PyType<'py> { /// Creates a new type object. #[inline] pub fn new>(py: Python<'py>) -> Self { - py.from_owned_ptr(T::type_object() as *const _ as *mut ffi::PyTypeObject as _) + ::type_object().into_scoped(py) } /// Retrieves the underlying FFI pointer associated with this Python object. diff --git a/src/unscoped.rs b/src/unscoped.rs new file mode 100644 index 00000000000..e88b81beed8 --- /dev/null +++ b/src/unscoped.rs @@ -0,0 +1,28 @@ +use crate::types::*; +use crate::{AsPyPointer, IntoPyPointer, PyNativeType, FromPyPointer}; + +pub trait Unscoped<'py> { + type NativeType: PyNativeType<'py> + AsPyPointer + IntoPyPointer + FromPyPointer<'py>; +} + +#[macro_export] +macro_rules! py_unscoped { + ($name: ident, $native_ty: ident) => { + #[derive(Debug)] + pub struct $name; + + impl<'py> Unscoped<'py> for $name { + type NativeType = $native_ty<'py>; + } + + impl From<$native_ty<'_>> for $crate::Py<$name> { + fn from(other: $native_ty<'_>) -> Self { + unsafe { $crate::Py::from_owned_ptr(other.into_ptr()) } + } + } + }; +} + +py_unscoped!(Dict, PyDict); +py_unscoped!(Tuple, PyTuple); +py_unscoped!(Type, PyType); From d3f44f84252c5ee07ccee76bb00a7ec89c706a04 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 29 Apr 2020 22:46:25 +0100 Subject: [PATCH 07/11] Again get lib tests passing --- pyo3-derive-backend/src/pyclass.rs | 26 +++---- src/conversion.rs | 10 --- src/lib.rs | 2 +- src/pycell.rs | 49 ++++++------ src/types/any.rs | 7 +- src/types/boolobject.rs | 2 +- src/types/bytearray.rs | 2 +- src/types/bytes.rs | 2 +- src/types/complex.rs | 2 +- src/types/datetime.rs | 10 +-- src/types/dict.rs | 2 +- src/types/floatob.rs | 2 +- src/types/iterator.rs | 18 ++--- src/types/list.rs | 2 +- src/types/mod.rs | 120 +++++++++++++++-------------- src/types/module.rs | 2 +- src/types/num.rs | 2 +- src/types/sequence.rs | 6 +- src/types/set.rs | 4 +- src/types/slice.rs | 2 +- src/types/string.rs | 2 +- src/types/tuple.rs | 2 +- src/types/typeobject.rs | 2 +- tests/common.rs | 2 +- tests/test_datetime.rs | 6 +- tests/test_methods.rs | 2 +- tests/test_various.rs | 12 +-- 27 files changed, 148 insertions(+), 152 deletions(-) diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index 5c92a75beac..ad3ee399058 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -276,7 +276,7 @@ fn impl_class( } } else { quote! { - impl pyo3::pyclass::PyClassAlloc for #cls {} + impl pyo3::pyclass::PyClassAlloc<'_> for #cls {} } } }; @@ -357,7 +357,7 @@ fn impl_class( let base_layout = if attr.has_extends { quote! { ::LayoutAsBase } } else { - quote! { pyo3::pycell::PyCellBase } + quote! { pyo3::pycell::PyCellBase<'py, pyo3::PyAny<'py>> } }; let base_nativetype = if attr.has_extends { quote! { ::BaseNativeType } @@ -379,13 +379,13 @@ fn impl_class( }; Ok(quote! { - unsafe impl pyo3::type_object::PyTypeInfo for #cls { + unsafe impl<'py> pyo3::type_object::PyTypeInfo<'py> for #cls { type Type = #cls; - type BaseType = #base; - type Layout = pyo3::PyCell; + type BaseType = #base<'py>; + type Layout = pyo3::pycell::PyCellLayout<'py, Self>; type BaseLayout = #base_layout; - type Initializer = pyo3::pyclass_init::PyClassInitializer; - type AsRefTarget = pyo3::PyCell; + type Initializer = pyo3::pyclass_init::PyClassInitializer<'py, Self>; + type AsRefTarget = pyo3::PyCell<'py, Self>; const NAME: &'static str = #cls_name; const MODULE: Option<&'static str> = #module; @@ -400,20 +400,20 @@ fn impl_class( } } - impl pyo3::PyClass for #cls { + impl<'py> pyo3::PyClass<'py> for #cls { type Dict = #dict; type WeakRef = #weakref; - type BaseNativeType = #base_nativetype; + type BaseNativeType = #base_nativetype<'py>; } - impl<'a> pyo3::derive_utils::ExtractExt<'a> for &'a #cls + impl<'a, 'py: 'a> pyo3::derive_utils::ExtractExt<'a, 'py> for &'a #cls { - type Target = pyo3::PyRef<'a, #cls>; + type Target = pyo3::PyRef<'a, 'py, #cls>; } - impl<'a> pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls + impl<'a, 'py: 'a> pyo3::derive_utils::ExtractExt<'a, 'py> for &'a mut #cls { - type Target = pyo3::PyRefMut<'a, #cls>; + type Target = pyo3::PyRefMut<'a, 'py, #cls>; } #into_pyobject diff --git a/src/conversion.rs b/src/conversion.rs index 18fc9fe0265..356e995fa7b 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -252,16 +252,6 @@ where } } -impl<'a, 'py, T> FromPyObject<'a, 'py> for &'a PyCell<'py, T> -where - 'py: 'a, - T: PyClass<'py>, -{ - fn extract(obj: &'a PyAny<'py>) -> PyResult { - PyTryFrom::try_from(obj).map_err(Into::into) - } -} - impl<'py, T> FromPyObject<'_, 'py> for T where T: PyClass<'py> + Clone, diff --git a/src/lib.rs b/src/lib.rs index 77faf30d112..200700ea534 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,7 +298,7 @@ macro_rules! py_run_impl { use pyo3::ToPyObject; let d = [$((stringify!($val), $val.to_object($py)),)+].into_py_dict($py); - $py.run($code, None, Some(d)) + $py.run($code, None, Some(&d)) .map_err(|e| { e.print($py); // So when this c api function the last line called printed the error to stderr, diff --git a/src/pycell.rs b/src/pycell.rs index 36f18197740..d463bf315bb 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -1,5 +1,5 @@ //! Includes `PyCell` implementation. -use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject}; +use crate::conversion::{AsPyPointer, FromPyPointer}; use crate::pyclass_init::PyClassInitializer; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout, PyTypeInfo}; @@ -198,8 +198,12 @@ unsafe impl<'py, T: PyClass<'py>> PyLayout<'py, T> for PyCellLayout<'py, T> { /// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1"); /// ``` #[repr(transparent)] +#[derive(Clone)] pub struct PyCell<'py, T: PyClass<'py>>(PyAny<'py>, PhantomData>); +crate::pyobject_native_type_common!(PyCell<'py, T: PyClass<'py> >); +crate::pyobject_native_type_extract!(PyCell<'py, T: PyClass<'py> >); + impl<'py, T: PyClass<'py>> PyCell<'py, T> { /// Make new `PyCell` on the Python heap and returns the reference of it. /// @@ -375,37 +379,32 @@ impl<'py, T: PyClass<'py>> PyCell<'py, T> { } } -unsafe impl<'p, T> FromPyPointer<'p> for PyCell<'p, T> -where - T: PyClass<'p>, -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option { - NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p), PhantomData)) - } - unsafe fn from_borrowed_ptr_or_opt( - py: Python<'p>, - ptr: *mut ffi::PyObject, - ) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell)) +impl<'py, T: PyClass<'py>> ::std::convert::AsRef> for PyCell<'py, T> { + #[inline] + fn as_ref(&self) -> &PyAny<'py> { + &self.0 } } -unsafe impl<'py, T: PyClass<'py>> PyDowncastImpl<'py> for PyCell<'py, T> { - unsafe fn unchecked_downcast<'a>(obj: &'a PyAny) -> &'a Self { - &*(obj.as_ptr() as *const Self) - } - private_impl! {} -} +impl<'py, T: PyClass<'py>> ::std::ops::Deref for PyCell<'py, T> { + type Target = PyAny<'py>; -impl<'py, T: PyClass<'py>> AsPyPointer for PyCell<'py, T> { - fn as_ptr(&self) -> *mut ffi::PyObject { - self.inner().as_ptr() + #[inline] + fn deref(&self) -> &PyAny<'py> { + &self.0 } } -impl<'py, T: PyClass<'py>> ToPyObject for &PyCell<'py, T> { - fn to_object(&self, py: Python<'_>) -> PyObject { - unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } +unsafe impl<'py, T: PyClass<'py>> FromPyPointer<'py> for PyCell<'py, T> +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'py>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p), PhantomData)) + } + unsafe fn from_borrowed_ptr_or_opt( + py: Python<'py>, + ptr: *mut ffi::PyObject, + ) -> Option<&'py Self> { + NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p))) } } diff --git a/src/types/any.rs b/src/types/any.rs index 595a169fac7..613c33f91a7 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -34,14 +34,15 @@ use std::ptr::NonNull; pub struct PyAny<'a>(NonNull, PhantomData>); impl<'py> crate::type_object::PySizedLayout<'py, PyAny<'py>> for ffi::PyObject {} -pyobject_native_type_named!(PyAny); +pyobject_native_type_named!(PyAny<'py>); +pyobject_native_type_common!(PyAny<'py>); pyobject_native_type_info!( - PyAny, + PyAny<'py>, ffi::PyObject, ffi::PyBaseObject_Type, ffi::PyObject_Check ); -pyobject_native_type_extract!(PyAny); +pyobject_native_type_extract!(PyAny<'py>); impl<'py> PyAny<'py> { pub fn downcast(&self) -> Result<&T, PyDowncastError> diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 7891a98248b..0ccf4c4a67d 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -8,7 +8,7 @@ use crate::{ #[repr(transparent)] pub struct PyBool<'py>(PyAny<'py>); -pyobject_native_type!(PyBool, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check); +pyobject_native_type!(PyBool<'py>, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check); impl<'py> PyBool<'py> { /// Depending on `val`, returns `true` or `false`. diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 7c6dffd8422..1f0ac79413c 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -12,7 +12,7 @@ use std::slice; #[repr(transparent)] pub struct PyByteArray<'py>(PyAny<'py>); -pyobject_native_var_type!(PyByteArray, ffi::PyByteArray_Type, ffi::PyByteArray_Check); +pyobject_native_var_type!(PyByteArray<'py>, ffi::PyByteArray_Type, ffi::PyByteArray_Check); impl<'py> PyByteArray<'py> { /// Creates a new Python bytearray object. diff --git a/src/types/bytes.rs b/src/types/bytes.rs index fc01e08df48..7e3365537e7 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -13,7 +13,7 @@ use std::str; #[repr(transparent)] pub struct PyBytes<'py>(PyAny<'py>); -pyobject_native_var_type!(PyBytes, ffi::PyBytes_Type, ffi::PyBytes_Check); +pyobject_native_var_type!(PyBytes<'py>, ffi::PyBytes_Type, ffi::PyBytes_Check); impl<'py> PyBytes<'py> { /// Creates a new Python bytestring object. diff --git a/src/types/complex.rs b/src/types/complex.rs index c348c2ea9ed..a55e9731499 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -13,7 +13,7 @@ use std::os::raw::c_double; pub struct PyComplex<'py>(PyAny<'py>); pyobject_native_type!( - PyComplex, + PyComplex<'py>, ffi::PyComplexObject, ffi::PyComplex_Type, ffi::PyComplex_Check diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 58437edb12b..63bb0742eb5 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -67,7 +67,7 @@ pub trait PyTimeAccess { /// Bindings around `datetime.date` pub struct PyDate<'py>(PyAny<'py>); pyobject_native_type!( - PyDate, + PyDate<'py>, crate::ffi::PyDateTime_Date, *PyDateTimeAPI.DateType, Some("datetime"), @@ -123,7 +123,7 @@ impl PyDateAccess for PyDate<'_> { /// Bindings for `datetime.datetime` pub struct PyDateTime<'py>(PyAny<'py>); pyobject_native_type!( - PyDateTime, + PyDateTime<'py>, crate::ffi::PyDateTime_DateTime, *PyDateTimeAPI.DateTimeType, Some("datetime"), @@ -233,7 +233,7 @@ impl PyTimeAccess for PyDateTime<'_> { /// Bindings for `datetime.time` pub struct PyTime<'py>(PyAny<'py>); pyobject_native_type!( - PyTime, + PyTime<'py>, crate::ffi::PyDateTime_Time, *PyDateTimeAPI.TimeType, Some("datetime"), @@ -318,7 +318,7 @@ impl PyTimeAccess for PyTime<'_> { /// This is an abstract base class and should not be constructed directly. pub struct PyTzInfo<'py>(PyAny<'py>); pyobject_native_type!( - PyTzInfo, + PyTzInfo<'py>, crate::ffi::PyObject, *PyDateTimeAPI.TZInfoType, Some("datetime"), @@ -328,7 +328,7 @@ pyobject_native_type!( /// Bindings for `datetime.timedelta` pub struct PyDelta<'py>(PyAny<'py>); pyobject_native_type!( - PyDelta, + PyDelta<'py>, crate::ffi::PyDateTime_Delta, *PyDateTimeAPI.DeltaType, Some("datetime"), diff --git a/src/types/dict.rs b/src/types/dict.rs index d5e91138658..6a1164a404a 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -19,7 +19,7 @@ use std::{cmp, collections, hash}; pub struct PyDict<'py>(PyAny<'py>); pyobject_native_type!( - PyDict, + PyDict<'py>, ffi::PyDictObject, ffi::PyDict_Type, ffi::PyDict_Check diff --git a/src/types/floatob.rs b/src/types/floatob.rs index 6bb0e9f8b51..03d463da5c0 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -17,7 +17,7 @@ use std::os::raw::c_double; pub struct PyFloat<'py>(PyAny<'py>); pyobject_native_type!( - PyFloat, + PyFloat<'py>, ffi::PyFloatObject, ffi::PyFloat_Type, ffi::PyFloat_Check diff --git a/src/types/iterator.rs b/src/types/iterator.rs index e57c37b961d..b37b78bdd78 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -7,7 +7,7 @@ use crate::{ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyRes /// A Python iterator object. /// -/// Unlike other Python objects, this class includes a `Python<'p>` token +/// Unlike other Python objects, this class includes a `Python<'py>` token /// so that `PyIterator` can implement the Rust `Iterator` trait. /// /// # Example @@ -26,15 +26,15 @@ use crate::{ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyRes /// # Ok(()) /// # } /// ``` -pub struct PyIterator<'p>(PyAny<'p>); +pub struct PyIterator<'py>(PyAny<'py>); -pyobject_native_type_named!(PyIterator); -pyobject_native_type_extract!(PyIterator); -pyobject_native_newtype!(PyIterator); +pyobject_native_type_named!(PyIterator<'py>); +pyobject_native_type_extract!(PyIterator<'py>); +pyobject_native_newtype!(PyIterator<'py>); -impl<'p> PyIterator<'p> { +impl<'py> PyIterator<'py> { /// Constructs a `PyIterator` from a Python iterator object. - pub fn from_object(py: Python<'p>, obj: &T) -> Result, PyDowncastError> + pub fn from_object(py: Python<'py>, obj: &T) -> Result, PyDowncastError> where T: AsPyPointer, { @@ -55,8 +55,8 @@ impl<'p> PyIterator<'p> { } } -impl<'p> Iterator for PyIterator<'p> { - type Item = PyResult>; +impl<'py> Iterator for PyIterator<'py> { + type Item = PyResult>; /// Retrieves the next item from an iterator. /// diff --git a/src/types/list.rs b/src/types/list.rs index 5caae0c2f13..d4d343100a1 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -13,7 +13,7 @@ use crate::{ #[repr(transparent)] pub struct PyList<'py>(PyAny<'py>); -pyobject_native_var_type!(PyList, ffi::PyList_Type, ffi::PyList_Check); +pyobject_native_var_type!(PyList<'py>, ffi::PyList_Type, ffi::PyList_Check); impl<'py> PyList<'py> { /// Constructs a new list with the given elements. diff --git a/src/types/mod.rs b/src/types/mod.rs index 87efc31e2ca..393be443782 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -26,11 +26,11 @@ pub use self::tuple::PyTuple; pub use self::typeobject::PyType; #[macro_export] -macro_rules! pyobject_native_type_named ( - ($name: ident $(,$type_param: ident)*) => { - unsafe impl<'py, $($type_param,)*> $crate::PyNativeType<'py> for $name<'py> {} +macro_rules! pyobject_native_type_common ( + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >) => { + unsafe impl<'py $(, $type_param $(: $bound)?)*> $crate::PyNativeType<'py> for $name<'py $(,$type_param)*> {} - impl<$($type_param,)*> $crate::AsPyPointer for $name<'_> { + impl<'py $(, $type_param $(: $bound)?)*> $crate::AsPyPointer for $name<'py $(,$type_param)*> { /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] fn as_ptr(&self) -> *mut $crate::ffi::PyObject { @@ -38,7 +38,7 @@ macro_rules! pyobject_native_type_named ( } } - impl<$($type_param,)*> $crate::IntoPyPointer for $name<'_> { + impl<'py $(, $type_param $(: $bound)?)*> $crate::IntoPyPointer for $name<'py $(,$type_param)*> { /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] fn into_ptr(self) -> *mut $crate::ffi::PyObject { @@ -49,16 +49,16 @@ macro_rules! pyobject_native_type_named ( } } - impl<$($type_param,)*> PartialEq for $name<'_> { + impl<'py $(, $type_param $(: $bound)?)*> PartialEq for $name<'py $(,$type_param)*> { #[inline] - fn eq(&self, o: &$name) -> bool { + fn eq(&self, o: &$name<'py $(,$type_param)*>) -> bool { use $crate::AsPyPointer; self.as_ptr() == o.as_ptr() } } - impl<$($type_param,)*> $crate::ToPyObject for $name<'_> + impl<'py $(, $type_param $(: $bound)?)*> $crate::ToPyObject for $name<'py $(,$type_param)*> { #[inline] fn to_object(&self, py: $crate::Python) -> $crate::PyObject { @@ -67,15 +67,20 @@ macro_rules! pyobject_native_type_named ( } } - impl std::convert::From<$name<'_>> for $crate::PyObject + impl<'py $(, $type_param $(: $bound)?)*> std::convert::From<$name<'py $(,$type_param)*>> for $crate::PyObject { - fn from(ob: $name<'_>) -> Self { + fn from(ob: $name<'py $(,$type_param)*>) -> Self { use $crate::{IntoPyPointer, PyNativeType}; unsafe { Self::from_owned_ptr(ob.py(), ob.into_ptr()) } } } + } +); - impl<$($type_param,)*> ::std::fmt::Debug for $name<'_> { +#[macro_export] +macro_rules! pyobject_native_type_named ( + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >) => { + impl<'py $(, $type_param $(: $bound)?)*> ::std::fmt::Debug for $name<'py $(,$type_param)*> { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { @@ -85,7 +90,7 @@ macro_rules! pyobject_native_type_named ( } } - impl<$($type_param,)*> ::std::fmt::Display for $name<'_> { + impl<'py $(, $type_param $(: $bound)?)*> ::std::fmt::Display for $name<'py $(,$type_param)*> { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { @@ -99,49 +104,48 @@ macro_rules! pyobject_native_type_named ( #[macro_export] macro_rules! pyobject_native_type { - ($name: ident, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - impl<'py> $crate::type_object::PySizedLayout<'py, $name<'py>> for $layout {} - impl<'py> $crate::derive_utils::PyBaseTypeUtils<'py> for $name<'py> { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path) => { + impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PySizedLayout<'py, $name<'py $(,$type_param)*>> for $layout {} + impl<'py $(, $type_param $(: $bound)?)*> $crate::derive_utils::PyBaseTypeUtils<'py> for $name<'py $(,$type_param)*> { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; type LayoutAsBase = $crate::pycell::PyCellBase<'py, Self>; type BaseNativeType = Self; } - pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_newtype!($name $(,$type_param)*); - pyobject_native_type_info!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); - pyobject_native_type_extract!($name $(,$type_param)*); - - + pyobject_native_type_named!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_newtype!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_type_info!($name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, $module, $checkfunction); + pyobject_native_type_extract!($name<'py $(, $type_param $(: $bound)?)*>); }; - ($name: ident, $layout: path, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path) => { pyobject_native_type! { - $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* } }; } #[macro_export] macro_rules! pyobject_native_var_type { - ($name: ident, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_newtype!($name $(,$type_param)*); - pyobject_native_type_info!($name, $crate::ffi::PyObject, - $typeobject, $module, $checkfunction $(,$type_param)*); - pyobject_native_type_extract!($name $(,$type_param)*); + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $module: expr, $checkfunction: path) => { + pyobject_native_newtype!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_type_named!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_type_info!($name<'py $(, $type_param $(: $bound)?)*>, $crate::ffi::PyObject, + $typeobject, $module, $checkfunction); + pyobject_native_type_extract!($name<'py $(, $type_param $(: $bound)?)*>); }; - ($name: ident, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $checkfunction: path) => { pyobject_native_var_type! { - $name, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name<'py $(, $type_param $(: $bound)?)*>, $typeobject, Some("builtins"), $checkfunction } }; } // NOTE: This macro is not included in pyobject_native_newtype! // because rust-numpy has a special implementation. +#[macro_export] macro_rules! pyobject_native_type_extract { - ($name: ident $(,$type_param: ident)*) => { - impl<'a, 'py, $($type_param,)*> $crate::FromPyObject<'a, 'py> for &'a $name<'py> { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >) => { + impl<'a, 'py $(, $type_param $(: $bound)?)*> $crate::FromPyObject<'a, 'py> for &'a $name<'py $(,$type_param)*> { fn extract(obj: &'a $crate::PyAny<'py>) -> $crate::PyResult { $crate::PyTryFrom::try_from(obj).map_err(Into::into) } @@ -151,11 +155,11 @@ macro_rules! pyobject_native_type_extract { #[macro_export] macro_rules! pyobject_native_type_info( - ($name: ident, $layout: path, $typeobject: expr, - $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl<'py> $crate::type_object::PyLayout<'py, $name<'py>> for $layout {} + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, + $module: expr, $checkfunction: path) => { + unsafe impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PyLayout<'py, $name<'py $(,$type_param)*>> for $layout {} - unsafe impl<'py, $($type_param,)*> $crate::type_object::PyTypeInfo<'py> for $name<'py> { + unsafe impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PyTypeInfo<'py> for $name<'py $(,$type_param)*> { type Type = (); type BaseType = $crate::PyAny<'py>; type Layout = $layout; @@ -179,57 +183,59 @@ macro_rules! pyobject_native_type_info( } }; - ($name: ident, $layout: path, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path) => { pyobject_native_type_info! { - $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction } }; ); #[macro_export] macro_rules! pyobject_native_newtype( - ($name: ident $(,$type_param: ident)*) => { - impl<'a, $($type_param,)*> ::std::convert::From<&'a $name<'a>> for &'a $crate::PyAny<'a> { - fn from(ob: &'a $name) -> Self { - unsafe{&*(ob as *const $name as *const $crate::PyAny)} - } - } + ($name: ident < 'py $( ,$type_param: ident)* > ) => { + pyobject_native_type_common!($name<'py $(,$type_param)*>); - impl Clone for $name<'_> { - fn clone(&self) -> Self { - Self(self.0.clone()) + impl<'a, 'py, $($type_param,)*> ::std::convert::From<&'a $name<'py $(,$type_param)*>> for &'a $crate::PyAny<'a> { + fn from(ob: &'a $name<'py $(,$type_param)*>) -> Self { + unsafe{&*(ob as *const _ as *const $crate::PyAny)} } } - impl<'a, $($type_param,)*> ::std::convert::AsRef<$crate::PyAny<'a>> for $name<'a> { + impl<'py, $($type_param,)*> ::std::convert::AsRef<$crate::PyAny<'py>> for $name<'py $(,$type_param)*> { #[inline] - fn as_ref(&self) -> &$crate::PyAny<'a> { + fn as_ref(&self) -> &$crate::PyAny<'py> { &self.0 } } - impl<'a, $($type_param,)*> ::std::ops::Deref for $name<'a> { - type Target = $crate::PyAny<'a>; + impl<'py, $($type_param,)*> ::std::ops::Deref for $name<'py $(,$type_param)*> { + type Target = $crate::PyAny<'py>; #[inline] - fn deref(&self) -> &$crate::PyAny<'a> { + fn deref(&self) -> &$crate::PyAny<'py> { &self.0 } } - unsafe impl<'p> $crate::FromPyPointer<'p> for $name<'p> + unsafe impl<'py $(,$type_param)*> $crate::FromPyPointer<'py> for $name<'py $(,$type_param)*> { - unsafe fn from_owned_ptr_or_opt(py: $crate::Python<'p>, ptr: *mut $crate::ffi::PyObject) -> Option { + unsafe fn from_owned_ptr_or_opt(py: $crate::Python<'py>, ptr: *mut $crate::ffi::PyObject) -> Option { ::std::ptr::NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p))) } unsafe fn from_borrowed_ptr_or_opt( - py: $crate::Python<'p>, + py: $crate::Python<'py>, ptr: *mut $crate::ffi::PyObject, - ) -> Option<&'p Self> { + ) -> Option<&'py Self> { use $crate::type_object::PyDowncastImpl; ::std::ptr::NonNull::new(ptr).map(|p| Self::unchecked_downcast($crate::gil::register_borrowed(py, p))) } } + + impl<'py $(,$type_param)*> Clone for $name<'py $(,$type_param)*> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } }; ); diff --git a/src/types/module.rs b/src/types/module.rs index b2986ea5e0a..78b28039888 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -21,7 +21,7 @@ use std::str; #[repr(transparent)] pub struct PyModule<'py>(PyAny<'py>); -pyobject_native_var_type!(PyModule, ffi::PyModule_Type, ffi::PyModule_Check); +pyobject_native_var_type!(PyModule<'py>, ffi::PyModule_Type, ffi::PyModule_Check); impl<'py> PyModule<'py> { /// Creates a new module object with the `__name__` attribute set to name. diff --git a/src/types/num.rs b/src/types/num.rs index 38279592886..6fa9a47ade4 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -112,7 +112,7 @@ macro_rules! int_convert_128 { #[repr(transparent)] pub struct PyLong<'py>(PyAny<'py>); -pyobject_native_var_type!(PyLong, ffi::PyLong_Type, ffi::PyLong_Check); +pyobject_native_var_type!(PyLong<'py>, ffi::PyLong_Type, ffi::PyLong_Check); macro_rules! int_fits_c_long { ($rust_type:ty) => { diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 4dbda06efe0..69167104418 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -13,9 +13,9 @@ use crate::{FromPyObject, PyTryFrom, ToBorrowedObject}; /// Represents a reference to a Python object supporting the sequence protocol. #[repr(transparent)] pub struct PySequence<'py>(PyAny<'py>); -pyobject_native_type_named!(PySequence); -pyobject_native_type_extract!(PySequence); -pyobject_native_newtype!(PySequence); +pyobject_native_type_named!(PySequence<'py>); +pyobject_native_type_extract!(PySequence<'py>); +pyobject_native_newtype!(PySequence<'py>); impl<'py> PySequence<'py> { /// Returns the number of objects in sequence. diff --git a/src/types/set.rs b/src/types/set.rs index 82f61e530e0..78b6248d1f7 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -18,9 +18,9 @@ pub struct PySet<'py>(PyAny<'py>); #[repr(transparent)] pub struct PyFrozenSet<'py>(PyAny<'py>); -pyobject_native_type!(PySet, ffi::PySetObject, ffi::PySet_Type, ffi::PySet_Check); +pyobject_native_type!(PySet<'py>, ffi::PySetObject, ffi::PySet_Type, ffi::PySet_Check); pyobject_native_type!( - PyFrozenSet, + PyFrozenSet<'py>, ffi::PySetObject, ffi::PyFrozenSet_Type, ffi::PyFrozenSet_Check diff --git a/src/types/slice.rs b/src/types/slice.rs index 1fe17929986..c2f69568140 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -16,7 +16,7 @@ use std::os::raw::c_long; pub struct PySlice<'py>(PyAny<'py>); pyobject_native_type!( - PySlice, + PySlice<'py>, ffi::PySliceObject, ffi::PySlice_Type, ffi::PySlice_Check diff --git a/src/types/string.rs b/src/types/string.rs index 5079e609236..3c725db46f0 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -16,7 +16,7 @@ use std::str; #[repr(transparent)] pub struct PyString<'py>(PyAny<'py>); -pyobject_native_var_type!(PyString, ffi::PyUnicode_Type, ffi::PyUnicode_Check); +pyobject_native_var_type!(PyString<'py>, ffi::PyUnicode_Type, ffi::PyUnicode_Check); impl<'py> PyString<'py> { /// Creates a new Python string object. diff --git a/src/types/tuple.rs b/src/types/tuple.rs index ef860475c1e..0f0fc6c2d6a 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -14,7 +14,7 @@ use std::slice; #[repr(transparent)] pub struct PyTuple<'py>(PyAny<'py>); -pyobject_native_var_type!(PyTuple, ffi::PyTuple_Type, ffi::PyTuple_Check); +pyobject_native_var_type!(PyTuple<'py>, ffi::PyTuple_Type, ffi::PyTuple_Check); impl<'py> PyTuple<'py> { /// Constructs a new tuple with the given elements. diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 803782081de..58d8f9ce546 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -16,7 +16,7 @@ use std::ffi::CStr; #[repr(transparent)] pub struct PyType<'a>(PyAny<'a>); -pyobject_native_var_type!(PyType, ffi::PyType_Type, ffi::PyType_Check); +pyobject_native_var_type!(PyType<'py>, ffi::PyType_Type, ffi::PyType_Check); impl<'py> PyType<'py> { /// Creates a new type object. diff --git a/tests/common.rs b/tests/common.rs index 4cd3c084f9f..de000afc54f 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -15,7 +15,7 @@ macro_rules! py_expect_exception { use pyo3::types::IntoPyDict; let d = [(stringify!($val), &$val)].into_py_dict($py); - let res = $py.run($code, None, Some(d)); + let res = $py.run($code, None, Some(&d)); let err = res.unwrap_err(); if !err.matches($py, $py.get_type::()) { panic!("Expected {} but got {:?}", stringify!($err), err) diff --git a/tests/test_datetime.rs b/tests/test_datetime.rs index bb62401e8dc..d1ce377d9a4 100644 --- a/tests/test_datetime.rs +++ b/tests/test_datetime.rs @@ -5,11 +5,11 @@ use pyo3::prelude::*; use pyo3::types::IntoPyDict; #[allow(clippy::trivially_copy_pass_by_ref)] -fn _get_subclasses<'p>( - py: &'p Python, +fn _get_subclasses<'py>( + py: Python<'py>, py_type: &str, args: &str, -) -> PyResult<(&'p PyAny, &'p PyAny, &'p PyAny)> { +) -> PyResult<(PyAny<'py>, PyAny<'py>, PyAny<'py>)> { // Import the class from Python and create some subclasses let datetime = py.import("datetime")?; diff --git a/tests/test_methods.rs b/tests/test_methods.rs index da473fccc6a..7fa40fc330c 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -368,7 +368,7 @@ struct MethodWithLifeTime {} #[pymethods] impl MethodWithLifeTime { - fn set_to_list<'py>(&self, py: Python<'py>, set: &'py PySet) -> PyResult<&'py PyList> { + fn set_to_list<'py>(&self, py: Python<'py>, set: &PySet) -> PyResult> { let mut items = vec![]; for _ in 0..set.len() { items.push(set.pop().unwrap()); diff --git a/tests/test_various.rs b/tests/test_various.rs index 99708e0eb95..e5c0aefc294 100644 --- a/tests/test_various.rs +++ b/tests/test_various.rs @@ -30,7 +30,7 @@ fn mut_ref_arg() { let d = [("inst1", &inst1), ("inst2", &inst2)].into_py_dict(py); - py.run("inst1.set_other(inst2)", None, Some(d)).unwrap(); + py.run("inst1.set_other(inst2)", None, Some(&d)).unwrap(); let inst2 = inst2.as_ref(py).borrow(); assert_eq!(inst2.n, 100); } @@ -128,11 +128,11 @@ impl PickleSupport { } pub fn __reduce__<'py>( - slf: &'py PyCell, + slf: PyCell, py: Python<'py>, - ) -> PyResult<(PyObject, &'py PyTuple, PyObject)> { - let cls = slf.to_object(py).getattr(py, "__class__")?; - let dict = slf.to_object(py).getattr(py, "__dict__")?; + ) -> PyResult<(PyObject, PyTuple<'py>, PyObject)> { + let cls = slf.getattr(py, "__class__")?; + let dict = slf.getattr(py, "__dict__")?; Ok((cls, PyTuple::empty(py), dict)) } } @@ -152,7 +152,7 @@ fn test_pickle() { let py = gil.python(); let module = PyModule::new(py, "test_module").unwrap(); module.add_class::().unwrap(); - add_module(py, module).unwrap(); + add_module(py, &module).unwrap(); let inst = PyCell::new(py, PickleSupport {}).unwrap(); py_run!( py, From 999376420bba5bd5205c16d14615858103d1011e Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 29 Apr 2020 23:51:34 +0100 Subject: [PATCH 08/11] Various fixups to tests; much more needed --- examples/rustapi_module/src/datetime.rs | 30 +++--- pyo3-derive-backend/src/func.rs | 18 +++- src/class/basic.rs | 12 +-- src/class/context.rs | 6 +- src/class/descr.rs | 12 +-- src/class/iter.rs | 4 +- src/class/mapping.rs | 8 +- src/class/number.rs | 118 ++++++++++++------------ src/class/pyasync.rs | 6 +- src/class/sequence.rs | 18 ++-- tests/test_arithmetics.rs | 4 +- tests/test_datetime.rs | 10 +- tests/test_dunder.rs | 10 +- tests/test_getter_setter.rs | 4 +- tests/test_mapping.rs | 14 +-- tests/test_methods.rs | 20 ++-- tests/test_module.rs | 4 +- tests/test_pyself.rs | 4 +- tests/test_sequence.rs | 32 +++---- tests/test_various.rs | 8 +- 20 files changed, 178 insertions(+), 164 deletions(-) diff --git a/examples/rustapi_module/src/datetime.rs b/examples/rustapi_module/src/datetime.rs index cc20b6c67cf..edfaa922223 100644 --- a/examples/rustapi_module/src/datetime.rs +++ b/examples/rustapi_module/src/datetime.rs @@ -6,12 +6,12 @@ use pyo3::types::{ use pyo3::wrap_pyfunction; #[pyfunction] -fn make_date<'p>(py: Python<'p>, year: i32, month: u8, day: u8) -> PyResult<&'p PyDate> { +fn make_date(py: Python, year: i32, month: u8, day: u8) -> PyResult { PyDate::new(py, year, month, day) } #[pyfunction] -fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> &'p PyTuple { +fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> PyTuple<'p> { PyTuple::new( py, &[d.get_year(), d.get_month() as i32, d.get_day() as i32], @@ -19,7 +19,7 @@ fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> &'p PyTuple { } #[pyfunction] -fn date_from_timestamp<'p>(py: Python<'p>, timestamp: i64) -> PyResult<&'p PyDate> { +fn date_from_timestamp(py: Python, timestamp: i64) -> PyResult { PyDate::from_timestamp(py, timestamp) } @@ -31,7 +31,7 @@ fn make_time<'p>( second: u8, microsecond: u32, tzinfo: Option<&PyTzInfo>, -) -> PyResult<&'p PyTime> { +) -> PyResult> { PyTime::new( py, hour, @@ -52,7 +52,7 @@ fn time_with_fold<'p>( microsecond: u32, tzinfo: Option<&PyTzInfo>, fold: bool, -) -> PyResult<&'p PyTime> { +) -> PyResult> { PyTime::new_with_fold( py, hour, @@ -65,7 +65,7 @@ fn time_with_fold<'p>( } #[pyfunction] -fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple { +fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -79,7 +79,7 @@ fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple { #[cfg(Py_3_6)] #[pyfunction] -fn get_time_tuple_fold<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple { +fn get_time_tuple_fold<'p>(py: Python<'p>, dt: &PyTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -103,7 +103,7 @@ fn make_delta<'p>( } #[pyfunction] -fn get_delta_tuple<'p>(py: Python<'p>, delta: &PyDelta) -> &'p PyTuple { +fn get_delta_tuple<'p>(py: Python<'p>, delta: &PyDelta) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -125,7 +125,7 @@ fn make_datetime<'p>( second: u8, microsecond: u32, tzinfo: Option<&PyTzInfo>, -) -> PyResult<&'p PyDateTime> { +) -> PyResult> { PyDateTime::new( py, year, @@ -140,7 +140,7 @@ fn make_datetime<'p>( } #[pyfunction] -fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple { +fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -157,7 +157,7 @@ fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple { #[cfg(Py_3_6)] #[pyfunction] -fn get_datetime_tuple_fold<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple { +fn get_datetime_tuple_fold<'p>(py: Python<'p>, dt: &PyDateTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -178,7 +178,7 @@ fn datetime_from_timestamp<'p>( py: Python<'p>, ts: f64, tz: Option<&PyTzInfo>, -) -> PyResult<&'p PyDateTime> { +) -> PyResult> { PyDateTime::from_timestamp(py, ts, tz) } @@ -199,15 +199,15 @@ impl TzClass { TzClass {} } - fn utcoffset<'p>(&self, py: Python<'p>, _dt: &PyDateTime) -> PyResult<&'p PyDelta> { + fn utcoffset<'p>(&self, py: Python<'p>, _dt: &PyDateTime) -> PyResult> { PyDelta::new(py, 0, 3600, 0, true) } - fn tzname(&self, _py: Python<'_>, _dt: &PyDateTime) -> PyResult { + fn tzname(&self, _py: Python, _dt: &PyDateTime) -> PyResult { Ok(String::from("+01:00")) } - fn dst(&self, _py: Python<'_>, _dt: &PyDateTime) -> PyResult> { + fn dst<'p>(&self, _py: Python, _dt: &PyDateTime) -> PyResult>> { Ok(None) } } diff --git a/pyo3-derive-backend/src/func.rs b/pyo3-derive-backend/src/func.rs index 95539d8499f..b1d1497f6f4 100644 --- a/pyo3-derive-backend/src/func.rs +++ b/pyo3-derive-backend/src/func.rs @@ -452,8 +452,22 @@ fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Type { _ => panic!("fn arg type is not supported"), }; - // Add a lifetime if there is none - if let syn::Type::Reference(ref mut r) = ty { + + if let syn::Type::Reference(r) = &mut ty { + // HACK: For PyAny, add <'p> + match &mut *r.elem { + syn::Type::Path(ty) => { + let seg = ty.path.segments.last_mut().unwrap(); + if seg.ident == "PyAny" { + if let syn::PathArguments::None = seg.arguments { + seg.arguments = syn::PathArguments::AngleBracketed(syn::parse_quote!(<'p>)); + } + } + }, + _ => {} + } + + // Add a lifetime if there is none r.lifetime.get_or_insert(syn::parse_quote! {'p}); } diff --git a/src/class/basic.rs b/src/class/basic.rs index 6bd800a3e3e..96dfc246ca0 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -102,17 +102,17 @@ pub trait PyObjectProtocol<'p>: PyClass<'p> { } pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: for<'a> FromPyObject<'a, 'p>; + type Name: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: for<'a> FromPyObject<'a, 'p>; - type Value: for<'a> FromPyObject<'a, 'p>; + type Name: FromPyObject<'p, 'p>; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: for<'a> FromPyObject<'a, 'p>; + type Name: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyObjectStrProtocol<'p>: PyObjectProtocol<'p> { @@ -124,7 +124,7 @@ pub trait PyObjectReprProtocol<'p>: PyObjectProtocol<'p> { type Result: Into>; } pub trait PyObjectFormatProtocol<'p>: PyObjectProtocol<'p> { - type Format: for<'a> FromPyObject<'a, 'p>; + type Format: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } @@ -139,7 +139,7 @@ pub trait PyObjectBytesProtocol<'p>: PyObjectProtocol<'p> { type Result: Into>; } pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } diff --git a/src/class/context.rs b/src/class/context.rs index 5c38201aa75..18b6cadd3e9 100644 --- a/src/class/context.rs +++ b/src/class/context.rs @@ -37,9 +37,9 @@ pub trait PyContextEnterProtocol<'p>: PyContextProtocol<'p> { } pub trait PyContextExitProtocol<'p>: PyContextProtocol<'p> { - type ExcType: for<'a> crate::FromPyObject<'a, 'p>; - type ExcValue: for<'a> crate::FromPyObject<'a, 'p>; - type Traceback: for<'a> crate::FromPyObject<'a, 'p>; + type ExcType: crate::FromPyObject<'p, 'p>; + type ExcValue: crate::FromPyObject<'p, 'p>; + type Traceback: crate::FromPyObject<'p, 'p>; type Success: crate::IntoPy; type Result: Into>; } diff --git a/src/class/descr.rs b/src/class/descr.rs index d0a5da91543..f288a2e19a4 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -44,25 +44,25 @@ pub trait PyDescrProtocol<'p>: PyClass<'p> { } pub trait PyDescrGetProtocol<'p>: PyDescrProtocol<'p> { - type Inst: for<'a> FromPyObject<'a, 'p>; - type Owner: for<'a> FromPyObject<'a, 'p>; + type Inst: FromPyObject<'p, 'p>; + type Owner: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyDescrSetProtocol<'p>: PyDescrProtocol<'p> { - type Inst: for<'a> FromPyObject<'a, 'p>; - type Value: for<'a> FromPyObject<'a, 'p>; + type Inst: FromPyObject<'p, 'p>; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyDescrDeleteProtocol<'p>: PyDescrProtocol<'p> { - type Inst: for<'a> FromPyObject<'a, 'p>; + type Inst: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> { - type Inst: for<'a> FromPyObject<'a, 'p>; + type Inst: FromPyObject<'p, 'p>; type Result: Into>; } diff --git a/src/class/iter.rs b/src/class/iter.rs index 9bf8ebd35fc..a4a43e55b5d 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -29,13 +29,13 @@ pub trait PyIterProtocol<'p>: PyClass<'p> { } pub trait PyIterIterProtocol<'p>: PyIterProtocol<'p> { - type Receiver: for<'a> TryFromPyCell<'a, 'p, Self>; + type Receiver: TryFromPyCell<'p, 'p, Self>; type Success: crate::IntoPy; type Result: Into>; } pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> { - type Receiver: for<'a> TryFromPyCell<'a, 'p, Self>; + type Receiver: TryFromPyCell<'p, 'p, Self>; type Success: crate::IntoPy; type Result: Into>>; } diff --git a/src/class/mapping.rs b/src/class/mapping.rs index 5e7e3d9120c..6ac411abb72 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -54,19 +54,19 @@ pub trait PyMappingLenProtocol<'p>: PyMappingProtocol<'p> { } pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: for<'a> FromPyObject<'a, 'p>; + type Key: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: for<'a> FromPyObject<'a, 'p>; - type Value: for<'a> FromPyObject<'a, 'p>; + type Key: FromPyObject<'p, 'p>; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: for<'a> FromPyObject<'a, 'p>; + type Key: FromPyObject<'p, 'p>; type Result: Into>; } diff --git a/src/class/number.rs b/src/class/number.rs index 62706cfe305..33fe58d9655 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -318,256 +318,256 @@ pub trait PyNumberProtocol<'p>: PyClass<'p> { } pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberMulProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberTruedivProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberModProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberPowProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; - type Modulo: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; + type Modulo: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberLShiftProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberAndProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberXorProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberOrProtocol<'p>: PyNumberProtocol<'p> { - type Left: for<'a> FromPyObject<'a, 'p>; - type Right: for<'a> FromPyObject<'a, 'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRAddProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRSubProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRMulProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRTruedivProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRModProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRPowProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; - type Modulo: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; + type Modulo: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRLShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRAndProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRXorProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } @@ -608,7 +608,7 @@ pub trait PyNumberFloatProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberRoundProtocol<'p>: PyNumberProtocol<'p> { type Success: IntoPy; - type NDigits: for<'a> FromPyObject<'a, 'p>; + type NDigits: FromPyObject<'p, 'p>; type Result: Into>; } diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index 8db56db7f94..e9a79751ff0 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -79,9 +79,9 @@ pub trait PyAsyncAenterProtocol<'p>: PyAsyncProtocol<'p> { } pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> { - type ExcType: for<'a> crate::FromPyObject<'a, 'p>; - type ExcValue: for<'a> crate::FromPyObject<'a, 'p>; - type Traceback: for<'a> crate::FromPyObject<'a, 'p>; + type ExcType: crate::FromPyObject<'p, 'p>; + type ExcValue: crate::FromPyObject<'p, 'p>; + type Traceback: crate::FromPyObject<'p, 'p>; type Success: crate::IntoPy; type Result: Into>; } diff --git a/src/class/sequence.rs b/src/class/sequence.rs index b26ff4d1583..00c8e5c449f 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -85,46 +85,46 @@ pub trait PySequenceLenProtocol<'p>: PySequenceProtocol<'p> { } pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: for<'a> FromPyObject<'a, 'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Success: IntoPy; type Result: Into>; } pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: for<'a> FromPyObject<'a, 'p> + From; - type Value: for<'a> FromPyObject<'a, 'p>; + type Index: FromPyObject<'p, 'p> + From; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: for<'a> FromPyObject<'a, 'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Result: Into>; } pub trait PySequenceContainsProtocol<'p>: PySequenceProtocol<'p> { - type Item: for<'a> FromPyObject<'a, 'p>; + type Item: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PySequenceConcatProtocol<'p>: PySequenceProtocol<'p> { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> { - type Index: for<'a> FromPyObject<'a, 'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Success: IntoPy; type Result: Into>; } pub trait PySequenceInplaceConcatProtocol<'p>: PySequenceProtocol<'p> + IntoPy { - type Other: for<'a> FromPyObject<'a, 'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PySequenceInplaceRepeatProtocol<'p>: PySequenceProtocol<'p> + IntoPy { - type Index: for<'a> FromPyObject<'a, 'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Result: Into>; } diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index 8b1260dc957..732917961a0 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -258,7 +258,7 @@ impl PyNumberProtocol for RhsArithmetic { Ok(format!("{:?} | RA", other)) } - fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> PyResult { + fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny<'p>>) -> PyResult { Ok(format!("{:?} ** RA", other)) } } @@ -302,7 +302,7 @@ impl PyNumberProtocol for LhsAndRhsArithmetic { Ok(format!("{:?} - RA", other)) } - fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> PyResult { + fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny<'p>>) -> PyResult { Ok(format!("{:?} ** RA", other)) } diff --git a/tests/test_datetime.rs b/tests/test_datetime.rs index d1ce377d9a4..7dea2ef1e89 100644 --- a/tests/test_datetime.rs +++ b/tests/test_datetime.rs @@ -64,7 +64,7 @@ fn test_date_check() { let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "date", "2018, 1, 1").unwrap(); + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "date", "2018, 1, 1").unwrap(); assert_check_exact!(PyDate_Check, obj); assert_check_only!(PyDate_Check, sub_obj); @@ -76,7 +76,7 @@ fn test_time_check() { let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "time", "12, 30, 15").unwrap(); + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "time", "12, 30, 15").unwrap(); assert_check_exact!(PyTime_Check, obj); assert_check_only!(PyTime_Check, sub_obj); @@ -88,7 +88,7 @@ fn test_datetime_check() { let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "datetime", "2018, 1, 1, 13, 30, 15") + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "datetime", "2018, 1, 1, 13, 30, 15") .map_err(|e| e.print(py)) .unwrap(); @@ -103,7 +103,7 @@ fn test_delta_check() { let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "timedelta", "1, -3").unwrap(); + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "timedelta", "1, -3").unwrap(); assert_check_exact!(PyDelta_Check, obj); assert_check_only!(PyDelta_Check, sub_obj); @@ -127,7 +127,7 @@ fn test_datetime_utc() { let locals = [("dt", dt)].into_py_dict(py); let offset: f32 = py - .eval("dt.utcoffset().total_seconds()", None, Some(locals)) + .eval("dt.utcoffset().total_seconds()", None, Some(&locals)) .unwrap() .extract() .unwrap(); diff --git a/tests/test_dunder.rs b/tests/test_dunder.rs index 3ae14908b52..c1eaeb6569e 100644 --- a/tests/test_dunder.rs +++ b/tests/test_dunder.rs @@ -53,11 +53,11 @@ struct Iterator { #[pyproto] impl<'p> PyIterProtocol for Iterator { - fn __iter__(slf: PyRef<'p, Self>) -> PyResult> { + fn __iter__(slf: PyRef<'p, 'p, Self>) -> PyResult> { Ok(slf.into()) } - fn __next__(mut slf: PyRefMut<'p, Self>) -> PyResult> { + fn __next__(mut slf: PyRefMut<'p, 'p, Self>) -> PyResult> { Ok(slf.iter.next()) } } @@ -375,9 +375,9 @@ impl<'p> PyContextProtocol<'p> for ContextManager { fn __exit__( &mut self, - ty: Option<&'p PyType>, - _value: Option<&'p PyAny>, - _traceback: Option<&'p PyAny>, + ty: Option<&'p PyType<'p>>, + _value: Option<&'p PyAny<'p>>, + _traceback: Option<&'p PyAny<'p>>, ) -> PyResult { let gil = GILGuard::acquire(); self.exit_called = true; diff --git a/tests/test_getter_setter.rs b/tests/test_getter_setter.rs index 7610e81fa5b..1d29436c2f4 100644 --- a/tests/test_getter_setter.rs +++ b/tests/test_getter_setter.rs @@ -38,7 +38,7 @@ impl ClassWithProperties { } #[getter] - fn get_data_list<'py>(&self, py: Python<'py>) -> &'py PyList { + fn get_data_list<'py>(&self, py: Python<'py>) -> PyList<'py> { PyList::new(py, &[self.num]) } } @@ -64,7 +64,7 @@ fn class_with_properties() { py.run( "assert C.DATA.__doc__ == 'a getter for data'", None, - Some(d), + Some(&d), ) .unwrap(); } diff --git a/tests/test_mapping.rs b/tests/test_mapping.rs index 17a0203bf57..3aeeeb64089 100644 --- a/tests/test_mapping.rs +++ b/tests/test_mapping.rs @@ -75,8 +75,8 @@ fn test_getitem() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("m = Mapping(['1', '2', '3']); assert m['1'] == 0"); run("m = Mapping(['1', '2', '3']); assert m['2'] == 1"); @@ -90,8 +90,8 @@ fn test_setitem() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("m = Mapping(['1', '2', '3']); m['1'] = 4; assert m['1'] == 4"); run("m = Mapping(['1', '2', '3']); m['0'] = 0; assert m['0'] == 0"); @@ -106,8 +106,8 @@ fn test_delitem() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run( "m = Mapping(['1', '2', '3']); del m['1']; assert len(m) == 2; \ @@ -123,7 +123,7 @@ fn test_reversed() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); run("m = Mapping(['1', '2']); assert set(reversed(m)) == {'1', '2'}"); } diff --git a/tests/test_methods.rs b/tests/test_methods.rs index 7fa40fc330c..4dd0a0c99e0 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -27,8 +27,8 @@ fn instance_method() { let obj_ref = obj.borrow(); assert_eq!(obj_ref.method().unwrap(), 42); let d = [("obj", obj)].into_py_dict(py); - py.run("assert obj.method() == 42", None, Some(d)).unwrap(); - py.run("assert obj.method.__doc__ == 'Test method'", None, Some(d)) + py.run("assert obj.method() == 42", None, Some(&d)).unwrap(); + py.run("assert obj.method.__doc__ == 'Test method'", None, Some(&d)) .unwrap(); } @@ -54,8 +54,8 @@ fn instance_method_with_args() { let obj_ref = obj.borrow(); assert_eq!(obj_ref.method(6).unwrap(), 42); let d = [("obj", obj)].into_py_dict(py); - py.run("assert obj.method(3) == 21", None, Some(d)).unwrap(); - py.run("assert obj.method(multiplier=6) == 42", None, Some(d)) + py.run("assert obj.method(3) == 21", None, Some(&d)).unwrap(); + py.run("assert obj.method(multiplier=6) == 42", None, Some(&d)) .unwrap(); } @@ -83,7 +83,7 @@ fn class_method() { let d = [("C", py.get_type::())].into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -113,7 +113,7 @@ fn class_method_with_args() { py.run( "assert C.method('abc') == 'ClassMethodWithArgs.method(abc)'", None, - Some(d), + Some(&d), ) .unwrap(); } @@ -144,7 +144,7 @@ fn static_method() { let d = [("C", py.get_type::())].into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -173,7 +173,7 @@ fn static_method_with_args() { assert_eq!(StaticMethodWithArgs::method(py, 1234).unwrap(), "0x4d2"); let d = [("C", py.get_type::())].into_py_dict(py); - py.run("assert C.method(1337) == '0x539'", None, Some(d)) + py.run("assert C.method(1337) == '0x539'", None, Some(&d)) .unwrap(); } @@ -353,7 +353,7 @@ fn meth_doc() { let py = gil.python(); let d = [("C", py.get_type::())].into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -435,7 +435,7 @@ fn method_with_pyclassarg() { let obj2 = PyCell::new(py, MethodWithPyClassArg { value: 10 }).unwrap(); let objs = [("obj1", obj1), ("obj2", obj2)].into_py_dict(py); let run = |code| { - py.run(code, None, Some(objs)) + py.run(code, None, Some(&objs)) .map_err(|e| e.print(py)) .unwrap() }; diff --git a/tests/test_module.rs b/tests/test_module.rs index 6539bdf9797..b7d1518cbb0 100644 --- a/tests/test_module.rs +++ b/tests/test_module.rs @@ -80,7 +80,7 @@ fn test_module_with_functions() { .into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -116,7 +116,7 @@ fn test_module_renaming() { py.run( "assert different_name.__name__ == 'other_name'", None, - Some(d), + Some(&d), ) .unwrap(); } diff --git a/tests/test_pyself.rs b/tests/test_pyself.rs index aabc5d9a4b5..2b1f052b787 100644 --- a/tests/test_pyself.rs +++ b/tests/test_pyself.rs @@ -17,10 +17,10 @@ struct Reader { #[pymethods] impl Reader { - fn clone_ref(slf: &PyCell) -> &PyCell { + fn clone_ref<'py>(slf: &'py PyCell<'py, Self>) -> &'py PyCell<'py, Self> { slf } - fn clone_ref_with_py<'py>(slf: &'py PyCell, _py: Python<'py>) -> &'py PyCell { + fn clone_ref_with_py<'py>(slf: &'py PyCell, _py: Python<'py>) -> &'py PyCell<'py, Self> { slf } fn get_iter(slf: &PyCell, keys: Py) -> PyResult { diff --git a/tests/test_sequence.rs b/tests/test_sequence.rs index c0a21c94f70..64beb18a8d6 100644 --- a/tests/test_sequence.rs +++ b/tests/test_sequence.rs @@ -62,7 +62,7 @@ impl PySequenceProtocol for ByteSequence { } } - fn __concat__(&self, other: PyRef<'p, Self>) -> PyResult { + fn __concat__(&self, other: PyRef<'p, 'p, Self>) -> PyResult { let mut elements = self.elements.clone(); elements.extend_from_slice(&other.elements); Ok(Self { elements }) @@ -87,8 +87,8 @@ fn test_getitem() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2, 3]); assert s[0] == 1"); run("s = ByteSequence([1, 2, 3]); assert s[1] == 2"); @@ -103,8 +103,8 @@ fn test_setitem() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2, 3]); s[0] = 4; assert list(s) == [4, 2, 3]"); err("s = ByteSequence([1, 2, 3]); s[0] = 'hello'"); @@ -116,8 +116,8 @@ fn test_delitem() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2, 3]); del s[0]; assert list(s) == [2, 3]"); run("s = ByteSequence([1, 2, 3]); del s[1]; assert list(s) == [1, 3]"); @@ -133,7 +133,7 @@ fn test_contains() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); run("s = ByteSequence([1, 2, 3]); assert 1 in s"); run("s = ByteSequence([1, 2, 3]); assert 2 in s"); @@ -148,8 +148,8 @@ fn test_concat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s1 = ByteSequence([1, 2]); s2 = ByteSequence([3, 4]); assert list(s1+s2) == [1, 2, 3, 4]"); err("s1 = ByteSequence([1, 2]); s2 = 'hello'; s1 + s2"); @@ -161,8 +161,8 @@ fn test_inplace_concat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2]); s += ByteSequence([3, 4]); assert list(s) == [1, 2, 3, 4]"); err("s = ByteSequence([1, 2]); s += 'hello'"); @@ -174,8 +174,8 @@ fn test_repeat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s1 = ByteSequence([1, 2, 3]); s2 = s1*2; assert list(s2) == [1, 2, 3, 1, 2, 3]"); err("s1 = ByteSequence([1, 2, 3]); s2 = s1*-1; assert list(s2) == [1, 2, 3, 1, 2, 3]"); @@ -187,8 +187,8 @@ fn test_inplace_repeat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2]); s *= 3; assert list(s) == [1, 2, 1, 2, 1, 2]"); err("s = ByteSequence([1, 2); s *= -1"); diff --git a/tests/test_various.rs b/tests/test_various.rs index e5c0aefc294..c8bfac483f3 100644 --- a/tests/test_various.rs +++ b/tests/test_various.rs @@ -128,11 +128,11 @@ impl PickleSupport { } pub fn __reduce__<'py>( - slf: PyCell, + slf: &PyCell<'py, Self>, py: Python<'py>, - ) -> PyResult<(PyObject, PyTuple<'py>, PyObject)> { - let cls = slf.getattr(py, "__class__")?; - let dict = slf.getattr(py, "__dict__")?; + ) -> PyResult<(PyAny<'py>, PyTuple<'py>, PyAny<'py>)> { + let cls = slf.getattr("__class__")?; + let dict = slf.getattr("__dict__")?; Ok((cls, PyTuple::empty(py), dict)) } } From f170e602fb6d41dc43331b76d015f889eca8dace Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Thu, 30 Apr 2020 13:02:38 +0100 Subject: [PATCH 09/11] Working test_pymethods! --- pyo3-derive-backend/src/pymethod.rs | 8 +-- src/conversion.rs | 10 +--- src/derive_utils.rs | 88 ++++++++++++++--------------- src/err.rs | 2 +- src/object.rs | 8 +-- src/types/any.rs | 6 +- src/types/boolobject.rs | 6 +- src/types/mod.rs | 9 ++- tests/test_methods.rs | 10 ++-- 9 files changed, 69 insertions(+), 78 deletions(-) diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index 3d19983e5a0..c02827f6ed3 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -128,7 +128,7 @@ fn impl_wrap_common( let _py = _pool.python(); pyo3::run_callback(_py, || { #slf - let _args = _py.from_borrowed_ptr::(_args); + let _args = pyo3::PyAny::raw_borrowed(_py, &_args).downcast::()?; let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); #body @@ -451,8 +451,8 @@ fn impl_arg_params_(spec: &FnSpec<'_>, body: TokenStream, into_result: TokenStre ]; let mut output = [None; #num_normal_params]; - let mut _args = _args; - let mut _kwargs = _kwargs; + let _args = _args; + let _kwargs = _kwargs; let (_args, _kwargs) = pyo3::derive_utils::parse_fn_args( Some(_LOCATION), @@ -503,7 +503,7 @@ fn impl_arg_param( }; } else if spec.is_kwargs(&name) { return quote! { - let #arg_name = _kwargs; + let #arg_name = _kwargs.as_ref(); }; } let arg_value = quote!(output[#option_pos]); diff --git a/src/conversion.rs b/src/conversion.rs index 356e995fa7b..d7cd0fca321 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -64,16 +64,10 @@ where impl<'a, T> IntoPyPointer for &'a T where - T: AsPyPointer, + T: IntoPyPointer + Clone, { fn into_ptr(self) -> *mut ffi::PyObject { - let ptr = self.as_ptr(); - if !ptr.is_null() { - unsafe { - ffi::Py_INCREF(ptr); - } - } - ptr + self.clone().into_ptr() } } diff --git a/src/derive_utils.rs b/src/derive_utils.rs index b4124c93d46..a3581b0c245 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -40,7 +40,7 @@ pub fn parse_fn_args<'py>( accept_args: bool, accept_kwargs: bool, output: &mut [Option<&'py PyAny<'py>>], -) -> PyResult<(Cow<'py, PyTuple<'py>>, Option>>)> { +) -> PyResult<(PyTuple<'py>, Option>)> { let nargs = args.len(); let mut used_args = 0; macro_rules! raise_error { @@ -49,58 +49,47 @@ pub fn parse_fn_args<'py>( )))) } - let kwargs = match kwargs { - Some(kwargs) => { - let mut unrecognised_kwargs = Cow::Borrowed(kwargs); - // Iterate through the parameters and assign values to output: - for (i, (p, out)) in params.iter().zip(output).enumerate() { - *out = match kwargs.get_item(p.name) { - Some(kwarg) => { - if i < nargs { - raise_error!("got multiple values for argument: {}", p.name) - } + // Copy unrecognised_kwargs not to modify it + let unrecognized_kwargs = kwargs.as_ref().map(|d| d.copy()).transpose()?; - // Delete kwarg from unrecognised set (first making a copy if needed) - if let Cow::Borrowed(k) = &unrecognised_kwargs{ - unrecognised_kwargs = Cow::Owned(k.copy()?); - } - unrecognised_kwargs.del_item(p.name)?; + // Iterate through the parameters and assign values to output: + for (i, (p, out)) in params.iter().zip(output).enumerate() { + *out = match kwargs.and_then(|d| d.get_item(p.name)) { + Some(kwarg) => { + if i < nargs { + raise_error!("got multiple values for argument: {}", p.name) + } - Some(kwarg) + unrecognized_kwargs.as_ref().unwrap().del_item(p.name)?; + Some(kwarg) + } + None => { + if p.kw_only { + if !p.is_optional { + raise_error!("missing required keyword-only argument: {}", p.name) } - None => { - if p.kw_only { - if !p.is_optional { - raise_error!("missing required keyword-only argument: {}", p.name) - } - None - } else if i < nargs { - used_args += 1; - Some(args.get_item(i)) - } else { - if !p.is_optional { - raise_error!("missing required positional argument: {}", p.name) - } - None - } + None + } else if i < nargs { + used_args += 1; + Some(args.get_item(i)) + } else { + if !p.is_optional { + raise_error!("missing required positional argument: {}", p.name) } + None } } + } + } - if unrecognised_kwargs.is_empty() { - None - } else if !accept_kwargs { - // Raise an error when we get an unknown key - let (key, _) = unrecognised_kwargs.iter().next().unwrap(); - raise_error!("got an unexpected keyword argument: {}", key) - } else { - Some(unrecognised_kwargs) - } - - }, - None => None - }; + let kwargs = unrecognized_kwargs; + let is_kwargs_empty = kwargs.as_ref().map_or(true, |dict| dict.is_empty()); + // Raise an error when we get an unknown key + if !accept_kwargs && !is_kwargs_empty { + let (key, _) = kwargs.as_ref().unwrap().iter().next().unwrap(); + raise_error!("got an unexpected keyword argument: {}", key) + } // Raise an error when we get too many positional args if !accept_args && used_args < nargs { raise_error!( @@ -112,9 +101,14 @@ pub fn parse_fn_args<'py>( } // Adjust the remaining args let args = if accept_args { - Cow::Owned(args.slice(used_args as isize, nargs as isize)) + args.slice(used_args as isize, nargs as isize) + } else { + args.clone() + }; + let kwargs = if accept_kwargs && is_kwargs_empty { + None } else { - Cow::Borrowed(args) + kwargs }; Ok((args, kwargs)) diff --git a/src/err.rs b/src/err.rs index 88a6170df19..a9af44985da 100644 --- a/src/err.rs +++ b/src/err.rs @@ -141,7 +141,7 @@ impl PyErr { if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 { PyErr { ptype: unsafe { Py::from_borrowed_ptr(ffi::PyExceptionInstance_Class(ptr)) }, - pvalue: PyErrValue::Value(obj.into()), + pvalue: PyErrValue::Value(obj.clone().into()), ptraceback: None, } } else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 { diff --git a/src/object.rs b/src/object.rs index 8c5ff37e7f3..e9c0a92da3b 100644 --- a/src/object.rs +++ b/src/object.rs @@ -266,12 +266,12 @@ impl PyObject { } } -impl<'a, T> std::convert::From<&'a T> for PyObject +impl<'a, 'py, T> std::convert::From for PyObject where - T: AsPyPointer, + T: IntoPyPointer + PyNativeType<'py> { - fn from(ob: &'a T) -> Self { - unsafe { PyObject::from_non_null(NonNull::new(ob.as_ptr()).expect("Null ptr")) } + fn from(ob: T) -> Self { + unsafe { PyObject::from_non_null(NonNull::new(ob.into_ptr()).expect("Null ptr")) } } } diff --git a/src/types/any.rs b/src/types/any.rs index 613c33f91a7..e7c232c1add 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -68,11 +68,15 @@ impl<'py> PyAny<'py> { let PyAny(ptr, _) = self; ptr } + + pub fn raw_borrowed<'a>(_py: Python<'py>, ptr_ref: &'a *mut ffi::PyObject) -> &'a Self { + unsafe { std::mem::transmute(ptr_ref) } + } } impl Clone for PyAny<'_> { fn clone(&self) -> Self { - unsafe { ffi::Py_INCREF(self.0.as_ptr()); }; + unsafe { ffi::Py_INCREF(self.0.as_ptr()); } Self(self.0, PhantomData) } } diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 0ccf4c4a67d..43596bc4422 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -44,7 +44,7 @@ impl ToPyObject for bool { impl FromPy for PyObject { #[inline] fn from_py(other: bool, py: Python) -> Self { - PyBool::new(py, other).into() + PyBool::new(py, other).clone().into() } } @@ -71,7 +71,7 @@ mod test { assert!(PyBool::new(py, true).is_true()); let t: &PyAny = PyBool::new(py, true).into(); assert_eq!(true, t.extract().unwrap()); - assert_eq!(true.to_object(py), PyBool::new(py, true).into()); + assert_eq!(true.to_object(py), PyBool::new(py, true).clone().into()); } #[test] @@ -81,6 +81,6 @@ mod test { assert!(!PyBool::new(py, false).is_true()); let t: &PyAny = PyBool::new(py, false).into(); assert_eq!(false, t.extract().unwrap()); - assert_eq!(false.to_object(py), PyBool::new(py, false).into()); + assert_eq!(false.to_object(py), PyBool::new(py, false).clone().into()); } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 393be443782..2bcc128a6e3 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -67,11 +67,10 @@ macro_rules! pyobject_native_type_common ( } } - impl<'py $(, $type_param $(: $bound)?)*> std::convert::From<$name<'py $(,$type_param)*>> for $crate::PyObject - { - fn from(ob: $name<'py $(,$type_param)*>) -> Self { - use $crate::{IntoPyPointer, PyNativeType}; - unsafe { Self::from_owned_ptr(ob.py(), ob.into_ptr()) } + impl<'py $(, $type_param $(: $bound)?)*> $crate::IntoPy<$crate::PyObject> for $name<'py $(,$type_param)*> { + fn into_py(self, py: $crate::Python) -> $crate::PyObject { + use $crate::IntoPyPointer; + unsafe { $crate::PyObject::from_owned_ptr(py, self.into_ptr()) } } } } diff --git a/tests/test_methods.rs b/tests/test_methods.rs index 4dd0a0c99e0..b6b10d447da 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -26,7 +26,7 @@ fn instance_method() { let obj = PyCell::new(py, InstanceMethod { member: 42 }).unwrap(); let obj_ref = obj.borrow(); assert_eq!(obj_ref.method().unwrap(), 42); - let d = [("obj", obj)].into_py_dict(py); + let d = [("obj", &obj)].into_py_dict(py); py.run("assert obj.method() == 42", None, Some(&d)).unwrap(); py.run("assert obj.method.__doc__ == 'Test method'", None, Some(&d)) .unwrap(); @@ -53,7 +53,7 @@ fn instance_method_with_args() { let obj = PyCell::new(py, InstanceMethodWithArgs { member: 7 }).unwrap(); let obj_ref = obj.borrow(); assert_eq!(obj_ref.method(6).unwrap(), 42); - let d = [("obj", obj)].into_py_dict(py); + let d = [("obj", &obj)].into_py_dict(py); py.run("assert obj.method(3) == 21", None, Some(&d)).unwrap(); py.run("assert obj.method(multiplier=6) == 42", None, Some(&d)) .unwrap(); @@ -217,7 +217,7 @@ impl MethArgs { args: &PyTuple, kwargs: Option<&PyDict>, ) -> PyResult { - Ok([args.into(), kwargs.to_object(py)].to_object(py)) + Ok([args.clone().into(), kwargs.to_object(py)].to_object(py)) } #[args(args = "*", kwargs = "**")] @@ -228,7 +228,7 @@ impl MethArgs { args: &PyTuple, kwargs: Option<&PyDict>, ) -> PyObject { - [a.to_object(py), args.into(), kwargs.to_object(py)].to_object(py) + [a.to_object(py), args.clone().into(), kwargs.to_object(py)].to_object(py) } #[args(a, b = 2, "*", c = 3)] @@ -513,7 +513,7 @@ impl FromSequence { fn new(seq: Option<&pyo3::types::PySequence>) -> PyResult { if let Some(seq) = seq { Ok(FromSequence { - numbers: seq.as_ref().extract::>()?, + numbers: seq.as_ref().extract()?, }) } else { Ok(FromSequence::default()) From 58002d204e4b3bf196d66627ca043d8b9bd075df Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 1 May 2020 00:57:14 +0100 Subject: [PATCH 10/11] Tests all compile; not yet all passing! --- guide/src/class.md | 1 - pyo3-derive-backend/src/func.rs | 7 ++- pyo3-derive-backend/src/pyclass.rs | 41 +++++++----- pyo3-derive-backend/src/pymethod.rs | 2 +- src/conversion.rs | 2 +- src/derive_utils.rs | 5 +- src/err.rs | 2 +- src/exceptions.rs | 6 +- src/freelist.rs | 7 ++- src/instance.rs | 40 +++++------- src/lib.rs | 2 +- src/object.rs | 2 +- src/objectprotocol.rs | 2 +- src/pycell.rs | 44 +++++++------ src/pyclass.rs | 25 ++++---- src/pyclass_init.rs | 25 ++++---- src/type_marker.rs | 98 +++++++++++++++++++++++++++++ src/type_object.rs | 36 +++-------- src/types/any.rs | 6 +- src/types/boolobject.rs | 4 +- src/types/bytearray.rs | 3 +- src/types/bytes.rs | 4 +- src/types/complex.rs | 4 +- src/types/datetime.rs | 16 +++-- src/types/dict.rs | 4 +- src/types/floatob.rs | 5 +- src/types/list.rs | 4 +- src/types/mod.rs | 50 ++++++++------- src/types/module.rs | 5 +- src/types/num.rs | 4 +- src/types/set.rs | 7 ++- src/types/slice.rs | 4 +- src/types/string.rs | 4 +- src/types/tuple.rs | 4 +- src/types/typeobject.rs | 6 +- src/unscoped.rs | 28 --------- tests/test_buffer_protocol.rs | 2 +- tests/test_datetime.rs | 12 +--- tests/test_dunder.rs | 4 +- tests/test_inheritance.rs | 10 +-- tests/test_module.rs | 2 +- tests/test_pyself.rs | 11 ++-- tests/test_variable_arguments.rs | 6 +- 43 files changed, 322 insertions(+), 234 deletions(-) create mode 100644 src/type_marker.rs delete mode 100644 src/unscoped.rs diff --git a/guide/src/class.md b/guide/src/class.md index 78a9cee1cd3..6a2b689c39b 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -36,7 +36,6 @@ unsafe impl pyo3::PyTypeInfo for MyClass { type BaseLayout = pyo3::pycell::PyCellBase; type Layout = PyCell; type Initializer = PyClassInitializer; - type AsRefTarget = PyCell; const NAME: &'static str = "MyClass"; const MODULE: Option<&'static str> = None; diff --git a/pyo3-derive-backend/src/func.rs b/pyo3-derive-backend/src/func.rs index b1d1497f6f4..c43e128528a 100644 --- a/pyo3-derive-backend/src/func.rs +++ b/pyo3-derive-backend/src/func.rs @@ -131,15 +131,16 @@ pub(crate) fn impl_method_proto( let mut slf_ty = get_arg_ty(sig, 0); // update the type if no lifetime was given: - // PyRef --> PyRef<'p, Self> + // PyRef --> PyRef<'p, 'p, Self> if let syn::Type::Path(ref mut path) = slf_ty { if let syn::PathArguments::AngleBracketed(ref mut args) = path.path.segments[0].arguments { if let syn::GenericArgument::Lifetime(_) = args.args[0] { } else { - let lt = syn::parse_quote! {'p}; - args.args.insert(0, lt); + // Insert two 'p lifetimes for PyRef / PyRefMut + args.args.insert(0, syn::parse_quote! {'p}); + args.args.insert(0, syn::parse_quote! {'p}); } } } diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index ad3ee399058..c523c055dfd 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -43,7 +43,7 @@ impl Default for PyClassArgs { // We need the 0 as value for the constant we're later building using quote for when there // are no other flags flags: vec![parse_quote! { 0 }], - base: parse_quote! { pyo3::PyAny }, + base: parse_quote! { pyo3::type_marker::Any }, has_extends: false, } } @@ -312,14 +312,14 @@ fn impl_class( let weakref = if has_weakref { quote! { pyo3::pyclass_slots::PyClassWeakRefSlot } } else if attr.has_extends { - quote! { ::WeakRef } + quote! { >::WeakRef } } else { quote! { pyo3::pyclass_slots::PyClassDummySlot } }; let dict = if has_dict { quote! { pyo3::pyclass_slots::PyClassDictSlot } } else if attr.has_extends { - quote! { ::Dict } + quote! { >::Dict } } else { quote! { pyo3::pyclass_slots::PyClassDummySlot } }; @@ -355,14 +355,14 @@ fn impl_class( quote! { 0 } }; let base_layout = if attr.has_extends { - quote! { ::LayoutAsBase } + quote! { >::LayoutAsBase } } else { - quote! { pyo3::pycell::PyCellBase<'py, pyo3::PyAny<'py>> } + quote! { pyo3::pycell::PyCellBase<'py, pyo3::type_marker::Any> } }; let base_nativetype = if attr.has_extends { - quote! { ::BaseNativeType } + quote! { >::RootType } } else { - quote! { pyo3::PyAny } + quote! { pyo3::type_marker::Any } }; // If #cls is not extended type, we allow Self->PyObject conversion @@ -381,16 +381,10 @@ fn impl_class( Ok(quote! { unsafe impl<'py> pyo3::type_object::PyTypeInfo<'py> for #cls { type Type = #cls; - type BaseType = #base<'py>; - type Layout = pyo3::pycell::PyCellLayout<'py, Self>; - type BaseLayout = #base_layout; - type Initializer = pyo3::pyclass_init::PyClassInitializer<'py, Self>; - type AsRefTarget = pyo3::PyCell<'py, Self>; const NAME: &'static str = #cls_name; const MODULE: Option<&'static str> = #module; const DESCRIPTION: &'static str = #doc; - const FLAGS: usize = #(#flags)|* | #extended; #[inline] fn type_object() -> &'static pyo3::ffi::PyTypeObject { @@ -403,7 +397,7 @@ fn impl_class( impl<'py> pyo3::PyClass<'py> for #cls { type Dict = #dict; type WeakRef = #weakref; - type BaseNativeType = #base_nativetype<'py>; + type RootType = #base_nativetype; } impl<'a, 'py: 'a> pyo3::derive_utils::ExtractExt<'a, 'py> for &'a #cls @@ -416,6 +410,25 @@ fn impl_class( type Target = pyo3::PyRefMut<'a, 'py, #cls>; } + impl<'py> pyo3::type_marker::TypeMarker<'py> for #cls { + type NativeType = pyo3::PyCell<'py, #cls>; + type Layout = pyo3::pycell::PyCellLayout<'py, Self>; + type Initializer = pyo3::pyclass_init::PyClassInitializer<'py, Self>; + + const FLAGS: usize = #(#flags)|* | #extended; + + fn type_object() -> &'static pyo3::ffi::PyTypeObject { + >::type_object() + } + } + + impl<'py> pyo3::type_marker::TypeWithBase<'py> for #cls { + type BaseType = #base; + type BaseNativeType = <#base as pyo3::type_marker::TypeMarker<'py>>::NativeType; + type BaseLayout = #base_layout; + type BaseInitializer = <#base as pyo3::type_marker::TypeMarker<'py>>::Initializer; + } + #into_pyobject #inventory_impl diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index c02827f6ed3..4f090b0dc4c 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -128,7 +128,7 @@ fn impl_wrap_common( let _py = _pool.python(); pyo3::run_callback(_py, || { #slf - let _args = pyo3::PyAny::raw_borrowed(_py, &_args).downcast::()?; + let _args = pyo3::PyAny::raw_borrowed(_py, &_args).downcast::()?; let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); #body diff --git a/src/conversion.rs b/src/conversion.rs index d7cd0fca321..c65673a6f40 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -5,7 +5,7 @@ use crate::err::{self, PyDowncastError, PyResult}; use crate::object::PyObject; use crate::type_object::{PyDowncastImpl, PyTypeInfo}; use crate::types::PyTuple; -use crate::unscoped::Tuple; +use crate::type_marker::Tuple; use crate::{ffi, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; /// This trait represents that **we can do zero-cost conversion from the object diff --git a/src/derive_utils.rs b/src/derive_utils.rs index a3581b0c245..7deb875853d 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -11,7 +11,6 @@ use crate::pyclass_init::PyClassInitializer; use crate::types::{PyAny, PyDict, PyModule, PyTuple}; use crate::{ffi, GILPool, IntoPy, Py, PyCell, PyObject, Python}; use std::cell::UnsafeCell; -use std::borrow::Cow; /// Description of a python parameter; used for `parse_args()`. #[derive(Debug)] @@ -229,14 +228,14 @@ pub trait PyBaseTypeUtils<'py> { type Dict; type WeakRef; type LayoutAsBase; - type BaseNativeType; + type RootType; } impl<'py, T: PyClass<'py>> PyBaseTypeUtils<'py> for T { type Dict = T::Dict; type WeakRef = T::WeakRef; type LayoutAsBase = crate::pycell::PyCellInner<'py, T>; - type BaseNativeType = T::BaseNativeType; + type RootType = T::BaseNativeType; } /// Utility trait to enable &PyClass as a pymethod/function argument diff --git a/src/err.rs b/src/err.rs index a9af44985da..1b45daace7f 100644 --- a/src/err.rs +++ b/src/err.rs @@ -2,7 +2,7 @@ use crate::type_object::PyTypeObject; use crate::types::PyType; -use crate::unscoped::Type; +use crate::type_marker::Type; use crate::{exceptions, ffi}; use crate::{ AsPyPointer, FromPy, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToBorrowedObject, diff --git a/src/exceptions.rs b/src/exceptions.rs index 5addcd3c77f..ceae83d0cfb 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -90,7 +90,7 @@ macro_rules! import_exception { macro_rules! import_exception_type_object { ($module: expr, $name: ident) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::unscoped::Type> { + fn type_object() -> $crate::Py<$crate::type_marker::Type> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -174,7 +174,7 @@ macro_rules! create_exception { macro_rules! create_exception_type_object { ($module: ident, $name: ident, $base: ty) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::unscoped::Type> { + fn type_object() -> $crate::Py<$crate::type_marker::Type> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -216,7 +216,7 @@ macro_rules! impl_native_exception ( } } unsafe impl PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::unscoped::Type> { + fn type_object() -> $crate::Py<$crate::type_marker::Type> { unsafe { $crate::Py::from_borrowed_ptr(ffi::$exc_name) } } } diff --git a/src/freelist.rs b/src/freelist.rs index aa5caf26f9c..8e52c971c84 100644 --- a/src/freelist.rs +++ b/src/freelist.rs @@ -4,7 +4,8 @@ use crate::ffi; use crate::pyclass::{tp_free_fallback, PyClassAlloc}; -use crate::type_object::{PyLayout, PyTypeInfo}; +use crate::type_object::PyLayout; +use crate::type_marker::TypeWithBase; use crate::Python; use std::mem; use std::os::raw::c_void; @@ -70,11 +71,11 @@ impl FreeList { impl<'py, T> PyClassAlloc<'py> for T where - T: PyTypeInfo<'py> + PyClassWithFreeList, + T: TypeWithBase<'py> + PyClassWithFreeList, { unsafe fn alloc(_py: Python) -> *mut Self::Layout { if let Some(obj) = ::get_free_list().pop() { - ffi::PyObject_Init(obj, ::type_object() as *const _ as _); + ffi::PyObject_Init(obj, Self::type_object() as *const _ as _); obj as _ } else { crate::pyclass::default_alloc::() as _ diff --git a/src/instance.rs b/src/instance.rs index 7eee94397c5..86127efa27f 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,13 +1,12 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::FromPyPointer; use crate::err::{PyErr, PyResult}; use crate::gil; use crate::object::PyObject; use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl}; -use crate::unscoped::Unscoped; +use crate::type_marker::TypeMarker; use crate::{ ffi, AsPyPointer, IntoPy, IntoPyPointer, PyCell, PyClass, - PyClassInitializer, PyRef, PyRefMut, Python, ToPyObject, + PyClassInitializer, PyRef, PyRefMut, Python, ToPyObject, PyAny, FromPyObject, FromPyPointer }; use std::marker::PhantomData; use std::mem; @@ -134,12 +133,6 @@ impl Py { } } -impl<'py, T: Unscoped<'py>> Py { - pub fn into_scoped(self, py: Python<'py>) -> T::NativeType { - unsafe { T::NativeType::from_owned_ptr(py, self.into_ptr()) } - } -} - /// Retrieves `&'py` types from `Py` or `PyObject`. /// /// # Examples @@ -179,7 +172,7 @@ pub trait AsPyRef<'py>: Sized { impl<'py, T> AsPyRef<'py> for Py where - T: Unscoped<'py> + T: TypeMarker<'py> { type Target = T::NativeType; fn as_ref<'a>(&'a self, _py: Python<'py>) -> &'a Self::Target @@ -283,20 +276,19 @@ impl std::convert::From> for PyObject { } } -// impl<'a, 'py, T> FromPyObject<'a, 'py> for Py -// where -// T: PyTypeInfo<'py>, -// &'a T::AsRefTarget: FromPyObject<'a, 'py>, -// T::AsRefTarget: 'a + 'py + AsPyPointer, -// { -// /// Extracts `Self` from the source `PyObject`. -// fn extract(ob: &PyAny<'py>) -> PyResult { -// unsafe { -// ob.extract::<&T::AsRefTarget>() -// .map(|val| Py::from_borrowed_ptr(val.as_ptr())) -// } -// } -// } +impl<'py, T> FromPyObject<'_, 'py> for Py +where + T: TypeMarker<'py>, + T::NativeType: 'py + FromPyPointer<'py> + AsPyPointer, +{ + /// Extracts `Self` from the source `PyObject`. + fn extract(ob: &PyAny<'py>) -> PyResult { + unsafe { + let val = ob.py().from_borrowed_ptr_or_err::(ob.as_ptr())?; + Ok(Py::from_borrowed_ptr(val.as_ptr())) + } + } +} /// Reference to a converted [ToPyObject]. /// diff --git a/src/lib.rs b/src/lib.rs index 200700ea534..3f067659cc7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,9 +195,9 @@ pub mod pyclass; pub mod pyclass_init; pub mod pyclass_slots; mod python; +pub mod type_marker; pub mod type_object; pub mod types; -pub mod unscoped; /// The proc macros, which are also part of the prelude. pub mod proc_macro { diff --git a/src/object.rs b/src/object.rs index e9c0a92da3b..e6e3a094b9d 100644 --- a/src/object.rs +++ b/src/object.rs @@ -5,7 +5,7 @@ use crate::ffi; use crate::gil; use crate::instance::{AsPyRef, PyNativeType}; use crate::types::{PyAny, PyDict}; -use crate::unscoped::Tuple; +use crate::type_marker::Tuple; use crate::{AsPyPointer, Py, Python}; use crate::{FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, ToBorrowedObject, ToPyObject}; use std::ptr::NonNull; diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 5612f7ab2a3..e8ed12fc80e 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -4,7 +4,7 @@ use crate::class::basic::CompareOp; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions::TypeError; use crate::types::{PyAny, PyDict, PyIterator, PyString, PyType}; -use crate::unscoped::Tuple; +use crate::type_marker::Tuple; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyNativeType, PyObject, PyTryFrom, Python, ToBorrowedObject, ToPyObject, diff --git a/src/pycell.rs b/src/pycell.rs index d463bf315bb..6ffe647a794 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -2,8 +2,9 @@ use crate::conversion::{AsPyPointer, FromPyPointer}; use crate::pyclass_init::PyClassInitializer; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; -use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout, PyTypeInfo}; -use crate::{gil, ffi, FromPy, PyAny, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python}; +use crate::type_marker::TypeMarker; +use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout}; +use crate::{gil, ffi, FromPy, PyAny, PyClass, PyErr, PyObject, PyResult, Python}; use std::cell::{Cell, UnsafeCell, RefCell}; use std::fmt; use std::marker::PhantomData; @@ -15,14 +16,14 @@ use std::ptr::NonNull; /// This is necessary for sharing BorrowFlag between parents and children. #[doc(hidden)] #[repr(C)] -pub struct PyCellBase<'py, T: PyTypeInfo<'py>> { +pub struct PyCellBase<'py, T: TypeMarker<'py>> { ob_base: T::Layout, borrow_flag: Cell, } unsafe impl<'py, T> PyLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo<'py> + PyNativeType<'py>, + T: TypeMarker<'py>, T::Layout: PySizedLayout<'py, T>, { const IS_NATIVE_TYPE: bool = true; @@ -31,14 +32,14 @@ where // Thes impls ensures `PyCellBase` can be a base type. impl<'py, T> PySizedLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo<'py> + PyNativeType<'py>, + T: TypeMarker<'py>, T::Layout: PySizedLayout<'py, T>, { } unsafe impl<'py, T> PyBorrowFlagLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo<'py> + PyNativeType<'py>, + T: TypeMarker<'py>, T::Layout: PySizedLayout<'py, T>, { } @@ -83,11 +84,11 @@ impl<'py, T: PyClass<'py>> PyCellInner<'py, T> { self.value.get() } fn get_borrow_flag(&self) -> BorrowFlag { - let base = (&self.ob_base) as *const _ as *const PyCellBase; + let base = (&self.ob_base) as *const _ as *const PyCellBase; unsafe { (*base).borrow_flag.get() } } fn set_borrow_flag(&self, flag: BorrowFlag) { - let base = (&self.ob_base) as *const _ as *const PyCellBase; + let base = (&self.ob_base) as *const _ as *const PyCellBase; unsafe { (*base).borrow_flag.set(flag) } } } @@ -109,7 +110,7 @@ impl<'py, T: PyClass<'py>> PyCellLayout<'py, T> { if base.is_null() { return Err(PyErr::fetch(py)); } - let base = base as *mut PyCellBase; + let base = base as *mut PyCellBase; (*base).borrow_flag = Cell::new(BorrowFlag::UNUSED); let self_ = base as *mut Self; (*self_).dict = T::Dict::new(); @@ -198,11 +199,10 @@ unsafe impl<'py, T: PyClass<'py>> PyLayout<'py, T> for PyCellLayout<'py, T> { /// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1"); /// ``` #[repr(transparent)] -#[derive(Clone)] pub struct PyCell<'py, T: PyClass<'py>>(PyAny<'py>, PhantomData>); -crate::pyobject_native_type_common!(PyCell<'py, T: PyClass<'py> >); -crate::pyobject_native_type_extract!(PyCell<'py, T: PyClass<'py> >); +crate::pyobject_native_type_common!(PyCell<'py, T: PyClass<'py>>); +crate::pyobject_native_type_extract!(PyCell<'py, T: PyClass<'py>>); impl<'py, T: PyClass<'py>> PyCell<'py, T> { /// Make new `PyCell` on the Python heap and returns the reference of it. @@ -427,6 +427,12 @@ impl<'py, T: PyClass<'py> + fmt::Debug> fmt::Debug for PyCell<'py, T> { } } +impl<'py, T: PyClass<'py>> Clone for PyCell<'py, T> { + fn clone(&self) -> Self { + Self(self.0.clone(), PhantomData) + } +} + /// Wraps a borrowed reference to a value in a `PyCell`. /// /// See the [`PyCell`](struct.PyCell.html) documentation for more. @@ -478,17 +484,17 @@ impl<'py, T: PyClass<'py>> PyRef<'_, 'py, T> { impl<'py, T, U> AsRef for PyRef<'_, 'py, T> where - T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, U: PyClass<'py>, { - fn as_ref(&self) -> &T::BaseType { + fn as_ref(&self) -> &U { unsafe { &*self.inner.ob_base.get_ptr() } } } impl<'a, 'py, T, U> PyRef<'a, 'py, T> where - T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, U: PyClass<'py>, { /// Get `PyRef`. @@ -595,7 +601,7 @@ impl<'py, T: PyClass<'py>> PyRefMut<'_, 'py, T> { impl<'py, T, U> AsRef for PyRefMut<'_, 'py, T> where - T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, U: PyClass<'py>, { fn as_ref(&self) -> &T::BaseType { @@ -605,8 +611,8 @@ where impl<'py, T, U> AsMut for PyRefMut<'_, 'py, T> where - T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, - U: PyClass<'py>, +T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, +U: PyClass<'py>, { fn as_mut(&mut self) -> &mut T::BaseType { unsafe { &mut *self.inner.ob_base.get_ptr() } @@ -615,7 +621,7 @@ where impl<'a, 'py, T, U> PyRefMut<'a, 'py, T> where - T: PyClass<'py> + PyTypeInfo<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>>, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, U: PyClass<'py>, { /// Get `PyRef`. diff --git a/src/pyclass.rs b/src/pyclass.rs index 27cd0dbf5d8..77e0d3f033c 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -1,19 +1,22 @@ //! `PyClass` trait use crate::class::methods::{PyMethodDefType, PyMethodsProtocol}; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; +use crate::type_marker::{TypeMarker, TypeWithBase}; use crate::type_object::{type_flags, PyLayout}; use crate::pycell::PyCellLayout; -use crate::{class, ffi, PyErr, PyNativeType, PyResult, PyTypeInfo, Python}; +use crate::pyclass_init::PyNativeTypeInitializer; +use crate::{class, ffi, PyErr, PyResult, PyTypeInfo, Python}; use std::ffi::CString; use std::os::raw::c_void; use std::ptr; #[inline] -pub(crate) unsafe fn default_alloc<'py, T: PyTypeInfo<'py>>() -> *mut ffi::PyObject { +pub(crate) unsafe fn default_alloc<'py, T: TypeWithBase<'py>>() -> *mut ffi::PyObject +{ let type_obj = T::type_object(); // if the class derives native types(e.g., PyDict), call special new if T::FLAGS & type_flags::EXTENDED != 0 && T::BaseLayout::IS_NATIVE_TYPE { - let base_tp = ::type_object(); + let base_tp = T::base_type_object(); if let Some(base_new) = base_tp.tp_new { return base_new(type_obj as *const _ as _, ptr::null_mut(), ptr::null_mut()); } @@ -23,7 +26,7 @@ pub(crate) unsafe fn default_alloc<'py, T: PyTypeInfo<'py>>() -> *mut ffi::PyObj } /// This trait enables custom alloc/dealloc implementations for `T: PyClass`. -pub trait PyClassAlloc<'py>: PyTypeInfo<'py> + Sized { +pub trait PyClassAlloc<'py>: TypeWithBase<'py> + Sized { /// Allocate the actual field for `#[pyclass]`. /// /// # Safety @@ -72,15 +75,15 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) { /// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you don't have to use this trait directly. pub trait PyClass<'py>: 'static + - PyTypeInfo<'py, Layout = PyCellLayout<'py, Self>> + Sized + PyClassAlloc<'py> + PyMethodsProtocol + PyTypeInfo<'py> + TypeWithBase<'py, Layout = PyCellLayout<'py, Self>> + Sized + PyClassAlloc<'py> + PyMethodsProtocol { /// Specify this class has `#[pyclass(dict)]` or not. type Dict: PyClassDict; /// Specify this class has `#[pyclass(weakref)]` or not. type WeakRef: PyClassWeakRef; - /// The closest native ancestor. This is `PyAny` by default, and when you declare - /// `#[pyclass(extends=PyDict)]`, it's `PyDict`. - type BaseNativeType: PyTypeInfo<'py> + PyNativeType<'py>; + /// The closest native ancestor. This is `Any` by default, and when you declare + /// `#[pyclass(extends=Dict)]`, it's `Dict`. + type RootType: TypeMarker<'py, Initializer = PyNativeTypeInitializer<'py, Self::RootType>>; } #[cfg(not(Py_LIMITED_API))] @@ -90,7 +93,7 @@ pub(crate) fn initialize_type_object( type_object: &mut ffi::PyTypeObject, ) -> PyResult<()> where - T: for<'py> PyClass<'py>, + T: for<'py> PyClass<'py> { type_object.tp_doc = match T::DESCRIPTION { // PyPy will segfault if passed only a nul terminator as `tp_doc`, ptr::null() is OK though. @@ -100,7 +103,7 @@ where s => CString::new(s)?.into_raw(), }; - type_object.tp_base = ::type_object() as *const _ as _; + type_object.tp_base = T::base_type_object() as *const _ as _; type_object.tp_name = match module_name { Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME))?.into_raw(), @@ -202,7 +205,7 @@ where } } -fn py_class_flags PyTypeInfo<'py>>(type_object: &mut ffi::PyTypeObject) { +fn py_class_flags<'py, T: TypeMarker<'py>>(type_object: &mut ffi::PyTypeObject) { if type_object.tp_traverse != None || type_object.tp_clear != None || T::FLAGS & type_flags::GC != 0 diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index a486706f7e5..0c49031ee2d 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -1,6 +1,7 @@ //! Initialization utilities for `#[pyclass]`. use crate::pycell::PyCellLayout; -use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo}; +use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout}; +use crate::type_marker::TypeMarker; use crate::{PyClass, PyResult, Python}; use std::marker::PhantomData; @@ -8,15 +9,15 @@ use std::marker::PhantomData; /// /// This trait is intended to use internally for distinguishing `#[pyclass]` and /// Python native types. -pub trait PyObjectInit<'py, T: PyTypeInfo<'py>>: Sized { +pub trait PyObjectInit<'py, T: TypeMarker<'py>>: Sized { fn init_class>(self, layout: &mut L); private_decl! {} } /// Initializer for Python native type, like `PyDict`. -pub struct PyNativeTypeInitializer<'py, T: PyTypeInfo<'py>>(PhantomData, PhantomData>); +pub struct PyNativeTypeInitializer<'py, T: TypeMarker<'py>>(PhantomData, PhantomData>); -impl<'py, T: PyTypeInfo<'py>> PyObjectInit<'py, T> for PyNativeTypeInitializer<'py, T> { +impl<'py, T: TypeMarker<'py>> PyObjectInit<'py, T> for PyNativeTypeInitializer<'py, T> { fn init_class>(self, _layout: &mut L) {} private_impl! {} } @@ -66,14 +67,14 @@ impl<'py, T: PyTypeInfo<'py>> PyObjectInit<'py, T> for PyNativeTypeInitializer<' /// ``` pub struct PyClassInitializer<'py, T: PyClass<'py>> { init: T, - super_init: >::Initializer, + super_init: >::Initializer, } impl<'py, T: PyClass<'py>> PyClassInitializer<'py, T> { /// Constract new initialzer from value `T` and base class' initializer. /// /// We recommend to mainly use `add_subclass`, instead of directly call `new`. - pub fn new(init: T, super_init: >::Initializer) -> Self { + pub fn new(init: T, super_init: >::Initializer) -> Self { Self { init, super_init } } @@ -108,9 +109,9 @@ impl<'py, T: PyClass<'py>> PyClassInitializer<'py, T> { /// ``` pub fn add_subclass(self, subclass_value: S) -> PyClassInitializer<'py, S> where - S: PyClass<'py> + PyTypeInfo<'py, BaseType = T>, + T: PyClass<'py, Initializer = Self>, + S: PyClass<'py, BaseType = T, BaseInitializer = Self>, S::BaseLayout: PySizedLayout<'py, T>, - S::BaseType: PyTypeInfo<'py, Initializer = Self>, { PyClassInitializer::new(subclass_value, self) } @@ -144,7 +145,7 @@ impl<'py, T: PyClass<'py>> PyObjectInit<'py, T> for PyClassInitializer<'py, T> { impl<'py, T> From for PyClassInitializer<'py, T> where T: PyClass<'py>, - T::BaseType: PyTypeInfo<'py, Initializer = PyNativeTypeInitializer<'py, T::BaseType>>, + T::BaseType: TypeMarker<'py, Initializer = PyNativeTypeInitializer<'py, T::BaseType>>, { fn from(value: T) -> PyClassInitializer<'py, T> { Self::new(value, PyNativeTypeInitializer(PhantomData, PhantomData)) @@ -153,10 +154,10 @@ where impl<'py, S, B> From<(S, B)> for PyClassInitializer<'py, S> where - S: PyClass<'py> + PyTypeInfo<'py, BaseType = B>, + S: PyClass<'py, BaseType = B, BaseInitializer = PyClassInitializer<'py, B>>, S::BaseLayout: PySizedLayout<'py, B>, - B: PyClass<'py> + PyTypeInfo<'py, Initializer = PyClassInitializer<'py, B>>, - B::BaseType: PyTypeInfo<'py, Initializer = PyNativeTypeInitializer<'py, B::BaseType>>, + B: PyClass<'py, Initializer = PyClassInitializer<'py, B>>, + B::BaseType: TypeMarker<'py, Initializer = PyNativeTypeInitializer<'py, B::BaseType>>, { fn from(sub_and_base: (S, B)) -> PyClassInitializer<'py, S> { let (sub, base) = sub_and_base; diff --git a/src/type_marker.rs b/src/type_marker.rs new file mode 100644 index 00000000000..d16beee623b --- /dev/null +++ b/src/type_marker.rs @@ -0,0 +1,98 @@ +use crate::conversion::IntoPyPointer; +use crate::ffi; +use crate::pyclass_init::PyObjectInit; +use crate::type_object::{PyLayout, PySizedLayout, PyTypeInfo}; +use crate::types::*; +use crate::PyNativeType; + +pub trait TypeMarker<'py>: Sized { + type NativeType: PyNativeType<'py>; + type Layout: PyLayout<'py, Self>; + type Initializer: PyObjectInit<'py, Self>; + + /// Type flags (ie PY_TYPE_FLAG_GC, PY_TYPE_FLAG_WEAKREF) + const FLAGS: usize = 0; + + /// PyTypeObject instance for this type. + fn type_object() -> &'static ffi::PyTypeObject; +} + +pub trait TypeWithBase<'py>: TypeMarker<'py> { + type BaseType: TypeMarker<'py>; + type BaseNativeType: PyNativeType<'py>; + type BaseLayout: PySizedLayout<'py, Self::BaseType>; + type BaseInitializer: PyObjectInit<'py, Self::BaseType>; + + /// PyTypeObject instance for base type. + fn base_type_object() -> &'static ffi::PyTypeObject { + Self::BaseType::type_object() + } +} + + +#[macro_export] +macro_rules! py_type_marker { + ($name: ident, $native_ty: ident, $layout: path) => { + #[derive(Debug)] + pub struct $name; + + unsafe impl<'py> $crate::type_object::PyLayout<'py, $name> for $layout {} + unsafe impl<'py> $crate::type_object::PyLayout<'py, $crate::types::$native_ty<'py>> for $layout {} + + impl<'py> TypeMarker<'py> for $name { + type NativeType = $crate::types::$native_ty<'py>; + type Layout = $layout; + type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<'py, Self>; + + /// PyTypeObject instance for this type. + fn type_object() -> &'static ffi::PyTypeObject { + <$native_ty<'py> as PyTypeInfo<'py>>::type_object() + } + } + + impl<'py> TypeMarker<'py> for $crate::types::$native_ty<'py> { + type NativeType = $crate::types::$native_ty<'py>; + type Layout = $layout; + type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<'py, Self>; + + /// PyTypeObject instance for this type. + fn type_object() -> &'static ffi::PyTypeObject { + <$native_ty<'py> as PyTypeInfo<'py>>::type_object() + } + } + + impl From<$native_ty<'_>> for $crate::Py<$name> { + fn from(other: $native_ty<'_>) -> Self { + unsafe { $crate::Py::from_owned_ptr(other.into_ptr()) } + } + } + }; + ($name: ident, $native_ty: ident) => { + py_type_marker!($name, $native_ty, ffi::PyObject); + } +} + +py_type_marker!(Any, PyAny); +py_type_marker!(Bool, PyBool); +py_type_marker!(ByteArray, PyByteArray); +py_type_marker!(Bytes, PyBytes); +// py_type_marker!(Iterator, PyIterator); +py_type_marker!(List, PyList); +py_type_marker!(Long, PyLong); +py_type_marker!(Module, PyModule); +py_type_marker!(String, PyString); +py_type_marker!(Tuple, PyTuple); +py_type_marker!(Type, PyType); +py_type_marker!(TzInfo, PyTzInfo); +// py_type_marker!(Sequence, PySequence); + +py_type_marker!(Complex, PyComplex, ffi::PyComplexObject); +py_type_marker!(Date, PyDate, ffi::PyDateTime_Date); +py_type_marker!(DateTime, PyDateTime, ffi::PyDateTime_DateTime); +py_type_marker!(Delta, PyDelta, ffi::PyDateTime_Delta); +py_type_marker!(Dict, PyDict, ffi::PyDictObject); +py_type_marker!(Float, PyFloat, ffi::PyFloatObject); +py_type_marker!(FrozenSet, PyFrozenSet, ffi::PySetObject); +py_type_marker!(Set, PySet, ffi::PySetObject); +py_type_marker!(Slice, PySlice, ffi::PySliceObject); +py_type_marker!(Time, PyTime, ffi::PyDateTime_Time); diff --git a/src/type_object.rs b/src/type_object.rs index 591e4ec561d..a47db03ae54 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -2,9 +2,8 @@ //! Python type object information use crate::pyclass::{initialize_type_object, PyClass}; -use crate::pyclass_init::PyObjectInit; use crate::types::PyAny; -use crate::unscoped::Type; +use crate::type_marker::{TypeMarker, Type, TypeWithBase}; use crate::{ffi, AsPyPointer, Py, Python}; use std::cell::UnsafeCell; use std::ptr::NonNull; @@ -15,9 +14,12 @@ use std::sync::atomic::{AtomicBool, Ordering}; /// is of `PyAny`. /// /// This trait is intended to be used internally. -pub unsafe trait PyLayout<'py, T: PyTypeInfo<'py>> { +pub unsafe trait PyLayout<'py, T: TypeMarker<'py> + Sized> { const IS_NATIVE_TYPE: bool = true; - fn get_super(&mut self) -> Option<&mut T::BaseLayout> { + fn get_super(&mut self) -> Option<&mut T::BaseLayout> + where + T: TypeWithBase<'py> + { None } unsafe fn py_init(&mut self, _value: T) {} @@ -26,8 +28,8 @@ pub unsafe trait PyLayout<'py, T: PyTypeInfo<'py>> { /// `T: PySizedLayout` represents `T` is not a instance of /// [`PyVarObject`](https://docs.python.org/3.8/c-api/structures.html?highlight=pyvarobject#c.PyVarObject). -/// , in addition that `T` is a concrete representaion of `U`. -pub trait PySizedLayout<'py, T: PyTypeInfo<'py>>: PyLayout<'py, T> + Sized {} +/// , in addition that `T` is a concrete representation of `U`. +pub trait PySizedLayout<'py, T: TypeMarker<'py>>: PyLayout<'py, T> + Sized {} /// Marker type indicates that `Self` can be a base layout of `PyClass`. /// @@ -43,7 +45,7 @@ pub trait PySizedLayout<'py, T: PyTypeInfo<'py>>: PyLayout<'py, T> + Sized {} /// } /// ``` /// Otherwise, implementing this trait is undefined behavior. -pub unsafe trait PyBorrowFlagLayout<'py, T: PyTypeInfo<'py>>: PyLayout<'py, T> + Sized {} +pub unsafe trait PyBorrowFlagLayout<'py, T: TypeMarker<'py>>: PyLayout<'py, T> + Sized {} /// Our custom type flags #[doc(hidden)] @@ -98,7 +100,7 @@ where /// - the return value of type_object must always point to the same PyTypeObject instance pub unsafe trait PyTypeInfo<'py>: Sized { /// Type of objects to store in PyObject struct - type Type; + type Type: TypeMarker<'py>; /// Class name const NAME: &'static str; @@ -109,24 +111,6 @@ pub unsafe trait PyTypeInfo<'py>: Sized { /// Class doc string const DESCRIPTION: &'static str = "\0"; - /// Type flags (ie PY_TYPE_FLAG_GC, PY_TYPE_FLAG_WEAKREF) - const FLAGS: usize = 0; - - /// Base class - type BaseType: PyTypeInfo<'py> + PyTypeObject; - - /// Layout - type Layout: PyLayout<'py, Self>; - - /// Layout of Basetype. - type BaseLayout: PySizedLayout<'py, Self::BaseType>; - - /// Initializer for layout - type Initializer: PyObjectInit<'py, Self>; - - /// Utility type to make AsPyRef work - type AsRefTarget: PyDowncastImpl<'py>; - /// PyTypeObject instance for this type. fn type_object() -> &'static ffi::PyTypeObject; diff --git a/src/types/any.rs b/src/types/any.rs index e7c232c1add..5c98066074c 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -3,6 +3,7 @@ use crate::err::PyDowncastError; use crate::ffi; use crate::gil; use crate::python::Python; +use crate::type_marker; use std::marker::PhantomData; use std::ptr::NonNull; @@ -33,14 +34,15 @@ use std::ptr::NonNull; #[repr(transparent)] pub struct PyAny<'a>(NonNull, PhantomData>); -impl<'py> crate::type_object::PySizedLayout<'py, PyAny<'py>> for ffi::PyObject {} +impl<'py> crate::type_object::PySizedLayout<'py, type_marker::Any> for ffi::PyObject {} pyobject_native_type_named!(PyAny<'py>); pyobject_native_type_common!(PyAny<'py>); pyobject_native_type_info!( PyAny<'py>, ffi::PyObject, ffi::PyBaseObject_Type, - ffi::PyObject_Check + ffi::PyObject_Check, + type_marker::Any ); pyobject_native_type_extract!(PyAny<'py>); diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 43596bc4422..443112c4076 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -1,14 +1,14 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, - ToPyObject, + ToPyObject, type_marker }; /// Represents a Python `bool`. #[repr(transparent)] pub struct PyBool<'py>(PyAny<'py>); -pyobject_native_type!(PyBool<'py>, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check); +pyobject_native_type!(PyBool<'py>, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check, type_marker::Bool); impl<'py> PyBool<'py> { /// Depending on `val`, returns `true` or `false`. diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 1f0ac79413c..510d451e346 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -3,6 +3,7 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::instance::PyNativeType; use crate::types::PyAny; +use crate::type_marker; use crate::AsPyPointer; use crate::Python; use std::os::raw::c_char; @@ -12,7 +13,7 @@ use std::slice; #[repr(transparent)] pub struct PyByteArray<'py>(PyAny<'py>); -pyobject_native_var_type!(PyByteArray<'py>, ffi::PyByteArray_Type, ffi::PyByteArray_Check); +pyobject_native_var_type!(PyByteArray<'py>, ffi::PyByteArray_Type, ffi::PyByteArray_Check, type_marker::ByteArray); impl<'py> PyByteArray<'py> { /// Creates a new Python bytearray object. diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 7e3365537e7..fba42cb2caf 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -1,6 +1,6 @@ use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, - ToPyObject, + ToPyObject, type_marker }; use std::ops::Index; use std::os::raw::c_char; @@ -13,7 +13,7 @@ use std::str; #[repr(transparent)] pub struct PyBytes<'py>(PyAny<'py>); -pyobject_native_var_type!(PyBytes<'py>, ffi::PyBytes_Type, ffi::PyBytes_Check); +pyobject_native_var_type!(PyBytes<'py>, ffi::PyBytes_Type, ffi::PyBytes_Check, type_marker::Bytes); impl<'py> PyBytes<'py> { /// Creates a new Python bytestring object. diff --git a/src/types/complex.rs b/src/types/complex.rs index a55e9731499..74b7a76bdb7 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -2,6 +2,7 @@ use crate::ffi; #[cfg(not(PyPy))] use crate::instance::PyNativeType; use crate::types::PyAny; +use crate::type_marker; use crate::AsPyPointer; use crate::Python; #[cfg(not(PyPy))] @@ -16,7 +17,8 @@ pyobject_native_type!( PyComplex<'py>, ffi::PyComplexObject, ffi::PyComplex_Type, - ffi::PyComplex_Check + ffi::PyComplex_Check, + type_marker::Complex ); impl<'py> PyComplex<'py> { diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 63bb0742eb5..74d3756a005 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -30,6 +30,7 @@ use crate::types::{PyAny, PyTuple}; use crate::AsPyPointer; use crate::Python; use crate::ToPyObject; +use crate::type_marker; use std::os::raw::c_int; #[cfg(not(PyPy))] use std::ptr; @@ -71,7 +72,8 @@ pyobject_native_type!( crate::ffi::PyDateTime_Date, *PyDateTimeAPI.DateType, Some("datetime"), - PyDate_Check + PyDate_Check, + type_marker::Date ); impl<'py> PyDate<'py> { @@ -127,7 +129,8 @@ pyobject_native_type!( crate::ffi::PyDateTime_DateTime, *PyDateTimeAPI.DateTimeType, Some("datetime"), - PyDateTime_Check + PyDateTime_Check, + type_marker::DateTime ); impl<'py> PyDateTime<'py> { @@ -237,7 +240,8 @@ pyobject_native_type!( crate::ffi::PyDateTime_Time, *PyDateTimeAPI.TimeType, Some("datetime"), - PyTime_Check + PyTime_Check, + type_marker::Time ); impl<'py> PyTime<'py> { @@ -322,7 +326,8 @@ pyobject_native_type!( crate::ffi::PyObject, *PyDateTimeAPI.TZInfoType, Some("datetime"), - PyTZInfo_Check + PyTZInfo_Check, + type_marker::TzInfo ); /// Bindings for `datetime.timedelta` @@ -332,7 +337,8 @@ pyobject_native_type!( crate::ffi::PyDateTime_Delta, *PyDateTimeAPI.DeltaType, Some("datetime"), - PyDelta_Check + PyDelta_Check, + type_marker::Delta ); impl<'py> PyDelta<'py> { diff --git a/src/types/dict.rs b/src/types/dict.rs index 6a1164a404a..63126067bfc 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -4,6 +4,7 @@ use crate::err::{self, PyErr, PyResult}; use crate::instance::PyNativeType; use crate::object::PyObject; use crate::types::{PyAny, PyList}; +use crate::type_marker; use crate::AsPyPointer; #[cfg(not(PyPy))] use crate::IntoPyPointer; @@ -22,7 +23,8 @@ pyobject_native_type!( PyDict<'py>, ffi::PyDictObject, ffi::PyDict_Type, - ffi::PyDict_Check + ffi::PyDict_Check, + type_marker::Dict ); impl<'py> PyDict<'py> { diff --git a/src/types/floatob.rs b/src/types/floatob.rs index 03d463da5c0..771c3a2ee30 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -3,7 +3,7 @@ // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, ObjectProtocol, PyAny, PyErr, PyNativeType, PyObject, - PyResult, Python, ToPyObject, + PyResult, Python, ToPyObject, type_marker, }; use std::os::raw::c_double; @@ -20,7 +20,8 @@ pyobject_native_type!( PyFloat<'py>, ffi::PyFloatObject, ffi::PyFloat_Type, - ffi::PyFloat_Check + ffi::PyFloat_Check, + type_marker::Float ); impl<'py> PyFloat<'py> { diff --git a/src/types/list.rs b/src/types/list.rs index d4d343100a1..ca2b2e8a4ec 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -6,14 +6,14 @@ use crate::err::{self, PyResult}; use crate::ffi::{self, Py_ssize_t}; use crate::{ AsPyPointer, IntoPy, IntoPyPointer, PyAny, PyNativeType, PyObject, Python, ToBorrowedObject, - ToPyObject, + ToPyObject, type_marker }; /// Represents a Python `list`. #[repr(transparent)] pub struct PyList<'py>(PyAny<'py>); -pyobject_native_var_type!(PyList<'py>, ffi::PyList_Type, ffi::PyList_Check); +pyobject_native_var_type!(PyList<'py>, ffi::PyList_Type, ffi::PyList_Check, type_marker::List); impl<'py> PyList<'py> { /// Constructs a new list with the given elements. diff --git a/src/types/mod.rs b/src/types/mod.rs index 2bcc128a6e3..b43179144ee 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -73,6 +73,13 @@ macro_rules! pyobject_native_type_common ( unsafe { $crate::PyObject::from_owned_ptr(py, self.into_ptr()) } } } + + impl<'a, 'py $(, $type_param $(: $bound)?)*> $crate::FromPyObject<'a, 'py> for $name<'py $(,$type_param)*> { + fn extract(any: &'a $crate::PyAny<'py>) -> $crate::PyResult<$name<'py $(,$type_param)*>> { + use $crate::{AsPyPointer, PyNativeType}; + unsafe { $crate::FromPyPointer::from_borrowed_ptr_or_err(any.py(), any.as_ptr()).map(Clone::clone) } + } + } } ); @@ -103,38 +110,45 @@ macro_rules! pyobject_native_type_named ( #[macro_export] macro_rules! pyobject_native_type { - ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path) => { - impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PySizedLayout<'py, $name<'py $(,$type_param)*>> for $layout {} + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path, $typemarker: path) => { + impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PySizedLayout<'py, $typemarker> for $layout {} impl<'py $(, $type_param $(: $bound)?)*> $crate::derive_utils::PyBaseTypeUtils<'py> for $name<'py $(,$type_param)*> { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; - type LayoutAsBase = $crate::pycell::PyCellBase<'py, Self>; - type BaseNativeType = Self; + type LayoutAsBase = $crate::pycell::PyCellBase<'py, $typemarker>; + type RootType = Self; } + impl<'py $(, $type_param $(: $bound)?)*> $crate::derive_utils::PyBaseTypeUtils<'py> for $typemarker { + type Dict = $crate::pyclass_slots::PyClassDummySlot; + type WeakRef = $crate::pyclass_slots::PyClassDummySlot; + type LayoutAsBase = $crate::pycell::PyCellBase<'py, $typemarker>; + type RootType = Self; + } + pyobject_native_type_named!($name<'py $(, $type_param $(: $bound)?)*>); pyobject_native_newtype!($name<'py $(, $type_param $(: $bound)?)*>); - pyobject_native_type_info!($name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, $module, $checkfunction); + pyobject_native_type_info!($name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, $module, $checkfunction, $typemarker); pyobject_native_type_extract!($name<'py $(, $type_param $(: $bound)?)*>); }; - ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path, $typemarker: path) => { pyobject_native_type! { - $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction, $typemarker } }; } #[macro_export] macro_rules! pyobject_native_var_type { - ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $module: expr, $checkfunction: path) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $module: expr, $checkfunction: path, $typemarker: path) => { pyobject_native_newtype!($name<'py $(, $type_param $(: $bound)?)*>); pyobject_native_type_named!($name<'py $(, $type_param $(: $bound)?)*>); pyobject_native_type_info!($name<'py $(, $type_param $(: $bound)?)*>, $crate::ffi::PyObject, - $typeobject, $module, $checkfunction); + $typeobject, $module, $checkfunction, $typemarker); pyobject_native_type_extract!($name<'py $(, $type_param $(: $bound)?)*>); }; - ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $checkfunction: path) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $checkfunction: path, $typemarker: path) => { pyobject_native_var_type! { - $name<'py $(, $type_param $(: $bound)?)*>, $typeobject, Some("builtins"), $checkfunction + $name<'py $(, $type_param $(: $bound)?)*>, $typeobject, Some("builtins"), $checkfunction, $typemarker } }; } @@ -155,16 +169,10 @@ macro_rules! pyobject_native_type_extract { #[macro_export] macro_rules! pyobject_native_type_info( ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, - $module: expr, $checkfunction: path) => { - unsafe impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PyLayout<'py, $name<'py $(,$type_param)*>> for $layout {} + $module: expr, $checkfunction: path, $typemarker: path) => { unsafe impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PyTypeInfo<'py> for $name<'py $(,$type_param)*> { - type Type = (); - type BaseType = $crate::PyAny<'py>; - type Layout = $layout; - type BaseLayout = ffi::PyObject; - type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<'py, Self>; - type AsRefTarget = Self; + type Type = $typemarker; const NAME: &'static str = stringify!($name); const MODULE: Option<&'static str> = $module; @@ -182,9 +190,9 @@ macro_rules! pyobject_native_type_info( } }; - ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path, $typemarker: path) => { pyobject_native_type_info! { - $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction + $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction, $typemarker } }; ); diff --git a/src/types/module.rs b/src/types/module.rs index 78b28039888..944ce2524ec 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -11,7 +11,8 @@ use crate::objectprotocol::ObjectProtocol; use crate::pyclass::PyClass; use crate::type_object::PyTypeObject; use crate::types::{PyAny, PyDict, PyList}; -use crate::unscoped::Tuple; +use crate::type_marker; +use crate::type_marker::Tuple; use crate::{AsPyPointer, IntoPy, Py, Python, ToPyObject}; use std::ffi::{CStr, CString}; use std::os::raw::c_char; @@ -21,7 +22,7 @@ use std::str; #[repr(transparent)] pub struct PyModule<'py>(PyAny<'py>); -pyobject_native_var_type!(PyModule<'py>, ffi::PyModule_Type, ffi::PyModule_Check); +pyobject_native_var_type!(PyModule<'py>, ffi::PyModule_Type, ffi::PyModule_Check, type_marker::Module); impl<'py> PyModule<'py> { /// Creates a new module object with the `__name__` attribute set to name. diff --git a/src/types/num.rs b/src/types/num.rs index 6fa9a47ade4..583b901d746 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -4,7 +4,7 @@ use crate::{ exceptions, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, - PyResult, Python, ToPyObject, + PyResult, Python, ToPyObject, type_marker }; use num_traits::cast::cast; use std::i64; @@ -112,7 +112,7 @@ macro_rules! int_convert_128 { #[repr(transparent)] pub struct PyLong<'py>(PyAny<'py>); -pyobject_native_var_type!(PyLong<'py>, ffi::PyLong_Type, ffi::PyLong_Check); +pyobject_native_var_type!(PyLong<'py>, ffi::PyLong_Type, ffi::PyLong_Check, type_marker::Long); macro_rules! int_fits_c_long { ($rust_type:ty) => { diff --git a/src/types/set.rs b/src/types/set.rs index 78b6248d1f7..c0e3326575c 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -4,7 +4,7 @@ use crate::err::{self, PyErr, PyResult}; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyNativeType, PyObject, Python, - ToBorrowedObject, ToPyObject, + ToBorrowedObject, ToPyObject, type_marker }; use std::cmp; use std::collections::{BTreeSet, HashSet}; @@ -18,12 +18,13 @@ pub struct PySet<'py>(PyAny<'py>); #[repr(transparent)] pub struct PyFrozenSet<'py>(PyAny<'py>); -pyobject_native_type!(PySet<'py>, ffi::PySetObject, ffi::PySet_Type, ffi::PySet_Check); +pyobject_native_type!(PySet<'py>, ffi::PySetObject, ffi::PySet_Type, ffi::PySet_Check, type_marker::Set); pyobject_native_type!( PyFrozenSet<'py>, ffi::PySetObject, ffi::PyFrozenSet_Type, - ffi::PyFrozenSet_Check + ffi::PyFrozenSet_Check, + type_marker::FrozenSet ); impl<'py> PySet<'py> { diff --git a/src/types/slice.rs b/src/types/slice.rs index c2f69568140..727e6c6ee0e 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -5,6 +5,7 @@ use crate::ffi::{self, Py_ssize_t}; use crate::instance::PyNativeType; use crate::object::PyObject; use crate::types::PyAny; +use crate::type_marker; use crate::Python; use crate::{AsPyPointer, ToPyObject}; use std::os::raw::c_long; @@ -19,7 +20,8 @@ pyobject_native_type!( PySlice<'py>, ffi::PySliceObject, ffi::PySlice_Type, - ffi::PySlice_Check + ffi::PySlice_Check, + type_marker::Slice ); /// Represents Python `slice` indices. diff --git a/src/types/string.rs b/src/types/string.rs index 3c725db46f0..b6cb0c2550b 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -2,7 +2,7 @@ use crate::{ ffi, gil, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, - PyResult, PyTryFrom, Python, ToPyObject, + PyResult, PyTryFrom, Python, ToPyObject, type_marker }; use std::borrow::Cow; use std::ffi::CStr; @@ -16,7 +16,7 @@ use std::str; #[repr(transparent)] pub struct PyString<'py>(PyAny<'py>); -pyobject_native_var_type!(PyString<'py>, ffi::PyUnicode_Type, ffi::PyUnicode_Check); +pyobject_native_var_type!(PyString<'py>, ffi::PyUnicode_Type, ffi::PyUnicode_Check, type_marker::String); impl<'py> PyString<'py> { /// Creates a new Python string object. diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 0f0fc6c2d6a..207b9b1219a 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -1,7 +1,7 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::ffi::{self, Py_ssize_t}; -use crate::unscoped::Tuple; +use crate::type_marker::Tuple; use crate::{ exceptions, AsPyPointer, AsPyRef, FromPy, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyNativeType, PyObject, PyResult, PyTryFrom, Python, ToPyObject, @@ -14,7 +14,7 @@ use std::slice; #[repr(transparent)] pub struct PyTuple<'py>(PyAny<'py>); -pyobject_native_var_type!(PyTuple<'py>, ffi::PyTuple_Type, ffi::PyTuple_Check); +pyobject_native_var_type!(PyTuple<'py>, ffi::PyTuple_Type, ffi::PyTuple_Check, Tuple); impl<'py> PyTuple<'py> { /// Constructs a new tuple with the given elements. diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 58d8f9ce546..11b4f079254 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -2,10 +2,12 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython +use crate::conversion::IntoPyPointer; use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::instance::PyNativeType; use crate::type_object::{PyTypeInfo, PyTypeObject}; +use crate::type_marker; use crate::types::PyAny; use crate::AsPyPointer; use crate::Python; @@ -16,13 +18,13 @@ use std::ffi::CStr; #[repr(transparent)] pub struct PyType<'a>(PyAny<'a>); -pyobject_native_var_type!(PyType<'py>, ffi::PyType_Type, ffi::PyType_Check); +pyobject_native_var_type!(PyType<'py>, ffi::PyType_Type, ffi::PyType_Check, type_marker::Type); impl<'py> PyType<'py> { /// Creates a new type object. #[inline] pub fn new>(py: Python<'py>) -> Self { - ::type_object().into_scoped(py) + unsafe { py.from_owned_ptr(::type_object().into_ptr()) } } /// Retrieves the underlying FFI pointer associated with this Python object. diff --git a/src/unscoped.rs b/src/unscoped.rs deleted file mode 100644 index e88b81beed8..00000000000 --- a/src/unscoped.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::types::*; -use crate::{AsPyPointer, IntoPyPointer, PyNativeType, FromPyPointer}; - -pub trait Unscoped<'py> { - type NativeType: PyNativeType<'py> + AsPyPointer + IntoPyPointer + FromPyPointer<'py>; -} - -#[macro_export] -macro_rules! py_unscoped { - ($name: ident, $native_ty: ident) => { - #[derive(Debug)] - pub struct $name; - - impl<'py> Unscoped<'py> for $name { - type NativeType = $native_ty<'py>; - } - - impl From<$native_ty<'_>> for $crate::Py<$name> { - fn from(other: $native_ty<'_>) -> Self { - unsafe { $crate::Py::from_owned_ptr(other.into_ptr()) } - } - } - }; -} - -py_unscoped!(Dict, PyDict); -py_unscoped!(Tuple, PyTuple); -py_unscoped!(Type, PyType); diff --git a/tests/test_buffer_protocol.rs b/tests/test_buffer_protocol.rs index c576e1fd00c..e4b9bb5cda4 100644 --- a/tests/test_buffer_protocol.rs +++ b/tests/test_buffer_protocol.rs @@ -93,7 +93,7 @@ fn test_buffer() { ) .unwrap(); let env = [("ob", instance)].into_py_dict(py); - py.run("assert bytes(ob) == b' 23'", None, Some(env)) + py.run("assert bytes(ob) == b' 23'", None, Some(&env)) .unwrap(); } diff --git a/tests/test_datetime.rs b/tests/test_datetime.rs index 7dea2ef1e89..c1071e4cb04 100644 --- a/tests/test_datetime.rs +++ b/tests/test_datetime.rs @@ -13,7 +13,7 @@ fn _get_subclasses<'py>( // Import the class from Python and create some subclasses let datetime = py.import("datetime")?; - let locals = [(py_type, datetime.get(py_type)?)].into_py_dict(*py); + let locals = [(py_type, datetime.get(py_type)?)].into_py_dict(py); let make_subclass_py = format!("class Subklass({}):\n pass", py_type); @@ -54,14 +54,8 @@ macro_rules! assert_check_only { }; } -// Because of the relase pool unsoundness reported in https://github.com/PyO3/pyo3/issues/756, -// we need to stop other threads before calling `py.import()`. -// TODO(kngwyu): Remove this variable -static MUTEX: parking_lot::Mutex<()> = parking_lot::const_mutex(()); - #[test] fn test_date_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "date", "2018, 1, 1").unwrap(); @@ -73,7 +67,6 @@ fn test_date_check() { #[test] fn test_time_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "time", "12, 30, 15").unwrap(); @@ -85,7 +78,6 @@ fn test_time_check() { #[test] fn test_datetime_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "datetime", "2018, 1, 1, 13, 30, 15") @@ -100,7 +92,6 @@ fn test_datetime_check() { #[test] fn test_delta_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "timedelta", "1, -3").unwrap(); @@ -115,7 +106,6 @@ fn test_datetime_utc() { use assert_approx_eq::assert_approx_eq; use pyo3::types::PyDateTime; - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); let datetime = py.import("datetime").map_err(|e| e.print(py)).unwrap(); diff --git a/tests/test_dunder.rs b/tests/test_dunder.rs index c1eaeb6569e..249181515bb 100644 --- a/tests/test_dunder.rs +++ b/tests/test_dunder.rs @@ -459,8 +459,8 @@ fn test_cls_impl() { let ob = Py::new(py, Test {}).unwrap(); let d = [("ob", ob)].into_py_dict(py); - py.run("assert ob[1] == 'int'", None, Some(d)).unwrap(); - py.run("assert ob[100:200:1] == 'slice'", None, Some(d)) + py.run("assert ob[1] == 'int'", None, Some(&d)).unwrap(); + py.run("assert ob[100:200:1] == 'slice'", None, Some(&d)) .unwrap(); } diff --git a/tests/test_inheritance.rs b/tests/test_inheritance.rs index 1ec72302a49..555568709e4 100644 --- a/tests/test_inheritance.rs +++ b/tests/test_inheritance.rs @@ -3,7 +3,7 @@ use pyo3::py_run; use pyo3::types::IntoPyDict; -use pyo3::types::{PyDict, PySet}; +use pyo3::type_marker::{Dict, Set}; mod common; #[pyclass] @@ -24,7 +24,7 @@ fn subclass() { py.run( "class A(SubclassAble): pass\nassert issubclass(A, SubclassAble)", None, - Some(d), + Some(&d), ) .map_err(|e| e.print(py)) .unwrap(); @@ -98,7 +98,7 @@ fn mutation_fails() { let obj = PyCell::new(py, SubClass::new()).unwrap(); let global = Some([("obj", obj)].into_py_dict(py)); let e = py - .run("obj.base_set(lambda: obj.sub_set_and_ret(1))", global, None) + .run("obj.base_set(lambda: obj.sub_set_and_ret(1))", global.as_ref(), None) .unwrap_err(); assert!(e.is_instance::(py)) } @@ -150,7 +150,7 @@ except Exception as e: ); } -#[pyclass(extends=PySet)] +#[pyclass(extends=Set)] #[derive(Debug)] struct SetWithName { #[pyo3(get(name))] @@ -177,7 +177,7 @@ fn inherit_set() { ); } -#[pyclass(extends=PyDict)] +#[pyclass(extends=Dict)] #[derive(Debug)] struct DictWithName { #[pyo3(get(name))] diff --git a/tests/test_module.rs b/tests/test_module.rs index b7d1518cbb0..357145db1cf 100644 --- a/tests/test_module.rs +++ b/tests/test_module.rs @@ -258,7 +258,7 @@ fn test_module_nesting() { #[pyfunction(a = 5, vararg = "*")] fn ext_vararg_fn(py: Python, a: i32, vararg: &PyTuple) -> PyObject { - [a.to_object(py), vararg.into()].to_object(py) + [a.to_object(py), vararg.clone().into()].to_object(py) } #[pymodule] diff --git a/tests/test_pyself.rs b/tests/test_pyself.rs index 2b1f052b787..c77ed32e423 100644 --- a/tests/test_pyself.rs +++ b/tests/test_pyself.rs @@ -3,6 +3,7 @@ use pyo3; use pyo3::prelude::*; use pyo3::types::{PyBytes, PyString}; use pyo3::{AsPyRef, PyCell, PyIterProtocol}; +use pyo3::type_marker::Bytes; use std::collections::HashMap; mod common; @@ -23,23 +24,23 @@ impl Reader { fn clone_ref_with_py<'py>(slf: &'py PyCell, _py: Python<'py>) -> &'py PyCell<'py, Self> { slf } - fn get_iter(slf: &PyCell, keys: Py) -> PyResult { + fn get_iter(slf: &PyCell, keys: PyBytes) -> PyResult { Ok(Iter { reader: slf.into(), - keys, + keys: keys.into(), idx: 0, }) } fn get_iter_and_reset( mut slf: PyRefMut, - keys: Py, + keys: PyBytes, py: Python, ) -> PyResult { let reader = Py::new(py, slf.clone())?; slf.inner.clear(); Ok(Iter { reader, - keys, + keys: keys.into(), idx: 0, }) } @@ -49,7 +50,7 @@ impl Reader { #[derive(Debug)] struct Iter { reader: Py, - keys: Py, + keys: Py, idx: usize, } diff --git a/tests/test_variable_arguments.rs b/tests/test_variable_arguments.rs index efaecef059b..ced7dc6f51b 100644 --- a/tests/test_variable_arguments.rs +++ b/tests/test_variable_arguments.rs @@ -10,13 +10,13 @@ struct MyClass {} impl MyClass { #[staticmethod] #[args(args = "*")] - fn test_args(args: &PyTuple) -> PyResult<&PyTuple> { - Ok(args) + fn test_args(args: PyTuple) -> PyResult { + Ok(args.clone()) } #[staticmethod] #[args(kwargs = "**")] - fn test_kwargs(kwargs: Option<&PyDict>) -> PyResult> { + fn test_kwargs<'py>(kwargs: Option<&'py PyDict>) -> PyResult>> { Ok(kwargs) } } From 1d508ec72bdf8219b016b62592e09bd1432ec241 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 1 May 2020 08:55:22 +0100 Subject: [PATCH 11/11] All tests passing --- src/conversion.rs | 4 ++-- src/instance.rs | 9 ++++++--- src/type_marker.rs | 14 +++++++++++++- tests/ui/missing_clone.stderr | 2 +- tests/ui/static_ref.rs | 2 +- tests/ui/wrong_aspyref_lifetimes.rs | 3 ++- tests/ui/wrong_aspyref_lifetimes.stderr | 18 +++++++++--------- 7 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index c65673a6f40..ed9bdd4bc4a 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -368,7 +368,7 @@ where fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { let value = value.into(); unsafe { - if T::is_instance(value) { + if >::is_instance(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError) @@ -377,7 +377,7 @@ where } fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { - if T::is_exact_instance(value) { + if >::is_exact_instance(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError) diff --git a/src/instance.rs b/src/instance.rs index 86127efa27f..21cced64c88 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,5 +1,5 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::err::{PyErr, PyResult}; +use crate::err::{PyErr, PyResult, PyDowncastError}; use crate::gil; use crate::object::PyObject; use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl}; @@ -284,8 +284,11 @@ where /// Extracts `Self` from the source `PyObject`. fn extract(ob: &PyAny<'py>) -> PyResult { unsafe { - let val = ob.py().from_borrowed_ptr_or_err::(ob.as_ptr())?; - Ok(Py::from_borrowed_ptr(val.as_ptr())) + if T::is_instance(ob) { + Ok(Py::from_borrowed_ptr(ob.as_ptr())) + } else { + Err(PyDowncastError.into()) + } } } } diff --git a/src/type_marker.rs b/src/type_marker.rs index d16beee623b..5aa5b0f3669 100644 --- a/src/type_marker.rs +++ b/src/type_marker.rs @@ -3,7 +3,7 @@ use crate::ffi; use crate::pyclass_init::PyObjectInit; use crate::type_object::{PyLayout, PySizedLayout, PyTypeInfo}; use crate::types::*; -use crate::PyNativeType; +use crate::{AsPyPointer, PyNativeType}; pub trait TypeMarker<'py>: Sized { type NativeType: PyNativeType<'py>; @@ -15,6 +15,18 @@ pub trait TypeMarker<'py>: Sized { /// PyTypeObject instance for this type. fn type_object() -> &'static ffi::PyTypeObject; + + /// Check if `*mut ffi::PyObject` is instance of this type + fn is_instance(object: &PyAny) -> bool { + unsafe { + ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object() as *const _ as _) != 0 + } + } + + /// Check if `*mut ffi::PyObject` is exact instance of this type + fn is_exact_instance(object: &PyAny) -> bool { + unsafe { (*object.as_ptr()).ob_type == Self::type_object() as *const _ as _ } + } } pub trait TypeWithBase<'py>: TypeMarker<'py> { diff --git a/tests/ui/missing_clone.stderr b/tests/ui/missing_clone.stderr index bb243766f3d..024abf96550 100644 --- a/tests/ui/missing_clone.stderr +++ b/tests/ui/missing_clone.stderr @@ -4,4 +4,4 @@ error[E0277]: the trait bound `TestClass: std::clone::Clone` is not satisfied 15 | let t: TestClass = pyvalue.extract(py).unwrap(); | ^^^^^^^ the trait `std::clone::Clone` is not implemented for `TestClass` | - = note: required because of the requirements on the impl of `pyo3::conversion::FromPyObject<'_>` for `TestClass` + = note: required because of the requirements on the impl of `pyo3::conversion::FromPyObject<'_, '_>` for `TestClass` diff --git a/tests/ui/static_ref.rs b/tests/ui/static_ref.rs index 5202920ac03..79f1a3b2cac 100644 --- a/tests/ui/static_ref.rs +++ b/tests/ui/static_ref.rs @@ -3,7 +3,7 @@ use pyo3::types::PyList; #[pyclass] struct MyClass { - list: &'static PyList, + list: &'static PyList<'static>, } #[pymethods] diff --git a/tests/ui/wrong_aspyref_lifetimes.rs b/tests/ui/wrong_aspyref_lifetimes.rs index 20d94b2367c..9f81ce1749b 100644 --- a/tests/ui/wrong_aspyref_lifetimes.rs +++ b/tests/ui/wrong_aspyref_lifetimes.rs @@ -1,8 +1,9 @@ +use pyo3::type_marker::Dict; use pyo3::{types::PyDict, AsPyRef, Py, PyNativeType, Python}; fn main() { let gil = Python::acquire_gil(); - let dict: Py = PyDict::new(gil.python()).into(); + let dict: Py = PyDict::new(gil.python()).into(); let dict: &PyDict = dict.as_ref(gil.python()); drop(gil); diff --git a/tests/ui/wrong_aspyref_lifetimes.stderr b/tests/ui/wrong_aspyref_lifetimes.stderr index 7c3b87ce86b..e082bbf2d2c 100644 --- a/tests/ui/wrong_aspyref_lifetimes.stderr +++ b/tests/ui/wrong_aspyref_lifetimes.stderr @@ -1,10 +1,10 @@ error[E0505]: cannot move out of `gil` because it is borrowed - --> $DIR/wrong_aspyref_lifetimes.rs:7:10 - | -6 | let dict: &PyDict = dict.as_ref(gil.python()); - | --- borrow of `gil` occurs here -7 | drop(gil); - | ^^^ move out of `gil` occurs here -8 | -9 | let _py: Python = dict.py(); // Obtain a Python<'p> without GIL. - | ---- borrow later used here + --> $DIR/wrong_aspyref_lifetimes.rs:8:10 + | +7 | let dict: &PyDict = dict.as_ref(gil.python()); + | --- borrow of `gil` occurs here +8 | drop(gil); + | ^^^ move out of `gil` occurs here +9 | +10 | let _py: Python = dict.py(); // Obtain a Python<'p> without GIL. + | ---- borrow later used here