I am looking to write a Rust backend for my library, and I need to implement the equivalent of the following function in pyo3
:
def f(x):
return x
This should return the same object as the input, and the function getting the return value should hold a new reference to the input. If I were writing this in the C API I would write it as:
PyObject * f(PyObject * x) {
Py_XINCREF(x);
return x;
}
In PyO3, I find it quite confusing to navigate the differences between PyObject
, PyObjectRef
, &PyObject
, Py<PyObject>
, Py<&PyObject>
.
The most naive version of this function is:
extern crate pyo3;
use pyo3::prelude::*;
#[pyfunction]
pub fn f(_py: Python, x: &PyObject) -> PyResult<&PyObject> {
Ok(x)
}
Among other things, the lifetimes of x
and the return value are not the same, plus I see no opportunity for pyo3
to increase the reference count for x
, and in fact the compiler seems to agree with me:
error[E0106]: missing lifetime specifier
--> src/lib.rs:4:49
|
4 | pub fn f(_py: Python, x: &PyObject) -> PyResult<&PyObject> {
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_py` or `x`
There may be a way for me to manually increase the reference count using the _py
parameter and use lifetime annotations to make the compiler happy, but my impression is that pyo3
intends to manage reference counts itself using object lifetimes.
What is the proper way to write this function? Should I be attempting to wrap it in a Py
container?