From 7801b7d2a4e68130cc56059c048871ae6ae76619 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Sat, 23 Mar 2024 15:27:37 +0000 Subject: [PATCH] move `downcast` functions from `PyAnyMethods` to `Bound` --- guide/src/types.md | 4 +- src/conversion.rs | 1 - src/conversions/num_bigint.rs | 8 +- src/conversions/num_complex.rs | 8 +- src/conversions/std/osstr.rs | 1 - src/conversions/std/string.rs | 2 +- src/err/mod.rs | 2 +- src/impl_/coroutine.rs | 2 +- src/impl_/pymethods.rs | 2 +- src/instance.rs | 219 ++++++++++++++++++++++++++++++++- src/py_result_ext.rs | 2 +- src/pybacked.rs | 6 +- src/pycell.rs | 1 - src/pyclass_init.rs | 1 - src/type_object.rs | 1 - src/types/any.rs | 199 +----------------------------- src/types/bytearray.rs | 1 - src/types/bytes.rs | 2 +- src/types/complex.rs | 2 +- src/types/datetime.rs | 3 +- src/types/dict.rs | 5 +- src/types/frozenset.rs | 2 +- src/types/function.rs | 2 - src/types/list.rs | 7 +- src/types/set.rs | 1 - src/types/slice.rs | 2 +- src/types/string.rs | 1 - src/types/tuple.rs | 2 +- 28 files changed, 245 insertions(+), 244 deletions(-) diff --git a/guide/src/types.md b/guide/src/types.md index 0f1fa3d0af1..bc8f82e60dd 100644 --- a/guide/src/types.md +++ b/guide/src/types.md @@ -446,8 +446,8 @@ let _: &PyAny = cell.as_ref(); [Py]: {{#PYO3_DOCS_URL}}/pyo3/struct.Py.html [PyAnyMethods::add]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.add [PyAnyMethods::extract]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.extract -[PyAnyMethods::downcast]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.downcast -[PyAnyMethods::downcast_into]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.downcast_into +[PyAnyMethods::downcast]: {{#PYO3_DOCS_URL}}/pyo3/struct.Bound.html#method.downcast +[PyAnyMethods::downcast_into]: {{#PYO3_DOCS_URL}}/pyo3/struct.Bound.html#method.downcast_into [`PyTypeCheck`]: {{#PYO3_DOCS_URL}}/pyo3/type_object/trait.PyTypeCheck.html [`PyAnyMethods`]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html [`PyDictMethods`]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyDictMethods.html diff --git a/src/conversion.rs b/src/conversion.rs index dfa53eac83e..4963c3dc0cc 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -4,7 +4,6 @@ use crate::err::{self, PyDowncastError, PyResult}; use crate::inspect::types::TypeInfo; use crate::pyclass::boolean_struct::False; use crate::type_object::PyTypeInfo; -use crate::types::any::PyAnyMethods; use crate::types::PyTuple; use crate::{ ffi, gil, Borrowed, Bound, Py, PyAny, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python, diff --git a/src/conversions/num_bigint.rs b/src/conversions/num_bigint.rs index 743df8a9923..7af83eddaf5 100644 --- a/src/conversions/num_bigint.rs +++ b/src/conversions/num_bigint.rs @@ -50,10 +50,8 @@ #[cfg(Py_LIMITED_API)] use crate::types::{bytes::PyBytesMethods, PyBytes}; use crate::{ - ffi, - instance::Bound, - types::{any::PyAnyMethods, PyLong}, - FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, + ffi, instance::Bound, types::PyLong, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, + Python, ToPyObject, }; use num_bigint::{BigInt, BigUint}; @@ -262,7 +260,7 @@ fn int_n_bits(long: &Bound<'_, PyLong>) -> PyResult { #[cfg(test)] mod tests { use super::*; - use crate::types::{PyDict, PyModule}; + use crate::types::{PyAnyMethods, PyDict, PyModule}; use indoc::indoc; fn rust_fib() -> impl Iterator diff --git a/src/conversions/num_complex.rs b/src/conversions/num_complex.rs index a57b2745ec9..9f4569b1e49 100644 --- a/src/conversions/num_complex.rs +++ b/src/conversions/num_complex.rs @@ -94,10 +94,8 @@ //! assert result == [complex(1,-1), complex(-2,0)] //! ``` use crate::{ - ffi, - ffi_ptr_ext::FfiPtrExt, - types::{any::PyAnyMethods, PyComplex}, - Bound, FromPyObject, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, + ffi, ffi_ptr_ext::FfiPtrExt, types::PyComplex, Bound, FromPyObject, PyAny, PyErr, PyObject, + PyResult, Python, ToPyObject, }; use num_complex::Complex; use std::os::raw::c_double; @@ -199,7 +197,7 @@ complex_conversion!(f64); #[cfg(test)] mod tests { use super::*; - use crate::types::{complex::PyComplexMethods, PyModule}; + use crate::types::{PyAnyMethods, PyComplexMethods, PyModule}; #[test] fn from_complex() { diff --git a/src/conversions/std/osstr.rs b/src/conversions/std/osstr.rs index b9382688589..02f73c0ddb3 100644 --- a/src/conversions/std/osstr.rs +++ b/src/conversions/std/osstr.rs @@ -1,5 +1,4 @@ use crate::instance::Bound; -use crate::types::any::PyAnyMethods; use crate::types::PyString; use crate::{ffi, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject}; use std::borrow::Cow; diff --git a/src/conversions/std/string.rs b/src/conversions/std/string.rs index 9c276d1d3d9..e9cb15dfbb2 100644 --- a/src/conversions/std/string.rs +++ b/src/conversions/std/string.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use crate::inspect::types::TypeInfo; use crate::{ instance::Bound, - types::{any::PyAnyMethods, string::PyStringMethods, PyString}, + types::{string::PyStringMethods, PyString}, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, }; diff --git a/src/err/mod.rs b/src/err/mod.rs index de1e621fc13..e1c6a86f0e8 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -119,7 +119,7 @@ impl<'py> DowncastIntoError<'py> { /// Consumes this `DowncastIntoError` and returns the original object, allowing continued /// use of it after a failed conversion. /// - /// See [`downcast_into`][PyAnyMethods::downcast_into] for an example. + /// See [`downcast_into`][Bound::downcast_into] for an example. pub fn into_inner(self) -> Bound<'py, PyAny> { self.from } diff --git a/src/impl_/coroutine.rs b/src/impl_/coroutine.rs index 1d3119400a0..b261e51b37e 100644 --- a/src/impl_/coroutine.rs +++ b/src/impl_/coroutine.rs @@ -8,7 +8,7 @@ use crate::{ instance::Bound, pycell::impl_::PyClassBorrowChecker, pyclass::boolean_struct::False, - types::{PyAnyMethods, PyString}, + types::PyString, IntoPy, Py, PyAny, PyClass, PyErr, PyObject, PyResult, Python, }; diff --git a/src/impl_/pymethods.rs b/src/impl_/pymethods.rs index df89dba7dbd..1ba959601f6 100644 --- a/src/impl_/pymethods.rs +++ b/src/impl_/pymethods.rs @@ -5,7 +5,7 @@ use crate::impl_::panic::PanicTrap; use crate::internal_tricks::extract_c_string; use crate::pycell::{PyBorrowError, PyBorrowMutError}; use crate::pyclass::boolean_struct::False; -use crate::types::{any::PyAnyMethods, PyModule, PyType}; +use crate::types::{PyModule, PyType}; use crate::{ ffi, Borrowed, Bound, DowncastError, Py, PyAny, PyClass, PyClassInitializer, PyErr, PyObject, PyRef, PyRefMut, PyResult, PyTraverseError, PyTypeCheck, PyVisit, Python, diff --git a/src/instance.rs b/src/instance.rs index 5f054d0d2d4..822e41b66b5 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -6,8 +6,8 @@ use crate::type_object::HasPyGilRef; use crate::types::{any::PyAnyMethods, string::PyStringMethods, typeobject::PyTypeMethods}; use crate::types::{DerefToPyAny, PyDict, PyString, PyTuple}; use crate::{ - ffi, AsPyPointer, DowncastError, FromPyObject, IntoPy, PyAny, PyClass, PyClassInitializer, - PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject, + ffi, AsPyPointer, DowncastError, DowncastIntoError, FromPyObject, IntoPy, PyAny, PyClass, + PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject, }; use crate::{gil, PyTypeCheck}; use std::marker::PhantomData; @@ -96,6 +96,221 @@ where } } +impl<'py, T> Bound<'py, T> { + /// Downcast this `PyAny` to a concrete Python type or pyclass. + /// + /// Note that you can often avoid downcasting yourself by just specifying + /// the desired type in function or method signatures. + /// However, manual downcasting is sometimes necessary. + /// + /// For extracting a Rust-only type, see [`PyAny::extract`](struct.PyAny.html#method.extract). + /// + /// # Example: Downcasting to a specific Python object + /// + /// ```rust + /// use pyo3::prelude::*; + /// use pyo3::types::{PyDict, PyList}; + /// + /// Python::with_gil(|py| { + /// let dict = PyDict::new_bound(py); + /// assert!(dict.is_instance_of::()); + /// let any = dict.as_any(); + /// + /// assert!(any.downcast::().is_ok()); + /// assert!(any.downcast::().is_err()); + /// }); + /// ``` + /// + /// # Example: Getting a reference to a pyclass + /// + /// This is useful if you want to mutate a `PyObject` that + /// might actually be a pyclass. + /// + /// ```rust + /// # fn main() -> Result<(), pyo3::PyErr> { + /// use pyo3::prelude::*; + /// + /// #[pyclass] + /// struct Class { + /// i: i32, + /// } + /// + /// Python::with_gil(|py| { + /// let class = Py::new(py, Class { i: 0 }).unwrap().into_bound(py).into_any(); + /// + /// let class_bound: &Bound<'_, Class> = class.downcast()?; + /// + /// class_bound.borrow_mut().i += 1; + /// + /// // Alternatively you can get a `PyRefMut` directly + /// let class_ref: PyRefMut<'_, Class> = class.extract()?; + /// assert_eq!(class_ref.i, 1); + /// Ok(()) + /// }) + /// # } + /// ``` + #[inline(always)] + pub fn downcast(&self) -> Result<&Bound<'py, U>, DowncastError<'_, 'py>> + where + U: PyTypeCheck, + { + #[inline] + fn inner<'a, 'py, U>( + any: &'a Bound<'py, PyAny>, + ) -> Result<&'a Bound<'py, U>, DowncastError<'a, 'py>> + where + U: PyTypeCheck, + { + if U::type_check(any) { + // Safety: type_check is responsible for ensuring that the type is correct + Ok(unsafe { any.downcast_unchecked() }) + } else { + Err(DowncastError::new(any, U::NAME)) + } + } + + inner(self.as_any()) + } + + /// Like `downcast` but takes ownership of `self`. + /// + /// In case of an error, it is possible to retrieve `self` again via [`DowncastIntoError::into_inner`]. + /// + /// # Example + /// + /// ```rust + /// use pyo3::prelude::*; + /// use pyo3::types::{PyDict, PyList}; + /// + /// Python::with_gil(|py| { + /// let obj: Bound<'_, PyAny> = PyDict::new_bound(py).into_any(); + /// + /// let obj: Bound<'_, PyAny> = match obj.downcast_into::() { + /// Ok(_) => panic!("obj should not be a list"), + /// Err(err) => err.into_inner(), + /// }; + /// + /// // obj is a dictionary + /// assert!(obj.downcast_into::().is_ok()); + /// }) + /// ``` + #[inline(always)] + pub fn downcast_into(self) -> Result, DowncastIntoError<'py>> + where + U: PyTypeCheck, + { + #[inline] + fn inner(any: Bound<'_, PyAny>) -> Result, DowncastIntoError<'_>> + where + U: PyTypeCheck, + { + if U::type_check(&any) { + // Safety: type_check is responsible for ensuring that the type is correct + Ok(unsafe { any.downcast_into_unchecked() }) + } else { + Err(DowncastIntoError::new(any, U::NAME)) + } + } + + inner(self.into_any()) + } + + /// Downcast this `PyAny` to a concrete Python type or pyclass (but not a subclass of it). + /// + /// It is almost always better to use [`PyAny::downcast`] because it accounts for Python + /// subtyping. Use this method only when you do not want to allow subtypes. + /// + /// The advantage of this method over [`PyAny::downcast`] is that it is faster. The implementation + /// of `downcast_exact` uses the equivalent of the Python expression `type(self) is T`, whereas + /// `downcast` uses `isinstance(self, T)`. + /// + /// For extracting a Rust-only type, see [`PyAny::extract`](struct.PyAny.html#method.extract). + /// + /// # Example: Downcasting to a specific Python object but not a subtype + /// + /// ```rust + /// use pyo3::prelude::*; + /// use pyo3::types::{PyBool, PyLong}; + /// + /// Python::with_gil(|py| { + /// let b = PyBool::new_bound(py, true); + /// assert!(b.is_instance_of::()); + /// let any: &Bound<'_, PyAny> = b.as_any(); + /// + /// // `bool` is a subtype of `int`, so `downcast` will accept a `bool` as an `int` + /// // but `downcast_exact` will not. + /// assert!(any.downcast::().is_ok()); + /// assert!(any.downcast_exact::().is_err()); + /// + /// assert!(any.downcast_exact::().is_ok()); + /// }); + /// ``` + #[inline(always)] + pub fn downcast_exact(&self) -> Result<&Bound<'py, U>, DowncastError<'_, 'py>> + where + U: PyTypeInfo, + { + #[inline] + fn inner<'a, 'py, U>( + any: &'a Bound<'py, PyAny>, + ) -> Result<&'a Bound<'py, U>, DowncastError<'a, 'py>> + where + U: PyTypeInfo, + { + if any.is_exact_instance_of::() { + // Safety: is_exact_instance_of is responsible for ensuring that the type is correct + Ok(unsafe { any.downcast_unchecked() }) + } else { + Err(DowncastError::new(any, U::NAME)) + } + } + + inner(self.as_any()) + } + + /// Like `downcast_exact` but takes ownership of `self`. + #[inline(always)] + pub fn downcast_into_exact(self) -> Result, DowncastIntoError<'py>> + where + U: PyTypeInfo, + { + #[inline] + fn inner(any: Bound<'_, PyAny>) -> Result, DowncastIntoError<'_>> + where + U: PyTypeInfo, + { + if any.is_exact_instance_of::() { + // Safety: is_exact_instance_of is responsible for ensuring that the type is correct + Ok(unsafe { any.downcast_into_unchecked() }) + } else { + Err(DowncastIntoError::new(any, U::NAME)) + } + } + + inner(self.into_any()) + } + + /// Converts this `PyAny` to a concrete Python type without checking validity. + /// + /// # Safety + /// + /// Callers must ensure that the type is valid or risk type confusion. + #[inline(always)] + pub unsafe fn downcast_unchecked(&self) -> &Bound<'py, U> { + &*(self as *const Bound<'py, T>).cast() + } + + /// Like `downcast_unchecked` but takes ownership of `self`. + /// + /// # Safety + /// + /// Callers must ensure that the type is valid or risk type confusion. + #[inline(always)] + pub unsafe fn downcast_into_unchecked(self) -> Bound<'py, U> { + std::mem::transmute(self) + } +} + impl<'py> Bound<'py, PyAny> { /// Constructs a new `Bound<'py, PyAny>` from a pointer. Panics if `ptr` is null. /// diff --git a/src/py_result_ext.rs b/src/py_result_ext.rs index 2ad079ed7ac..38b51c3ba0c 100644 --- a/src/py_result_ext.rs +++ b/src/py_result_ext.rs @@ -1,4 +1,4 @@ -use crate::{types::any::PyAnyMethods, Bound, PyAny, PyResult, PyTypeCheck}; +use crate::{Bound, PyAny, PyResult, PyTypeCheck}; pub(crate) trait PyResultExt<'py>: crate::sealed::Sealed { fn downcast_into(self) -> PyResult>; diff --git a/src/pybacked.rs b/src/pybacked.rs index bd29c830e65..d2569e35703 100644 --- a/src/pybacked.rs +++ b/src/pybacked.rs @@ -4,8 +4,8 @@ use std::{ops::Deref, ptr::NonNull}; use crate::{ types::{ - any::PyAnyMethods, bytearray::PyByteArrayMethods, bytes::PyBytesMethods, - string::PyStringMethods, PyByteArray, PyBytes, PyString, + bytearray::PyByteArrayMethods, bytes::PyBytesMethods, string::PyStringMethods, PyByteArray, + PyBytes, PyString, }, Bound, DowncastError, FromPyObject, Py, PyAny, PyErr, PyResult, }; @@ -119,7 +119,7 @@ impl FromPyObject<'_> for PyBackedBytes { #[cfg(test)] mod test { use super::*; - use crate::Python; + use crate::{types::PyAnyMethods, Python}; #[test] fn py_backed_str_empty() { diff --git a/src/pycell.rs b/src/pycell.rs index ccc55a756d6..12d8165dff7 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -203,7 +203,6 @@ use crate::pyclass::{ }; use crate::pyclass_init::PyClassInitializer; use crate::type_object::{PyLayout, PySizedLayout}; -use crate::types::any::PyAnyMethods; use crate::types::PyAny; use crate::{ffi, Bound, IntoPy, PyErr, PyNativeType, PyObject, PyResult, PyTypeCheck, Python}; use std::fmt; diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index 923bc5b7c5a..c46694cb42b 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -2,7 +2,6 @@ use crate::callback::IntoPyCallbackOutput; use crate::ffi_ptr_ext::FfiPtrExt; use crate::impl_::pyclass::{PyClassBaseType, PyClassDict, PyClassThreadChecker, PyClassWeakRef}; -use crate::types::PyAnyMethods; use crate::{ffi, Bound, Py, PyClass, PyErr, PyResult, Python}; use crate::{ ffi::PyTypeObject, diff --git a/src/type_object.rs b/src/type_object.rs index 84888bee458..74dfdc14b3f 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -1,7 +1,6 @@ //! Python type object information use crate::ffi_ptr_ext::FfiPtrExt; -use crate::types::any::PyAnyMethods; use crate::types::{PyAny, PyType}; use crate::{ffi, Bound, PyNativeType, Python}; diff --git a/src/types/any.rs b/src/types/any.rs index 19855abbb9a..608142e504a 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -1,6 +1,6 @@ use crate::class::basic::CompareOp; use crate::conversion::{AsPyPointer, FromPyObjectBound, IntoPy, ToPyObject}; -use crate::err::{DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyResult}; +use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::exceptions::{PyAttributeError, PyTypeError}; use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::Bound; @@ -1505,141 +1505,6 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed { /// Returns the Python type pointer for this object. fn get_type_ptr(&self) -> *mut ffi::PyTypeObject; - /// Downcast this `PyAny` to a concrete Python type or pyclass. - /// - /// Note that you can often avoid downcasting yourself by just specifying - /// the desired type in function or method signatures. - /// However, manual downcasting is sometimes necessary. - /// - /// For extracting a Rust-only type, see [`PyAny::extract`](struct.PyAny.html#method.extract). - /// - /// # Example: Downcasting to a specific Python object - /// - /// ```rust - /// use pyo3::prelude::*; - /// use pyo3::types::{PyDict, PyList}; - /// - /// Python::with_gil(|py| { - /// let dict = PyDict::new_bound(py); - /// assert!(dict.is_instance_of::()); - /// let any = dict.as_any(); - /// - /// assert!(any.downcast::().is_ok()); - /// assert!(any.downcast::().is_err()); - /// }); - /// ``` - /// - /// # Example: Getting a reference to a pyclass - /// - /// This is useful if you want to mutate a `PyObject` that - /// might actually be a pyclass. - /// - /// ```rust - /// # fn main() -> Result<(), pyo3::PyErr> { - /// use pyo3::prelude::*; - /// - /// #[pyclass] - /// struct Class { - /// i: i32, - /// } - /// - /// Python::with_gil(|py| { - /// let class = Py::new(py, Class { i: 0 }).unwrap().into_bound(py).into_any(); - /// - /// let class_bound: &Bound<'_, Class> = class.downcast()?; - /// - /// class_bound.borrow_mut().i += 1; - /// - /// // Alternatively you can get a `PyRefMut` directly - /// let class_ref: PyRefMut<'_, Class> = class.extract()?; - /// assert_eq!(class_ref.i, 1); - /// Ok(()) - /// }) - /// # } - /// ``` - fn downcast(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>> - where - T: PyTypeCheck; - - /// Like `downcast` but takes ownership of `self`. - /// - /// In case of an error, it is possible to retrieve `self` again via [`DowncastIntoError::into_inner`]. - /// - /// # Example - /// - /// ```rust - /// use pyo3::prelude::*; - /// use pyo3::types::{PyDict, PyList}; - /// - /// Python::with_gil(|py| { - /// let obj: Bound<'_, PyAny> = PyDict::new_bound(py).into_any(); - /// - /// let obj: Bound<'_, PyAny> = match obj.downcast_into::() { - /// Ok(_) => panic!("obj should not be a list"), - /// Err(err) => err.into_inner(), - /// }; - /// - /// // obj is a dictionary - /// assert!(obj.downcast_into::().is_ok()); - /// }) - /// ``` - fn downcast_into(self) -> Result, DowncastIntoError<'py>> - where - T: PyTypeCheck; - - /// Downcast this `PyAny` to a concrete Python type or pyclass (but not a subclass of it). - /// - /// It is almost always better to use [`PyAny::downcast`] because it accounts for Python - /// subtyping. Use this method only when you do not want to allow subtypes. - /// - /// The advantage of this method over [`PyAny::downcast`] is that it is faster. The implementation - /// of `downcast_exact` uses the equivalent of the Python expression `type(self) is T`, whereas - /// `downcast` uses `isinstance(self, T)`. - /// - /// For extracting a Rust-only type, see [`PyAny::extract`](struct.PyAny.html#method.extract). - /// - /// # Example: Downcasting to a specific Python object but not a subtype - /// - /// ```rust - /// use pyo3::prelude::*; - /// use pyo3::types::{PyBool, PyLong}; - /// - /// Python::with_gil(|py| { - /// let b = PyBool::new_bound(py, true); - /// assert!(b.is_instance_of::()); - /// let any: &Bound<'_, PyAny> = b.as_any(); - /// - /// // `bool` is a subtype of `int`, so `downcast` will accept a `bool` as an `int` - /// // but `downcast_exact` will not. - /// assert!(any.downcast::().is_ok()); - /// assert!(any.downcast_exact::().is_err()); - /// - /// assert!(any.downcast_exact::().is_ok()); - /// }); - /// ``` - fn downcast_exact(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>> - where - T: PyTypeInfo; - - /// Like `downcast_exact` but takes ownership of `self`. - fn downcast_into_exact(self) -> Result, DowncastIntoError<'py>> - where - T: PyTypeInfo; - - /// Converts this `PyAny` to a concrete Python type without checking validity. - /// - /// # Safety - /// - /// Callers must ensure that the type is valid or risk type confusion. - unsafe fn downcast_unchecked(&self) -> &Bound<'py, T>; - - /// Like `downcast_unchecked` but takes ownership of `self`. - /// - /// # Safety - /// - /// Callers must ensure that the type is valid or risk type confusion. - unsafe fn downcast_into_unchecked(self) -> Bound<'py, T>; - /// Extracts some type from the Python object. /// /// This is a wrapper function around @@ -2118,68 +1983,6 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> { unsafe { ffi::Py_TYPE(self.as_ptr()) } } - #[inline] - fn downcast(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>> - where - T: PyTypeCheck, - { - if T::type_check(self) { - // Safety: type_check is responsible for ensuring that the type is correct - Ok(unsafe { self.downcast_unchecked() }) - } else { - Err(DowncastError::new(self, T::NAME)) - } - } - - #[inline] - fn downcast_into(self) -> Result, DowncastIntoError<'py>> - where - T: PyTypeCheck, - { - if T::type_check(&self) { - // Safety: type_check is responsible for ensuring that the type is correct - Ok(unsafe { self.downcast_into_unchecked() }) - } else { - Err(DowncastIntoError::new(self, T::NAME)) - } - } - - #[inline] - fn downcast_exact(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>> - where - T: PyTypeInfo, - { - if self.is_exact_instance_of::() { - // Safety: is_exact_instance_of is responsible for ensuring that the type is correct - Ok(unsafe { self.downcast_unchecked() }) - } else { - Err(DowncastError::new(self, T::NAME)) - } - } - - #[inline] - fn downcast_into_exact(self) -> Result, DowncastIntoError<'py>> - where - T: PyTypeInfo, - { - if self.is_exact_instance_of::() { - // Safety: is_exact_instance_of is responsible for ensuring that the type is correct - Ok(unsafe { self.downcast_into_unchecked() }) - } else { - Err(DowncastIntoError::new(self, T::NAME)) - } - } - - #[inline] - unsafe fn downcast_unchecked(&self) -> &Bound<'py, T> { - &*(self as *const Bound<'py, PyAny>).cast() - } - - #[inline] - unsafe fn downcast_into_unchecked(self) -> Bound<'py, T> { - std::mem::transmute(self) - } - fn extract<'a, T>(&'a self) -> PyResult where T: FromPyObjectBound<'a, 'py>, diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 7227519975b..5b292c2669b 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -2,7 +2,6 @@ use crate::err::{PyErr, PyResult}; use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::{Borrowed, Bound}; use crate::py_result_ext::PyResultExt; -use crate::types::any::PyAnyMethods; use crate::{ffi, AsPyPointer, PyAny, PyNativeType, Python}; use std::os::raw::c_char; use std::slice; diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 44c87560514..e8c8b6232ef 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -1,6 +1,5 @@ use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::{Borrowed, Bound}; -use crate::types::any::PyAnyMethods; use crate::{ffi, Py, PyAny, PyNativeType, PyResult, Python}; use std::ops::Index; use std::os::raw::c_char; @@ -198,6 +197,7 @@ impl> Index for Bound<'_, PyBytes> { #[cfg(test)] mod tests { use super::*; + use crate::types::PyAnyMethods; #[test] fn test_bytes_index() { diff --git a/src/types/complex.rs b/src/types/complex.rs index 80ecffdc5cf..3bc15375d2a 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -1,4 +1,4 @@ -use crate::{ffi, types::any::PyAnyMethods, Bound, PyAny, PyNativeType, Python}; +use crate::{ffi, Bound, PyAny, PyNativeType, Python}; use std::os::raw::c_double; /// Represents a Python [`complex`](https://docs.python.org/3/library/functions.html#complex) object. diff --git a/src/types/datetime.rs b/src/types/datetime.rs index d46a2b77c33..4e7431fb89b 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -22,7 +22,6 @@ use crate::ffi::{ use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::PyNativeType; use crate::py_result_ext::PyResultExt; -use crate::types::any::PyAnyMethods; use crate::types::PyTuple; use crate::{Bound, IntoPy, Py, PyAny, PyErr, Python}; use std::os::raw::c_int; @@ -986,6 +985,8 @@ mod tests { #[cfg(all(feature = "macros", feature = "chrono"))] #[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons fn test_timezone_from_offset() { + use crate::types::PyAnyMethods; + Python::with_gil(|py| { assert!( timezone_from_offset(&PyDelta::new_bound(py, 0, -3600, 0, true).unwrap()) diff --git a/src/types/dict.rs b/src/types/dict.rs index 43bade5a80c..ddab8082c25 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -4,7 +4,6 @@ use crate::ffi::Py_ssize_t; use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::{Borrowed, Bound}; use crate::py_result_ext::PyResultExt; -use crate::types::any::PyAnyMethods; use crate::types::{PyAny, PyList}; use crate::{ffi, PyNativeType, Python, ToPyObject}; @@ -515,7 +514,7 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> { } fn into_mapping(self) -> Bound<'py, PyMapping> { - unsafe { self.into_any().downcast_into_unchecked() } + unsafe { self.downcast_into_unchecked() } } fn update(&self, other: &Bound<'_, PyMapping>) -> PyResult<()> { @@ -826,7 +825,7 @@ mod tests { use super::*; #[cfg(not(PyPy))] use crate::exceptions; - use crate::types::PyTuple; + use crate::types::{PyAnyMethods, PyTuple}; use std::collections::{BTreeMap, HashMap}; #[test] diff --git a/src/types/frozenset.rs b/src/types/frozenset.rs index 8a60efb8caa..382ac278e45 100644 --- a/src/types/frozenset.rs +++ b/src/types/frozenset.rs @@ -4,7 +4,6 @@ use crate::{ ffi, ffi_ptr_ext::FfiPtrExt, py_result_ext::PyResultExt, - types::any::PyAnyMethods, Bound, PyAny, PyNativeType, PyObject, Python, ToPyObject, }; use std::ptr; @@ -327,6 +326,7 @@ pub(crate) fn new_from_iter( #[cfg_attr(not(feature = "gil-refs"), allow(deprecated))] mod tests { use super::*; + use crate::types::PyAnyMethods; #[test] fn test_frozenset_new_and_len() { diff --git a/src/types/function.rs b/src/types/function.rs index f5305e31886..56fcc624af2 100644 --- a/src/types/function.rs +++ b/src/types/function.rs @@ -225,8 +225,6 @@ where F: Fn(&Bound<'_, PyTuple>, Option<&Bound<'_, PyDict>>) -> R + Send + 'static, R: crate::callback::IntoPyCallbackOutput<*mut ffi::PyObject>, { - use crate::types::any::PyAnyMethods; - crate::impl_::trampoline::cfunction_with_keywords( capsule_ptr, args, diff --git a/src/types/list.rs b/src/types/list.rs index 19dbe59510f..07e5b8d6c0e 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -5,12 +5,9 @@ use crate::ffi::{self, Py_ssize_t}; use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::Borrowed; use crate::internal_tricks::get_ssize_index; -use crate::types::{PySequence, PyTuple}; +use crate::types::{PySequence, PySequenceMethods, PyTuple}; use crate::{Bound, PyAny, PyNativeType, PyObject, Python, ToPyObject}; -use crate::types::any::PyAnyMethods; -use crate::types::sequence::PySequenceMethods; - /// Represents a Python `list`. #[repr(transparent)] pub struct PyList(PyAny); @@ -413,7 +410,7 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> { /// Returns `self` cast as a `PySequence`. fn into_sequence(self) -> Bound<'py, PySequence> { - unsafe { self.into_any().downcast_into_unchecked() } + unsafe { self.downcast_into_unchecked() } } /// Gets the list item at the specified index. diff --git a/src/types/set.rs b/src/types/set.rs index c043fa5ba4f..7461d7d8758 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -4,7 +4,6 @@ use crate::{ ffi_ptr_ext::FfiPtrExt, instance::Bound, py_result_ext::PyResultExt, - types::any::PyAnyMethods, PyNativeType, }; use crate::{ffi, PyAny, PyObject, Python, ToPyObject}; diff --git a/src/types/slice.rs b/src/types/slice.rs index 8e7545208dc..5d5d7b9e612 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -1,7 +1,6 @@ use crate::err::{PyErr, PyResult}; use crate::ffi::{self, Py_ssize_t}; use crate::ffi_ptr_ext::FfiPtrExt; -use crate::types::any::PyAnyMethods; use crate::{Bound, PyAny, PyNativeType, PyObject, Python, ToPyObject}; use std::os::raw::c_long; @@ -151,6 +150,7 @@ impl ToPyObject for PySliceIndices { #[cfg(test)] mod tests { use super::*; + use crate::types::PyAnyMethods; #[test] fn test_py_slice_new() { diff --git a/src/types/string.rs b/src/types/string.rs index 81c41adb545..cadc4316e04 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -3,7 +3,6 @@ use crate::exceptions::PyUnicodeDecodeError; use crate::ffi_ptr_ext::FfiPtrExt; use crate::instance::Borrowed; use crate::py_result_ext::PyResultExt; -use crate::types::any::PyAnyMethods; use crate::types::bytes::PyBytesMethods; use crate::types::PyBytes; use crate::{ffi, Bound, IntoPy, Py, PyAny, PyNativeType, PyResult, Python}; diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 4dfe4436bf0..26444e49e02 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -357,7 +357,7 @@ impl<'py> PyTupleMethods<'py> for Bound<'py, PyTuple> { } fn into_sequence(self) -> Bound<'py, PySequence> { - unsafe { self.into_any().downcast_into_unchecked() } + unsafe { self.downcast_into_unchecked() } } fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyTuple> {