Merge pull request #3653 from davidhewitt/native-type-source

Add `AsRefSource` to `PyNativeType`.
This commit is contained in:
David Hewitt 2023-12-14 22:33:49 +00:00 committed by GitHub
commit 97cf9b834c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 79 deletions

View File

@ -0,0 +1 @@
Add `AsRefSource` to `PyNativeType`.

View File

@ -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<T>` smart pointer.
type AsRefSource: HasPyGilRef<AsRefTarget = Self>;
/// 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<AsRefSource = T>,
{
// 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>

View File

@ -275,7 +275,9 @@ pub(crate) struct PyCellContents<T: PyClassImpl> {
pub(crate) weakref: T::WeakRef,
}
unsafe impl<T: PyClass> PyNativeType for PyCell<T> {}
unsafe impl<T: PyClass> PyNativeType for PyCell<T> {
type AsRefSource = T;
}
impl<T: PyClass> PyCell<T> {
/// Makes a new `PyCell` on the Python heap and return the reference to it.

View File

@ -73,7 +73,7 @@ impl PyAny {
/// This is equivalent to the Python expression `self is other`.
#[inline]
pub fn is<T: AsPyPointer>(&self, other: &T) -> bool {
Py2::<PyAny>::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<Py<PyString>>,
{
Py2::<PyAny>::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<Py<PyString>>,
{
Py2::<PyAny>::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<Py<PyString>>,
V: ToPyObject,
{
Py2::<PyAny>::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<Py<PyString>>,
{
Py2::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<&PyAny> {
Py2::<PyAny>::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::<PyAny>::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<Py<PyTuple>>) -> PyResult<&PyAny> {
Py2::<PyAny>::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<Py<PyString>>,
A: IntoPy<Py<PyTuple>>,
{
Py2::<PyAny>::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<Py<PyString>>,
{
Py2::<PyAny>::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<Py<PyString>>,
A: IntoPy<Py<PyTuple>>,
{
Py2::<PyAny>::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<bool> {
Py2::<PyAny>::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::<PyAny>::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::<PyAny>::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<bool> {
Py2::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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::<PyAny>::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<isize> {
Py2::<PyAny>::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<usize> {
Py2::<PyAny>::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::<PyAny>::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<bool> {
Py2::<PyAny>::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::<PyAny>::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<T: PyTypeInfo>(&self) -> bool {
Py2::<PyAny>::borrowed_from_gil_ref(&self).is_instance_of::<T>()
Py2::borrowed_from_gil_ref(&self).is_instance_of::<T>()
}
/// 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<T: PyTypeInfo>(&self) -> bool {
Py2::<PyAny>::borrowed_from_gil_ref(&self).is_exact_instance_of::<T>()
Py2::borrowed_from_gil_ref(&self).is_exact_instance_of::<T>()
}
/// Determines if self contains `value`.
@ -945,7 +940,7 @@ impl PyAny {
where
V: ToPyObject,
{
Py2::<PyAny>::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::<PyAny>::borrowed_from_gil_ref(&self)
Py2::borrowed_from_gil_ref(&self)
.py_super()
.map(Py2::into_gil_ref)
}

View File

@ -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<'_>)

View File

@ -68,7 +68,7 @@ impl PySuper {
ty: &Py2<'py, PyType>,
obj: &Py2<'py, PyAny>,
) -> PyResult<Py2<'py, PySuper>> {
Py2::<PyType>::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

View File

@ -23,13 +23,13 @@ impl PySequence {
/// This is equivalent to the Python expression `len(self)`.
#[inline]
pub fn len(&self) -> PyResult<usize> {
Py2::<PySequence>::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<bool> {
Py2::<PySequence>::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::<PySequence>::borrowed_from_gil_ref(&self)
.concat(Py2::<PySequence>::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::<PySequence>::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::<PySequence>::borrowed_from_gil_ref(&self)
.in_place_concat(Py2::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::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::<PySequence>::borrowed_from_gil_ref(&self)
Py2::borrowed_from_gil_ref(&self)
.to_tuple()
.map(|py2| py2.into_gil_ref())
}