I have a struct (Lines) containing a vec of Coordinates.
I'm trying to implement a non-consuming mutable iterator over non-overlapping sub-slices into this vector as &mut [Coordinate]
. Each sub-slice would represent 1 line stored in Lines.
-edit: Additionally the lists of indices may be reordered without the vertices being moved. As such the lines in vertices cannot be assumed to be in the same order as the indices.
The implementation works for the immutable iterator (same implementation as below, but without mut
s)
use std::ops::{Index, IndexMut};
#[derive(Debug)]
pub struct Coordinate {
x: u32,
y: u32,
}
/// SOA containing multiple line geometries
/// All coordinates of all the lines are stored contiguously in vertices
/// start_indices & end_indices both contain 1 entry for every geometry
#[derive(Debug)]
struct Lines {
vertices: Vec<Coordinate>,
start_indices: Vec<usize>,
end_indices: Vec<usize>,
}
impl Lines {
pub fn len(&self) -> usize {
self.start_indices.len()
}
fn iter_mut(&mut self) -> LinesIterMut {
LinesIterMut {
lines: self,
next_index: 0,
}
}
}
impl Index<usize> for Lines {
type Output = [Coordinate];
fn index(&self, index: usize) -> &Self::Output {
&self.vertices[self.start_indices[index]..self.end_indices[index]]
}
}
impl IndexMut<usize> for Lines {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.vertices[self.start_indices[index]..self.end_indices[index]]
}
}
pub struct LinesIterMut<'a> {
lines: &'a mut Lines,
next_index: usize,
}
impl<'a> Iterator for LinesIterMut<'a> {
type Item = &'a mut [Coordinate];
fn next(&mut self) -> Option<Self::Item> {
if self.next_index < self.lines.len() {
let current_index = self.next_index;
self.next_index += 1;
Some(&mut self.lines[current_index])
} else {
None
}
}
}
fn main() {
let mut my_lines = Lines {
vertices: vec![
Coordinate {
x: 1,
y: 2,
},
Coordinate {
x: 4,
y: 5,
},
],
start_indices: vec![0],
end_indices: vec![2],
};
for line in my_lines.iter_mut() {
line[0].y = 33;
println!("=> {:?}", line);
}
}
I get the following lifetime error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:54:23
|
54 | Some(&mut self.lines[current_index])
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 50:5...
--> src/main.rs:50:5
|
50 | fn next(&mut self) -> Option<Self::Item> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:54:23
|
54 | Some(&mut self.lines[current_index])
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 47:6...
--> src/main.rs:47:6
|
47 | impl<'a> Iterator for LinesIterMut<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:50:46
|
50 | fn next(&mut self) -> Option<Self::Item> {
| ______________________________________________^
51 | | if self.next_index < self.lines.len() {
52 | | let current_index = self.next_index;
53 | | self.next_index += 1;
... |
57 | | }
58 | | }
| |_____^
= note: expected `Iterator`
found `Iterator`
How do I tell the compiler that the lifetime of the reference is related to Lines?
-edit: Using the link provided by @kmdreko : https://stackoverflow.com/a/60072822/13138916 I wrote this. It works, but is this safe? How can I tell?
pub struct LinesIterMut<'a> {
lines: &'a mut Lines,
next_index: usize,
}
impl<'a> Iterator for LinesIterMut<'a> {
type Item = &'a mut [Coordinate];
fn next(&mut self) -> Option<Self::Item> {
if self.next_index < self.lines.len() {
let current_index = self.next_index;
self.next_index += 1;
Some(unsafe { std::mem::transmute(&mut self.lines[current_index]) }) // <<--- Only changed this line
} else {
None
}
}
}