I am using maturin and I am trying to implement the method get_car()
for my class.
But using the following code
use pyo3::prelude::*;
#[pyclass]
struct Car {
name: String,
}
#[pyclass]
struct Garage {
cars: Vec<Car>,
}
#[pymethods]
impl Garage {
fn get_car(&self, name: &str) -> Option<&Car> {
self.cars.iter().find(|car| car.name == name.to_string())
}
}
/// A Python module implemented in Rust.
#[pymodule]
fn pyo3_iter_issue(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Car>()?;
m.add_class::<Garage>()?;
Ok(())
}
I get this error message
the trait bound `Car: AsPyPointer` is not satisfied
the following other types implement trait `AsPyPointer`:
CancelledError
IncompleteReadError
InvalidStateError
LimitOverrunError
Option<T>
PanicException
Py<T>
PyAny
and 107 others
required for `&Car` to implement `IntoPy<Py<PyAny>>`
1 redundant requirement hidden
required for `Option<&Car>` to implement `IntoPy<Py<PyAny>>`
required for `Option<&Car>` to implement `OkWrap<Option<&Car>>`
I am still very new to rust and I do not understand the issue here?
Rust does not have lifetimes, so any
&
references are not Python compatible.The easiest way to fix this would be to use
Car
and.clone()
instead:Of course that would create copies of the object, which isn't always desirable.
It's a lot harder to reference something from Python code, though. Even the default
get
/set
implementations thatpyo3
can create clone the data, they do not reference.For that, you would need a refcounter around your objects. In the standard library, this would be
Rc
, butRc
is managed by Rust and can therefore not be passed to Python.The equivalent Python-managed reference counter is called
Py
:This has the drawback that now every time you want to access the object, even just from within Rust code, you need a GIL lock.
The third option is to use
Rc
(orArc
, because of threadsafety), but don't expose it to Python directly; instead, write aCarRef
wrapper that carries it. But then you might have to also useMutex
because of internal mutability, and it all gets messy pretty quickly. Although it's of course doable:But as you can see, it's not quite straight-forward. But now you at least avoided the GIL lock.