From fe7b1eed046e2cbc5b8321941a5cadbc04e4b075 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 24 Jan 2023 19:15:32 +0100 Subject: [PATCH] Update `downcast` documentation --- src/instance.rs | 51 ++++++++++++++++++++++++++++++++++++++++++------ src/types/any.rs | 36 +++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index b96c4cd5..9c473c84 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -991,10 +991,52 @@ impl std::fmt::Debug for Py { pub type PyObject = Py; impl PyObject { - /// Casts the PyObject to a concrete Python object type. + /// Downcast this `PyObject` to a concrete Python type or pyclass. /// - /// This can cast only to native Python types, not types implemented in Rust. For a more - /// flexible alternative, see [`Py::extract`](struct.Py.html#method.extract). + /// 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 [`Py::extract`](struct.Py.html#method.extract). + /// + /// # Example: Downcasting to a specific Python object + /// + /// ```rust + /// use pyo3::prelude::*; + /// use pyo3::types::{PyDict, PyList}; + /// + /// Python::with_gil(|py| { + /// let any: PyObject = PyDict::new(py).into(); + /// + /// assert!(any.downcast::(py).is_ok()); + /// assert!(any.downcast::(py).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. + /// + /// ``` + /// # fn main() -> Result<(), pyo3::PyErr> { + /// use pyo3::prelude::*; + /// + /// #[pyclass] + /// struct Class { + /// i: i32, + /// } + /// + /// Python::with_gil(|py| { + /// let class: PyObject = Py::new(py, Class { i: 0 }).unwrap().into_py(py); + /// + /// let class_cell: &PyCell = class.downcast(py)?; + /// + /// class_cell.borrow_mut().i += 1; + /// Ok(()) + /// }) + /// # } + /// ``` #[inline] pub fn downcast<'p, T>(&'p self, py: Python<'p>) -> Result<&T, PyDowncastError<'_>> where @@ -1005,9 +1047,6 @@ impl PyObject { /// Casts the PyObject to a concrete Python object type without checking validity. /// - /// This can cast only to native Python types, not types implemented in Rust. For a more - /// flexible alternative, see [`Py::extract`](struct.Py.html#method.extract). - /// /// # Safety /// /// Callers must ensure that the type is valid or risk type confusion. diff --git a/src/types/any.rs b/src/types/any.rs index 5abe9785..9a57fc17 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -755,11 +755,15 @@ impl PyAny { self.downcast() } - /// Converts this `PyAny` to a concrete Python type. + /// Downcast this `PyAny` to a concrete Python type or pyclass. /// - /// This can cast only to native Python types, not types implemented in Rust. + /// 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. /// - /// # Examples + /// 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::*; @@ -769,10 +773,36 @@ impl PyAny { /// let dict = PyDict::new(py); /// assert!(dict.is_instance_of::().unwrap()); /// let any: &PyAny = dict.as_ref(); + /// /// 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. + /// + /// ``` + /// # fn main() -> Result<(), pyo3::PyErr> { + /// use pyo3::prelude::*; + /// + /// #[pyclass] + /// struct Class { + /// i: i32, + /// } + /// + /// Python::with_gil(|py| { + /// let class: &PyAny = Py::new(py, Class { i: 0 }).unwrap().into_ref(py); + /// + /// let class_cell: &PyCell = class.downcast()?; + /// + /// class_cell.borrow_mut().i += 1; + /// Ok(()) + /// }) + /// # } + /// ``` #[inline] pub fn downcast<'p, T>(&'p self) -> Result<&'p T, PyDowncastError<'_>> where