I'm trying to make an iterator that attaches a reference to another object to each returned item.
The following code compiles just fine:
/// Holds row values and a reference to the column metadata so we it knows the column names and types:
pub struct TypedRow<'a> {
pub columns: &'a [ColumnSpec],
pub values: Vec<Value>,
}
impl TypedRow<'_> {
pub fn new(row: Row, columns: &[ColumnSpec]) -> TypedRow {
TypedRow {
columns,
values: row.values,
}
}
}
/// Iterates over rows, attaching the reference to metadata on the fly:
pub struct RowCursor {
columns: Vec<ColumnSpec>,
row_iter: <Vec<Row> as IntoIterator>::IntoIter,
}
impl RowCursor {
pub fn next_row(&mut self) -> Option<TypedRow> {
self.row_iter.next().map(move |r| { TypedRow::new(r, &self.columns) })
}
}
However, this is not an Iterator, so many useful stuff from iterators is not available.
So next I wanted to add a wrapper that would make an iterator for the RowCursor
.
I know it must be a separate struct and I can't directly make RowCursor
implement Iterator, because it returns values referencing self
. Streaming iterator doesn't work here either, because there is moving involved here as well (I'm not returning only a reference to itself).
Unexpectedly, I've run into lifetime problems:
pub struct RowIterator<'a> { // that should make the inner RowCursor live at least as long as the iterator, right?
cursor: &'a mut RowCursor
}
impl<'a> Iterator for RowIterator<'a> {
type Item = TypedRow<'a>;
fn next(&mut self) -> Option<TypedRow> {
self.cursor.next_row() // I thought it should be fine, because the TypedRow is attached to the inner RowCursor
}
}
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
--> stargate-grpc/src/result.rs:146:5
|
146 | fn next(&mut self) -> Option<TypedRow> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 146:13...
--> stargate-grpc/src/result.rs:146:13
|
146 | fn next(&mut self) -> Option<TypedRow> {
| ^^^^^^^^^
note: ...so that the method type is compatible with trait
--> stargate-grpc/src/result.rs:146:5
|
146 | fn next(&mut self) -> Option<TypedRow> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `fn(&mut RowIterator<'a>) -> std::option::Option<TypedRow<'_>>`
found `fn(&mut RowIterator<'a>) -> std::option::Option<TypedRow<'_>>`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 143:6...
--> stargate-grpc/src/result.rs:143:6
|
143 | impl<'a> Iterator for RowIterator<'a> {
| ^^
note: ...so that the types are compatible
--> stargate-grpc/src/result.rs:146:5
|
146 | fn next(&mut self) -> Option<TypedRow> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Iterator`
found `Iterator`
I guess the prioblem is that self.cursor
lifetime somehow gets shortened to the lifetime of &self here and not 'a (which might be longer). Is there a way to avoid it?
However, if I try to change &mut self
with &'a mut self
I get that my signature is incompatible with Iterator trait.