From ef8532b17512437937aedc674c9ad4bdd7893a0d Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Thu, 14 Dec 2023 18:35:06 +0000 Subject: [PATCH] Add `AsRefSource` to `PyNativeType`. --- newsfragments/3653.changed.md | 1 + src/instance.rs | 7 ++- src/pycell.rs | 4 +- src/types/any.rs | 97 +++++++++++++++++------------------ src/types/mod.rs | 4 +- src/types/pysuper.rs | 2 +- src/types/sequence.rs | 42 +++++++-------- 7 files changed, 78 insertions(+), 79 deletions(-) create mode 100644 newsfragments/3653.changed.md diff --git a/newsfragments/3653.changed.md b/newsfragments/3653.changed.md new file mode 100644 index 00000000000..75fea03cb71 --- /dev/null +++ b/newsfragments/3653.changed.md @@ -0,0 +1 @@ +Add `AsRefSource` to `PyNativeType`. diff --git a/src/instance.rs b/src/instance.rs index c1a3e48e0d1..1c0fdbcb596 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -24,6 +24,9 @@ use std::ptr::NonNull; /// /// This trait must only be implemented for types which cannot be accessed without the GIL. pub unsafe trait PyNativeType: Sized { + /// The form of this which is stored inside a `Py` smart pointer. + type AsRefSource: HasPyGilRef; + /// Returns a GIL marker constrained to the lifetime of this type. #[inline] fn py(&self) -> Python<'_> { @@ -172,9 +175,9 @@ impl<'py, T> Py2<'py, T> { /// Internal helper to convert e.g. &'a &'py PyDict to &'a Py2<'py, PyDict> for /// backwards-compatibility during migration to removal of pool. #[doc(hidden)] // public and doc(hidden) to use in examples and tests for now - pub fn borrowed_from_gil_ref<'a>(gil_ref: &'a &'py T::AsRefTarget) -> &'a Self + pub fn borrowed_from_gil_ref<'a, U>(gil_ref: &'a &'py U) -> &'a Self where - T: HasPyGilRef, + U: PyNativeType, { // Safety: &'py T::AsRefTarget is expected to be a Python pointer, // so &'a &'py T::AsRefTarget has the same layout as &'a Py2<'py, T> diff --git a/src/pycell.rs b/src/pycell.rs index 2b8082a9eee..3bc80a7eb07 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -275,7 +275,9 @@ pub(crate) struct PyCellContents { pub(crate) weakref: T::WeakRef, } -unsafe impl PyNativeType for PyCell {} +unsafe impl PyNativeType for PyCell { + type AsRefSource = T; +} impl PyCell { /// Makes a new `PyCell` on the Python heap and return the reference to it. diff --git a/src/types/any.rs b/src/types/any.rs index 6d6da10764d..23548265c54 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -73,7 +73,7 @@ impl PyAny { /// This is equivalent to the Python expression `self is other`. #[inline] pub fn is(&self, other: &T) -> bool { - Py2::::borrowed_from_gil_ref(&self).is(other) + Py2::borrowed_from_gil_ref(&self).is(other) } /// Determines whether this object has the given attribute. @@ -102,7 +102,7 @@ impl PyAny { where N: IntoPy>, { - Py2::::borrowed_from_gil_ref(&self).hasattr(attr_name) + Py2::borrowed_from_gil_ref(&self).hasattr(attr_name) } /// Retrieves an attribute value. @@ -131,7 +131,7 @@ impl PyAny { where N: IntoPy>, { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .getattr(attr_name) .map(Py2::into_gil_ref) } @@ -208,7 +208,7 @@ impl PyAny { N: IntoPy>, V: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).setattr(attr_name, value) + Py2::borrowed_from_gil_ref(&self).setattr(attr_name, value) } /// Deletes an attribute. @@ -221,7 +221,7 @@ impl PyAny { where N: IntoPy>, { - Py2::::borrowed_from_gil_ref(&self).delattr(attr_name) + Py2::borrowed_from_gil_ref(&self).delattr(attr_name) } /// Returns an [`Ordering`] between `self` and `other`. @@ -274,7 +274,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).compare(other) + Py2::borrowed_from_gil_ref(&self).compare(other) } /// Tests whether two Python objects obey a given [`CompareOp`]. @@ -315,7 +315,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .rich_compare(other, compare_op) .map(Py2::into_gil_ref) } @@ -327,7 +327,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).lt(other) + Py2::borrowed_from_gil_ref(&self).lt(other) } /// Tests whether this object is less than or equal to another. @@ -337,7 +337,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).le(other) + Py2::borrowed_from_gil_ref(&self).le(other) } /// Tests whether this object is equal to another. @@ -347,7 +347,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).eq(other) + Py2::borrowed_from_gil_ref(&self).eq(other) } /// Tests whether this object is not equal to another. @@ -357,7 +357,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).ne(other) + Py2::borrowed_from_gil_ref(&self).ne(other) } /// Tests whether this object is greater than another. @@ -367,7 +367,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).gt(other) + Py2::borrowed_from_gil_ref(&self).gt(other) } /// Tests whether this object is greater than or equal to another. @@ -377,7 +377,7 @@ impl PyAny { where O: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).ge(other) + Py2::borrowed_from_gil_ref(&self).ge(other) } /// Determines whether this object appears callable. @@ -408,7 +408,7 @@ impl PyAny { /// /// [1]: https://docs.python.org/3/library/functions.html#callable pub fn is_callable(&self) -> bool { - Py2::::borrowed_from_gil_ref(&self).is_callable() + Py2::borrowed_from_gil_ref(&self).is_callable() } /// Calls the object. @@ -446,7 +446,7 @@ impl PyAny { args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult<&PyAny> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .call(args, kwargs) .map(Py2::into_gil_ref) } @@ -472,7 +472,7 @@ impl PyAny { /// /// This is equivalent to the Python expression `help()`. pub fn call0(&self) -> PyResult<&PyAny> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .call0() .map(Py2::into_gil_ref) } @@ -505,7 +505,7 @@ impl PyAny { /// # } /// ``` pub fn call1(&self, args: impl IntoPy>) -> PyResult<&PyAny> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .call1(args) .map(Py2::into_gil_ref) } @@ -550,7 +550,7 @@ impl PyAny { N: IntoPy>, A: IntoPy>, { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .call_method(name, args, kwargs) .map(Py2::into_gil_ref) } @@ -590,7 +590,7 @@ impl PyAny { where N: IntoPy>, { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .call_method0(name) .map(Py2::into_gil_ref) } @@ -632,7 +632,7 @@ impl PyAny { N: IntoPy>, A: IntoPy>, { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .call_method1(name, args) .map(Py2::into_gil_ref) } @@ -641,7 +641,7 @@ impl PyAny { /// /// This is equivalent to the Python expression `bool(self)`. pub fn is_true(&self) -> PyResult { - Py2::::borrowed_from_gil_ref(&self).is_true() + Py2::borrowed_from_gil_ref(&self).is_true() } /// Returns whether the object is considered to be None. @@ -649,7 +649,7 @@ impl PyAny { /// This is equivalent to the Python expression `self is None`. #[inline] pub fn is_none(&self) -> bool { - Py2::::borrowed_from_gil_ref(&self).is_none() + Py2::borrowed_from_gil_ref(&self).is_none() } /// Returns whether the object is Ellipsis, e.g. `...`. @@ -657,14 +657,14 @@ impl PyAny { /// This is equivalent to the Python expression `self is ...`. #[deprecated(since = "0.20.0", note = "use `.is(py.Ellipsis())` instead")] pub fn is_ellipsis(&self) -> bool { - Py2::::borrowed_from_gil_ref(&self).is_ellipsis() + Py2::borrowed_from_gil_ref(&self).is_ellipsis() } /// Returns true if the sequence or mapping has a length of 0. /// /// This is equivalent to the Python expression `len(self) == 0`. pub fn is_empty(&self) -> PyResult { - Py2::::borrowed_from_gil_ref(&self).is_empty() + Py2::borrowed_from_gil_ref(&self).is_empty() } /// Gets an item from the collection. @@ -674,7 +674,7 @@ impl PyAny { where K: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .get_item(key) .map(Py2::into_gil_ref) } @@ -687,7 +687,7 @@ impl PyAny { K: ToPyObject, V: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).set_item(key, value) + Py2::borrowed_from_gil_ref(&self).set_item(key, value) } /// Deletes an item from the collection. @@ -697,7 +697,7 @@ impl PyAny { where K: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).del_item(key) + Py2::borrowed_from_gil_ref(&self).del_item(key) } /// Takes an object and returns an iterator for it. @@ -705,24 +705,22 @@ impl PyAny { /// This is typically a new iterator but if the argument is an iterator, /// this returns itself. pub fn iter(&self) -> PyResult<&PyIterator> { - Py2::::borrowed_from_gil_ref(&self) - .iter() - .map(|py2| { - // Can't use into_gil_ref here because T: PyTypeInfo bound is not satisfied - // Safety: into_ptr produces a valid pointer to PyIterator object - unsafe { self.py().from_owned_ptr(py2.into_ptr()) } - }) + Py2::borrowed_from_gil_ref(&self).iter().map(|py2| { + // Can't use into_gil_ref here because T: PyTypeInfo bound is not satisfied + // Safety: into_ptr produces a valid pointer to PyIterator object + unsafe { self.py().from_owned_ptr(py2.into_ptr()) } + }) } /// Returns the Python type object for this object's type. pub fn get_type(&self) -> &PyType { - Py2::::borrowed_from_gil_ref(&self).get_type() + Py2::borrowed_from_gil_ref(&self).get_type() } /// Returns the Python type pointer for this object. #[inline] pub fn get_type_ptr(&self) -> *mut ffi::PyTypeObject { - Py2::::borrowed_from_gil_ref(&self).get_type_ptr() + Py2::borrowed_from_gil_ref(&self).get_type_ptr() } /// Downcast this `PyAny` to a concrete Python type or pyclass. @@ -859,14 +857,14 @@ impl PyAny { /// Returns the reference count for the Python object. pub fn get_refcnt(&self) -> isize { - Py2::::borrowed_from_gil_ref(&self).get_refcnt() + Py2::borrowed_from_gil_ref(&self).get_refcnt() } /// Computes the "repr" representation of self. /// /// This is equivalent to the Python expression `repr(self)`. pub fn repr(&self) -> PyResult<&PyString> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .repr() .map(Py2::into_gil_ref) } @@ -875,7 +873,7 @@ impl PyAny { /// /// This is equivalent to the Python expression `str(self)`. pub fn str(&self) -> PyResult<&PyString> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .str() .map(Py2::into_gil_ref) } @@ -884,23 +882,21 @@ impl PyAny { /// /// This is equivalent to the Python expression `hash(self)`. pub fn hash(&self) -> PyResult { - Py2::::borrowed_from_gil_ref(&self).hash() + Py2::borrowed_from_gil_ref(&self).hash() } /// Returns the length of the sequence or mapping. /// /// This is equivalent to the Python expression `len(self)`. pub fn len(&self) -> PyResult { - Py2::::borrowed_from_gil_ref(&self).len() + Py2::borrowed_from_gil_ref(&self).len() } /// Returns the list of attributes of this object. /// /// This is equivalent to the Python expression `dir(self)`. pub fn dir(&self) -> &PyList { - Py2::::borrowed_from_gil_ref(&self) - .dir() - .into_gil_ref() + Py2::borrowed_from_gil_ref(&self).dir().into_gil_ref() } /// Checks whether this object is an instance of type `ty`. @@ -908,7 +904,7 @@ impl PyAny { /// This is equivalent to the Python expression `isinstance(self, ty)`. #[inline] pub fn is_instance(&self, ty: &PyAny) -> PyResult { - Py2::::borrowed_from_gil_ref(&self).is_instance(Py2::borrowed_from_gil_ref(&ty)) + Py2::borrowed_from_gil_ref(&self).is_instance(Py2::borrowed_from_gil_ref(&ty)) } /// Checks whether this object is an instance of exactly type `ty` (not a subclass). @@ -916,8 +912,7 @@ impl PyAny { /// This is equivalent to the Python expression `type(self) is ty`. #[inline] pub fn is_exact_instance(&self, ty: &PyAny) -> bool { - Py2::::borrowed_from_gil_ref(&self) - .is_exact_instance(Py2::borrowed_from_gil_ref(&ty)) + Py2::borrowed_from_gil_ref(&self).is_exact_instance(Py2::borrowed_from_gil_ref(&ty)) } /// Checks whether this object is an instance of type `T`. @@ -926,7 +921,7 @@ impl PyAny { /// if the type `T` is known at compile time. #[inline] pub fn is_instance_of(&self) -> bool { - Py2::::borrowed_from_gil_ref(&self).is_instance_of::() + Py2::borrowed_from_gil_ref(&self).is_instance_of::() } /// Checks whether this object is an instance of exactly type `T`. @@ -935,7 +930,7 @@ impl PyAny { /// if the type `T` is known at compile time. #[inline] pub fn is_exact_instance_of(&self) -> bool { - Py2::::borrowed_from_gil_ref(&self).is_exact_instance_of::() + Py2::borrowed_from_gil_ref(&self).is_exact_instance_of::() } /// Determines if self contains `value`. @@ -945,7 +940,7 @@ impl PyAny { where V: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).contains(value) + Py2::borrowed_from_gil_ref(&self).contains(value) } /// Returns a GIL marker constrained to the lifetime of this type. @@ -984,7 +979,7 @@ impl PyAny { /// This is equivalent to the Python expression `super()` #[cfg(not(PyPy))] pub fn py_super(&self) -> PyResult<&PySuper> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .py_super() .map(Py2::into_gil_ref) } diff --git a/src/types/mod.rs b/src/types/mod.rs index ef2390cc809..1cdf8441bad 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -87,7 +87,9 @@ pub mod iter { #[macro_export] macro_rules! pyobject_native_type_base( ($name:ty $(;$generics:ident)* ) => { - unsafe impl<$($generics,)*> $crate::PyNativeType for $name {} + unsafe impl<$($generics,)*> $crate::PyNativeType for $name { + type AsRefSource = Self; + } impl<$($generics,)*> ::std::fmt::Debug for $name { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) diff --git a/src/types/pysuper.rs b/src/types/pysuper.rs index e53eda8b719..7e44249caa8 100644 --- a/src/types/pysuper.rs +++ b/src/types/pysuper.rs @@ -68,7 +68,7 @@ impl PySuper { ty: &Py2<'py, PyType>, obj: &Py2<'py, PyAny>, ) -> PyResult> { - Py2::::borrowed_from_gil_ref(&PySuper::type_object(ty.py())) + Py2::borrowed_from_gil_ref(&PySuper::type_object(ty.py())) .call1((ty, obj)) .map(|any| { // Safety: super() always returns instance of super diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 0b0a4cfeaa5..e3b76c12152 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -23,13 +23,13 @@ impl PySequence { /// This is equivalent to the Python expression `len(self)`. #[inline] pub fn len(&self) -> PyResult { - Py2::::borrowed_from_gil_ref(&self).len() + Py2::borrowed_from_gil_ref(&self).len() } /// Returns whether the sequence is empty. #[inline] pub fn is_empty(&self) -> PyResult { - Py2::::borrowed_from_gil_ref(&self).is_empty() + Py2::borrowed_from_gil_ref(&self).is_empty() } /// Returns the concatenation of `self` and `other`. @@ -37,8 +37,8 @@ impl PySequence { /// This is equivalent to the Python expression `self + other`. #[inline] pub fn concat(&self, other: &PySequence) -> PyResult<&PySequence> { - Py2::::borrowed_from_gil_ref(&self) - .concat(Py2::::borrowed_from_gil_ref(&other)) + Py2::borrowed_from_gil_ref(&self) + .concat(Py2::borrowed_from_gil_ref(&other)) .map(Py2::into_gil_ref) } @@ -47,7 +47,7 @@ impl PySequence { /// This is equivalent to the Python expression `self * count`. #[inline] pub fn repeat(&self, count: usize) -> PyResult<&PySequence> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .repeat(count) .map(Py2::into_gil_ref) } @@ -61,8 +61,8 @@ impl PySequence { /// possible, but create and return a new object if not. #[inline] pub fn in_place_concat(&self, other: &PySequence) -> PyResult<&PySequence> { - Py2::::borrowed_from_gil_ref(&self) - .in_place_concat(Py2::::borrowed_from_gil_ref(&other)) + Py2::borrowed_from_gil_ref(&self) + .in_place_concat(Py2::borrowed_from_gil_ref(&other)) .map(Py2::into_gil_ref) } @@ -75,7 +75,7 @@ impl PySequence { /// possible, but create and return a new object if not. #[inline] pub fn in_place_repeat(&self, count: usize) -> PyResult<&PySequence> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .in_place_repeat(count) .map(Py2::into_gil_ref) } @@ -85,7 +85,7 @@ impl PySequence { /// This is equivalent to the Python expression `self[index]` without support of negative indices. #[inline] pub fn get_item(&self, index: usize) -> PyResult<&PyAny> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .get_item(index) .map(|py2| py2.into_gil_ref()) } @@ -95,7 +95,7 @@ impl PySequence { /// This is equivalent to the Python expression `self[begin:end]`. #[inline] pub fn get_slice(&self, begin: usize, end: usize) -> PyResult<&PySequence> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .get_slice(begin, end) .map(Py2::into_gil_ref) } @@ -108,7 +108,7 @@ impl PySequence { where I: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).set_item(i, item) + Py2::borrowed_from_gil_ref(&self).set_item(i, item) } /// Deletes the `i`th element of self. @@ -116,7 +116,7 @@ impl PySequence { /// This is equivalent to the Python statement `del self[i]`. #[inline] pub fn del_item(&self, i: usize) -> PyResult<()> { - Py2::::borrowed_from_gil_ref(&self).del_item(i) + Py2::borrowed_from_gil_ref(&self).del_item(i) } /// Assigns the sequence `v` to the slice of `self` from `i1` to `i2`. @@ -124,11 +124,7 @@ impl PySequence { /// This is equivalent to the Python statement `self[i1:i2] = v`. #[inline] pub fn set_slice(&self, i1: usize, i2: usize, v: &PyAny) -> PyResult<()> { - Py2::::borrowed_from_gil_ref(&self).set_slice( - i1, - i2, - Py2::borrowed_from_gil_ref(&v), - ) + Py2::borrowed_from_gil_ref(&self).set_slice(i1, i2, Py2::borrowed_from_gil_ref(&v)) } /// Deletes the slice from `i1` to `i2` from `self`. @@ -136,7 +132,7 @@ impl PySequence { /// This is equivalent to the Python statement `del self[i1:i2]`. #[inline] pub fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> { - Py2::::borrowed_from_gil_ref(&self).del_slice(i1, i2) + Py2::borrowed_from_gil_ref(&self).del_slice(i1, i2) } /// Returns the number of occurrences of `value` in self, that is, return the @@ -147,7 +143,7 @@ impl PySequence { where V: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).count(value) + Py2::borrowed_from_gil_ref(&self).count(value) } /// Determines if self contains `value`. @@ -158,7 +154,7 @@ impl PySequence { where V: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).contains(value) + Py2::borrowed_from_gil_ref(&self).contains(value) } /// Returns the first index `i` for which `self[i] == value`. @@ -169,13 +165,13 @@ impl PySequence { where V: ToPyObject, { - Py2::::borrowed_from_gil_ref(&self).index(value) + Py2::borrowed_from_gil_ref(&self).index(value) } /// Returns a fresh list based on the Sequence. #[inline] pub fn to_list(&self) -> PyResult<&PyList> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .to_list() .map(|py2| py2.into_gil_ref()) } @@ -183,7 +179,7 @@ impl PySequence { /// Returns a fresh tuple based on the Sequence. #[inline] pub fn to_tuple(&self) -> PyResult<&PyTuple> { - Py2::::borrowed_from_gil_ref(&self) + Py2::borrowed_from_gil_ref(&self) .to_tuple() .map(|py2| py2.into_gil_ref()) }