seals `PyAnyMethods` and friends (#3909)

* seals `PyAnyMethods` and friends

This seals these new traits, preventing downstream
crates from implementing them on their types.
These traits are mainly a workaround for arbitrary
self receiver types, so this gives us more
flexibility if these need to be changed in the
future.

* move `PyResultExt` seal
This commit is contained in:
Icxolu 2024-02-28 20:36:55 +01:00 committed by GitHub
parent 8a12970c96
commit 55833365b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 56 additions and 40 deletions

View File

@ -1,19 +1,10 @@
use crate::sealed::Sealed;
use crate::{ use crate::{
ffi, ffi,
instance::{Borrowed, Bound}, instance::{Borrowed, Bound},
PyAny, PyResult, Python, PyAny, PyResult, Python,
}; };
mod sealed {
use super::*;
pub trait Sealed {}
impl Sealed for *mut ffi::PyObject {}
}
use sealed::Sealed;
pub(crate) trait FfiPtrExt: Sealed { pub(crate) trait FfiPtrExt: Sealed {
unsafe fn assume_owned_or_err(self, py: Python<'_>) -> PyResult<Bound<'_, PyAny>>; unsafe fn assume_owned_or_err(self, py: Python<'_>) -> PyResult<Bound<'_, PyAny>>;
unsafe fn assume_owned_or_opt(self, py: Python<'_>) -> Option<Bound<'_, PyAny>>; unsafe fn assume_owned_or_opt(self, py: Python<'_>) -> Option<Bound<'_, PyAny>>;

View File

@ -324,6 +324,7 @@ pub use crate::version::PythonVersionInfo;
pub(crate) mod ffi_ptr_ext; pub(crate) mod ffi_ptr_ext;
pub(crate) mod py_result_ext; pub(crate) mod py_result_ext;
pub(crate) mod sealed;
/// Old module which contained some implementation details of the `#[pyproto]` module. /// Old module which contained some implementation details of the `#[pyproto]` module.
/// ///

View File

@ -1,16 +1,6 @@
use crate::{types::any::PyAnyMethods, Bound, PyAny, PyResult, PyTypeCheck}; use crate::{types::any::PyAnyMethods, Bound, PyAny, PyResult, PyTypeCheck};
mod sealed { pub(crate) trait PyResultExt<'py>: crate::sealed::Sealed {
use super::*;
pub trait Sealed {}
impl Sealed for PyResult<Bound<'_, PyAny>> {}
}
use sealed::Sealed;
pub(crate) trait PyResultExt<'py>: Sealed {
fn downcast_into<T: PyTypeCheck>(self) -> PyResult<Bound<'py, T>>; fn downcast_into<T: PyTypeCheck>(self) -> PyResult<Bound<'py, T>>;
unsafe fn downcast_into_unchecked<T>(self) -> PyResult<Bound<'py, T>>; unsafe fn downcast_into_unchecked<T>(self) -> PyResult<Bound<'py, T>>;
} }

34
src/sealed.rs Normal file
View File

@ -0,0 +1,34 @@
use crate::types::{
PyBool, PyByteArray, PyBytes, PyCapsule, PyComplex, PyDict, PyFloat, PyFrozenSet, PyList,
PyMapping, PyModule, PySequence, PySet, PySlice, PyString, PyTraceback, PyTuple, PyType,
};
use crate::{ffi, Bound, PyAny, PyResult};
pub trait Sealed {}
// for FfiPtrExt
impl Sealed for *mut ffi::PyObject {}
// for PyResultExt
impl Sealed for PyResult<Bound<'_, PyAny>> {}
// for Py(...)Methods
impl Sealed for Bound<'_, PyAny> {}
impl Sealed for Bound<'_, PyBool> {}
impl Sealed for Bound<'_, PyByteArray> {}
impl Sealed for Bound<'_, PyBytes> {}
impl Sealed for Bound<'_, PyCapsule> {}
impl Sealed for Bound<'_, PyComplex> {}
impl Sealed for Bound<'_, PyDict> {}
impl Sealed for Bound<'_, PyFloat> {}
impl Sealed for Bound<'_, PyFrozenSet> {}
impl Sealed for Bound<'_, PyList> {}
impl Sealed for Bound<'_, PyMapping> {}
impl Sealed for Bound<'_, PyModule> {}
impl Sealed for Bound<'_, PySequence> {}
impl Sealed for Bound<'_, PySet> {}
impl Sealed for Bound<'_, PySlice> {}
impl Sealed for Bound<'_, PyString> {}
impl Sealed for Bound<'_, PyTraceback> {}
impl Sealed for Bound<'_, PyTuple> {}
impl Sealed for Bound<'_, PyType> {}

View File

@ -939,7 +939,7 @@ impl PyAny {
/// It is recommended you import this trait via `use pyo3::prelude::*` rather than /// It is recommended you import this trait via `use pyo3::prelude::*` rather than
/// by importing this trait directly. /// by importing this trait directly.
#[doc(alias = "PyAny")] #[doc(alias = "PyAny")]
pub trait PyAnyMethods<'py> { pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
/// Returns whether `self` and `other` point to the same object. To compare /// Returns whether `self` and `other` point to the same object. To compare
/// the equality of two objects (the `==` operator), use [`eq`](PyAny::eq). /// the equality of two objects (the `==` operator), use [`eq`](PyAny::eq).
/// ///

View File

@ -55,7 +55,7 @@ impl PyBool {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyBool")] #[doc(alias = "PyBool")]
pub trait PyBoolMethods<'py> { pub trait PyBoolMethods<'py>: crate::sealed::Sealed {
/// Gets whether this boolean is `true`. /// Gets whether this boolean is `true`.
fn is_true(&self) -> bool; fn is_true(&self) -> bool;
} }

View File

@ -293,7 +293,7 @@ impl PyByteArray {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyByteArray")] #[doc(alias = "PyByteArray")]
pub trait PyByteArrayMethods<'py> { pub trait PyByteArrayMethods<'py>: crate::sealed::Sealed {
/// Gets the length of the bytearray. /// Gets the length of the bytearray.
fn len(&self) -> usize; fn len(&self) -> usize;

View File

@ -143,7 +143,7 @@ impl PyBytes {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyBytes")] #[doc(alias = "PyBytes")]
pub trait PyBytesMethods<'py> { pub trait PyBytesMethods<'py>: crate::sealed::Sealed {
/// Gets the Python string as a byte slice. /// Gets the Python string as a byte slice.
fn as_bytes(&self) -> &[u8]; fn as_bytes(&self) -> &[u8];
} }

View File

@ -263,7 +263,7 @@ impl PyCapsule {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyCapsule")] #[doc(alias = "PyCapsule")]
pub trait PyCapsuleMethods<'py> { pub trait PyCapsuleMethods<'py>: crate::sealed::Sealed {
/// Sets the context pointer in the capsule. /// Sets the context pointer in the capsule.
/// ///
/// Returns an error if this capsule is not valid. /// Returns an error if this capsule is not valid.

View File

@ -258,7 +258,7 @@ mod not_limited_impls {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyComplex")] #[doc(alias = "PyComplex")]
pub trait PyComplexMethods<'py> { pub trait PyComplexMethods<'py>: crate::sealed::Sealed {
/// Returns the real part of the complex number. /// Returns the real part of the complex number.
fn real(&self) -> c_double; fn real(&self) -> c_double;
/// Returns the imaginary part of the complex number. /// Returns the imaginary part of the complex number.

View File

@ -290,7 +290,7 @@ impl PyDict {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyDict")] #[doc(alias = "PyDict")]
pub trait PyDictMethods<'py> { pub trait PyDictMethods<'py>: crate::sealed::Sealed {
/// Returns a new dictionary that contains the same key-value pairs as self. /// Returns a new dictionary that contains the same key-value pairs as self.
/// ///
/// This is equivalent to the Python expression `self.copy()`. /// This is equivalent to the Python expression `self.copy()`.

View File

@ -58,7 +58,7 @@ impl PyFloat {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyFloat")] #[doc(alias = "PyFloat")]
pub trait PyFloatMethods<'py> { pub trait PyFloatMethods<'py>: crate::sealed::Sealed {
/// Gets the value of this float. /// Gets the value of this float.
fn value(&self) -> c_double; fn value(&self) -> c_double;
} }

View File

@ -157,7 +157,7 @@ impl PyFrozenSet {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyFrozenSet")] #[doc(alias = "PyFrozenSet")]
pub trait PyFrozenSetMethods<'py> { pub trait PyFrozenSetMethods<'py>: crate::sealed::Sealed {
/// Returns the number of items in the set. /// Returns the number of items in the set.
/// ///
/// This is equivalent to the Python expression `len(self)`. /// This is equivalent to the Python expression `len(self)`.

View File

@ -285,7 +285,7 @@ index_impls!(PyList, "list", PyList::len, PyList::get_slice);
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyList")] #[doc(alias = "PyList")]
pub trait PyListMethods<'py> { pub trait PyListMethods<'py>: crate::sealed::Sealed {
/// Returns the length of the list. /// Returns the length of the list.
fn len(&self) -> usize; fn len(&self) -> usize;

View File

@ -109,7 +109,7 @@ impl PyMapping {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyMapping")] #[doc(alias = "PyMapping")]
pub trait PyMappingMethods<'py> { pub trait PyMappingMethods<'py>: crate::sealed::Sealed {
/// Returns the number of objects in the mapping. /// Returns the number of objects in the mapping.
/// ///
/// This is equivalent to the Python expression `len(self)`. /// This is equivalent to the Python expression `len(self)`.

View File

@ -410,7 +410,7 @@ impl PyModule {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyModule")] #[doc(alias = "PyModule")]
pub trait PyModuleMethods<'py> { pub trait PyModuleMethods<'py>: crate::sealed::Sealed {
/// Returns the module's `__dict__` attribute, which contains the module's symbol table. /// Returns the module's `__dict__` attribute, which contains the module's symbol table.
fn dict(&self) -> Bound<'py, PyDict>; fn dict(&self) -> Bound<'py, PyDict>;

View File

@ -192,7 +192,7 @@ impl PySequence {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PySequence")] #[doc(alias = "PySequence")]
pub trait PySequenceMethods<'py> { pub trait PySequenceMethods<'py>: crate::sealed::Sealed {
/// Returns the number of objects in sequence. /// Returns the number of objects in sequence.
/// ///
/// This is equivalent to the Python expression `len(self)`. /// This is equivalent to the Python expression `len(self)`.

View File

@ -139,7 +139,7 @@ impl PySet {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PySet")] #[doc(alias = "PySet")]
pub trait PySetMethods<'py> { pub trait PySetMethods<'py>: crate::sealed::Sealed {
/// Removes all elements from the set. /// Removes all elements from the set.
fn clear(&self); fn clear(&self);

View File

@ -105,7 +105,7 @@ impl PySlice {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PySlice")] #[doc(alias = "PySlice")]
pub trait PySliceMethods<'py> { pub trait PySliceMethods<'py>: crate::sealed::Sealed {
/// Retrieves the start, stop, and step indices from the slice object, /// Retrieves the start, stop, and step indices from the slice object,
/// assuming a sequence of length `length`, and stores the length of the /// assuming a sequence of length `length`, and stores the length of the
/// slice in its `slicelength` member. /// slice in its `slicelength` member.

View File

@ -282,7 +282,7 @@ impl PyString {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyString")] #[doc(alias = "PyString")]
pub trait PyStringMethods<'py> { pub trait PyStringMethods<'py>: crate::sealed::Sealed {
/// Gets the Python string as a Rust UTF-8 string slice. /// Gets the Python string as a Rust UTF-8 string slice.
/// ///
/// Returns a `UnicodeEncodeError` if the input is not valid unicode /// Returns a `UnicodeEncodeError` if the input is not valid unicode

View File

@ -56,7 +56,7 @@ impl PyTraceback {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyTraceback")] #[doc(alias = "PyTraceback")]
pub trait PyTracebackMethods<'py> { pub trait PyTracebackMethods<'py>: crate::sealed::Sealed {
/// Formats the traceback as a string. /// Formats the traceback as a string.
/// ///
/// This does not include the exception type and value. The exception type and value can be /// This does not include the exception type and value. The exception type and value can be

View File

@ -248,7 +248,7 @@ index_impls!(PyTuple, "tuple", PyTuple::len, PyTuple::get_slice);
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyTuple")] #[doc(alias = "PyTuple")]
pub trait PyTupleMethods<'py> { pub trait PyTupleMethods<'py>: crate::sealed::Sealed {
/// Gets the length of the tuple. /// Gets the length of the tuple.
fn len(&self) -> usize; fn len(&self) -> usize;

View File

@ -107,7 +107,7 @@ impl PyType {
/// syntax these methods are separated into a trait, because stable Rust does not yet support /// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`. /// `arbitrary_self_types`.
#[doc(alias = "PyType")] #[doc(alias = "PyType")]
pub trait PyTypeMethods<'py> { pub trait PyTypeMethods<'py>: crate::sealed::Sealed {
/// Retrieves the underlying FFI pointer associated with this Python object. /// Retrieves the underlying FFI pointer associated with this Python object.
fn as_type_ptr(&self) -> *mut ffi::PyTypeObject; fn as_type_ptr(&self) -> *mut ffi::PyTypeObject;