Its not like I am not able to return any rust iterators from a python module function using pyo3. The problem is when lifetime doesn't live long enough!
Allow me to explain.
First attempt:
#[pyclass]
struct ItemIterator {
iter: Box<dyn Iterator<Item = u64> + Send>,
}
#[pymethods]
impl ItemIterator {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<u64> {
slf.iter.next()
}
}
#[pyfunction]
fn get_numbers() -> ItemIterator {
let i = vec![1u64, 2, 3, 4, 5].into_iter();
ItemIterator { iter: Box::new(i) }
}
In the contrived example above I have written a python iterator wrapper for our rust iterator as per pyo3 guide and it works seemlessly.
Second attempt:
The problem is when lifetimes are involved.
Say now I have a Warehouse
struct that I would want make available as python class alongside pertaining associated functions.
struct Warehouse {
items: Vec<u64>,
}
impl Warehouse {
fn new() -> Warehouse {
Warehouse {
items: vec![1u64, 2, 3, 4, 5],
}
}
fn get_items(&self) -> Box<dyn Iterator<Item = u64> + '_> {
Box::new(self.items.iter().map(|f| *f))
}
}
Implementing them as python class and methods
#[pyclass]
struct ItemIterator {
iter: Box<dyn Iterator<Item = u64> + Send>,
}
#[pymethods]
impl ItemIterator {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<u64> {
slf.iter.next()
}
}
#[pyclass]
struct Warehouse {
items: Vec<u64>,
}
#[pymethods]
impl Warehouse {
#[new]
fn new() -> Warehouse {
Warehouse {
items: vec![1u64, 2, 3, 4, 5],
}
}
fn get_items(&self) -> ItemIterator {
ItemIterator {
iter: Box::new(self.items.iter().map(|f| *f)),
}
}
}
This throws compiler error in getItems
function saying:
error: lifetime may not live long enough
--> src/lib.rs:54:19
|
52 | fn get_items(&self) -> ItemIterator {
| - let's call the lifetime of this reference `'1`
53 | ItemIterator {
54 | iter: Box::new(self.items.iter().map(|f| *f)),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
error: could not compile `pyo3-example` due to previous error
I am not really sure how to fix this. Can someone explain what's really going on here. How does this compare to my first attempt implementing iterators and how to fix this?