Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add narrative docs for BoundObject #4703

Merged
merged 12 commits into from
Nov 15, 2024
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 `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
35 changes: 35 additions & 0 deletions guide/src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,40 @@ 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:
ngoldbaum marked this conversation as resolved.
Show resolved Hide resolved

```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>(py: Python<'py>, the_vec: Vec<T>) -> PyResult<Vec<Bound<'py, PyAny>>>
where
T: IntoPyObject<'py> + Copy
{
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` and `Borrowed`.
ngoldbaum marked this conversation as resolved.
Show resolved Hide resolved

## 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 +363,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
Loading