From 6b3c6fdeee81f62ff1fb8064ab7bb7eee7e2d697 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Mon, 10 Aug 2020 20:08:48 +0100 Subject: [PATCH] Improve docs for Py::as_ref() and Py::into_ref() Co-authored-by: Georg Brandl --- guide/src/migration.md | 9 ++++++--- guide/src/types.md | 15 +++++++++++---- src/instance.rs | 36 ++++++++++++------------------------ 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/guide/src/migration.md b/guide/src/migration.md index 3b49231c..bd0dddba 100644 --- a/guide/src/migration.md +++ b/guide/src/migration.md @@ -60,9 +60,12 @@ This should change very little from a usage perspective. If you implemented trai `PyObject` and `Py`, you may find you can just remove the `PyObject` implementation. ### `AsPyRef` has been removed -The only implementor of `AsPyRef` was `Py`, so the `AsPyRef::as_ref` method has been moved to -`Py::as_ref`. This should require no code changes except removing the old `use` for code which -did not use `pyo3::prelude`. +As `PyObject` has been changed to be just a type alias, the only remaining implementor of `AsPyRef` +was `Py`. This removed the need for a trait, so the `AsPyRef::as_ref` method has been moved to +`Py::as_ref`. + +This should require no code changes except removing `use pyo3::AsPyRef` for code which did not use +`pyo3::prelude::*`. Before: ```rust,ignore diff --git a/guide/src/types.md b/guide/src/types.md index a61b0e32..6f2d97e1 100644 --- a/guide/src/types.md +++ b/guide/src/types.md @@ -140,11 +140,18 @@ Can be cloned using Python reference counts with `.clone()`. # let py = gil.python(); let list: Py = PyList::empty(py).into(); -// Access the native type using Py::as_ref(py) or Py::into_ref(py) -// (For #[pyclass] types, these will return &PyCell) -let _: &PyList = list.as_ref(py); -let _: &PyList = list.clone().into_ref(py); +// Access to the native type using Py::as_ref(py) or Py::into_ref(py) +// (For #[pyclass] types T, these will return &PyCell) +// Py::as_ref() borrows the object +let _: &PyList = list.as_ref(py); + +# let list_clone = list.clone(); // Just so that the .into() example for PyObject compiles. +// Py::into_ref() moves the reference into pyo3's "object storage"; useful for making APIs +// which return gil-bound references. +let _: &PyList = list.into_ref(py); + +# let list = list_clone; // Convert to PyObject with .into() let _: PyObject = list.into(); ``` diff --git a/src/instance.rs b/src/instance.rs index 3f374f1f..9cfc4002 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -37,7 +37,7 @@ pub unsafe trait PyNativeType: Sized { /// /// Accessing this object is thread-safe, since any access to its API requires a `Python<'py>` GIL /// token. There are a few different ways to use the Python object contained: -/// - [`Py::as_ref`](#method.as_ref) to borrow a GIL-bound reference to the contained object, +/// - [`Py::as_ref`](#method.as_ref) to borrow a GIL-bound reference to the contained object. /// - [`Py::borrow`](#method.borrow), [`Py::try_borrow`](#method.try_borrow), /// [`Py::borrow_mut`](#method.borrow_mut), or [`Py::try_borrow_mut`](#method.try_borrow_mut), /// to directly access a `#[pyclass]` value (which has RefCell-like behavior, see @@ -48,9 +48,6 @@ pub unsafe trait PyNativeType: Sized { /// /// See [the guide](https://pyo3.rs/master/types.html) for an explanation /// of the different Python object types. -/// -/// `Py` is implemented as a safe wrapper around `NonNull` with -/// specified type information. #[repr(transparent)] pub struct Py(NonNull, PhantomData); @@ -112,32 +109,23 @@ where unsafe { PyNativeType::unchecked_downcast(&*any) } } - /// Similar to [`as_ref`](#method.as_ref), but instead consumes this `Py` and registers the + /// Similar to [`as_ref`](#method.as_ref), and also consumes this `Py` and registers the /// Python object reference in PyO3's object storage. The reference count for the Python /// object will not be decreased until the GIL lifetime ends. /// - /// # Examples - /// Create `&PyList` from `Py`: - /// ``` - /// # use pyo3::prelude::*; - /// # use pyo3::types::PyList; - /// # Python::with_gil(|py| { - /// let list: Py = PyList::empty(py).into(); - /// let list: &PyList = list.into_ref(py); - /// assert_eq!(list.len(), 0); - /// # }); - /// ``` + /// # Example /// - /// Create `&PyCell` from `Py`: + /// Useful when returning GIL-bound references from functions. In the snippet below, note that + /// the `'py` lifetime of the input GIL lifetime is also given to the returned reference: /// ``` /// # use pyo3::prelude::*; - /// #[pyclass] - /// struct MyClass { } - /// # Python::with_gil(|py| { - /// let my_class: Py = Py::new(py, MyClass { }).unwrap(); - /// let my_class_cell: &PyCell = my_class.into_ref(py); - /// assert!(my_class_cell.try_borrow().is_ok()); - /// # }); + /// fn new_py_any<'py>(py: Python<'py>, value: impl IntoPy) -> &'py PyAny { + /// let obj: PyObject = value.into_py(py); + /// + /// // .as_ref(py) would not be suitable here, because a reference to `obj` may not be + /// // returned from the function. + /// obj.into_ref(py) + /// } /// ``` pub fn into_ref(self, py: Python) -> &T::AsRefTarget { unsafe { py.from_owned_ptr(self.into_ptr()) }