Another complicated lifetime problem

use std::ops::Index;

#[derive(Clone)]
struct Polygon;

#[derive(Clone)]
struct Polygons(Vec<Polygon>);

impl Index<usize> for Polygons {
    type Output = Polygon;

    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }
}

#[derive(Clone, PartialEq, PartialOrd)]
struct PathsPointIndex<'a, T> {
    polygons: &'a T,
    poly_idx: usize,
    point_idx: usize,
}

impl<'a, T> PathsPointIndex<'a, T> {
    fn new(polygons: &'a T, poly_idx: usize, point_idx: usize) -> Self {
        Self {
            polygons,
            poly_idx,
            point_idx,
        }
    }
}

struct ClosestPolygonPoint<'a> {
    poly: &'a Polygon,
}

impl<'a> ClosestPolygonPoint<'a> {
    fn new(poly: &'a Polygon) -> Self {
        Self { poly }
    }
}

struct Tower<'a> {
    outer_polygon: Polygons,
    start_locations: Vec<ClosestPolygonPoint<'a>>,
}

impl<'a> Tower<'a> {
    fn generate(&mut self) {
        let segment_start = PathsPointIndex::new(&self.outer_polygon, 0, 0);
        let segment_end = segment_start.clone();

        spread_dots(segment_start, segment_end, &mut self.start_locations);
    }
}

fn spread_dots(
    start: PathsPointIndex<Polygons>,
    _end: PathsPointIndex<Polygons>,
    result: &mut Vec<ClosestPolygonPoint>,
) {
    let polygon: &Polygon = &start.polygons[start.poly_idx];
    let closest = ClosestPolygonPoint::new(polygon);

    result.push(closest);
}

error: lifetime may not live long enough
  --> src/lib.rs:66:5
   |
59 |     start: PathsPointIndex<Polygons>,
   |     ----- has type `PathsPointIndex<'1, Polygons>`
60 |     _end: PathsPointIndex<Polygons>,
61 |     result: &mut Vec<ClosestPolygonPoint>,
   |     ------ has type `&mut Vec<ClosestPolygonPoint<'2>>`
...
66 |     result.push(closest);
   |     ^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`

How do I fix the above lifetime problem? I tried to annote fn spread_dots as below but I just run into a loop of ilfetime issues.

fn spread_dots<'b, 'a: 'b>(
    start: PathsPointIndex<'a, Polygons>,
    _end: PathsPointIndex<'a, Polygons>,
    result: &mut Vec<ClosestPolygonPoint<'b>>,
)```

You're trying to make Tower<'_> a self-referencial struct by storing references to the contents of the outer_polygon field in the start_locations field. Find some way to avoid that.

Probably you're overusing references more generally.

Sorry I don't have time to offer more concrete advice at this moment.

1 Like

Thanks, I didn't realise it is a self-referencial struct. I will try Rc for now.

OK, sounds like you understand the problem.

Just to show you how to fish I got to my response:

3 Likes

Why is '_ used here instead of 'a? Is it because the compiler can deduct it from the previous start?

No, the same as completely elided lifetimes, '_ introduces a new (unnamed) lifetime parameter. I just left it like that because the playground didn't need it (you never try to push something based on _end into result).

Probably you would have needed it to be 'a to fix another error if your playground was more complete. (Like so, perhaps.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.