Skip to content

Commit

Permalink
docs: add narrative docs for BoundObject
Browse files Browse the repository at this point in the history
  • Loading branch information
ngoldbaum committed Nov 14, 2024
1 parent a42e53e commit 2ce2ae1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
2 changes: 2 additions & 0 deletions guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ need to adapt an implementation of `IntoPyObject` to stay compatible with the Py
the new [`#[derive(IntoPyObject)]`](#intopyobject-derive-macro) macro can be used instead of
[manual implementations](#intopyobject-manual-implementation).

Since the `IntoPyObject::into_pyobject` may return either a `Bound` or `Borrowed`, you may find the [`BoundObject`](types.md#using-boundobject-to-deal-objects-that-may-be-bound-or-borrowed) trait to be useful to write code that generically handles either type of smart pointer.

Together with the introduction of `IntoPyObject` the old conversion traits `ToPyObject` and `IntoPy`
are deprecated and will be removed in a future PyO3 version.

Expand Down
32 changes: 32 additions & 0 deletions guide/src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,37 @@ let obj: &Py<PyAny> = borrowed.as_unbound();
let obj: Py<PyAny> = borrowed.to_owned().unbind().
```

### Using BoundObject to deal objects that may be Bound or Borrowed

You can use the [`BoundObject`][BoundObject] trait to handle function arguments or intermediate values in an iterator pipeline that may be either `Bound` or `Borrowed`. For example, the `IntoPyObject` implementation for `bool` returns a `Borrowed<'py, 'py, PyBool>`, but the implementation for `usize` returns a `Bound<'py, PyBool>`, so to write a function that generically converts vectors of either integers or bools into a vector of `Bound<'py, PyAny>`, you could do:

```rust
use pyo3::prelude::*;
use pyo3::BoundObject;
use pyo3::IntoPyObject;

let bools = vec![true, false, false, true];
let ints = vec![1, 2, 3, 4];

fn convert_to_vec_of_pyobj<'py, T: IntoPyObject<'py> + Copy>(py: Python<'py>, the_vec: Vec<T>) -> PyResult<Vec<Bound<'py, PyAny>>> {
the_vec.iter()
.map(|x| {
x.into_pyobject(py)
.map_err(Into::into)
.map(BoundObject::into_any)
.map(BoundObject::into_bound)
}
).collect()
}

Python::with_gil(|py| {
let vec_of_pybools = convert_to_vec_of_pyobj(py, bools);
let vec_of_pyints = convert_to_vec_of_pyobj(py, ints);
});
```

You can also import [`BoundObject`] to call methods shared by `Bound` or `Borrowed`.

## Concrete Python types

In all of `Py<T>`, `Bound<'py, T>`, and `Borrowed<'a, 'py, T>`, the type parameter `T` denotes the type of the Python object referred to by the smart pointer.
Expand Down Expand Up @@ -329,3 +360,4 @@ for more detail.
[PyList_append]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyList.html#method.append
[RefCell]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
[smart-pointers]: https://doc.rust-lang.org/book/ch15-00-smart-pointers.html
[BoundObject]: {{#PYO3_DOCS_URL}}/pyo3/instance/trait.BoundObject.html

0 comments on commit 2ce2ae1

Please sign in to comment.