0

I'm operating f32 array that represents multiple drawable elements (like SVG paths). Each drawable can indicate how many elements in the array it takes up, and then each drawable occurs immediately after the previous.

I want to mutate parts of the array whilst iterating over it. I did this as a while loop, which worked. But I wanted to clean it up and make an iterator for this, which makes the borrow checker complain

fn translate_original(renderables: &mut Vec<f32>, tx: f32, ty: f32) {
    // This works
    let mut i = 0;
    while i < renderables.len() {
        translate_renderable(renderables, i, tx, ty);
        i = next_renderable(renderables, i);
    }
}

fn translate_iterator(renderables: &mut Vec<f32>, tx: f32, ty: f32) {
    // This fails
    RenderableIterator::new(renderables)
        .for_each(|i| translate_renderable(renderables, i, tx, ty));
}

fn main() {
    let mut data_1: Vec<f32> = vec![
        // renderable 1
        2., 10., 10., 20., 20.,
        // renderable 2
        3., 30., 30., 40., 40., 50., 50.
    ];
    let mut data_2 = data_1.clone();
    translate_original(&mut data_1, 5., 5.);
    translate_iterator(&mut data_2, 5., 5.);
}

// Set up
fn next_renderable(renderables: &Vec<f32>, i: usize) -> usize {
    i + 1 + (renderables[i] as usize)
}

fn translate_renderable(renderables: &mut Vec<f32>, i: usize, tx: f32, ty: f32) {
    let from = i + 1;
    let to = next_renderable(renderables, i);
    for i in (from..to).step_by(2) {
        renderables[i] += tx;
        renderables[i + 1] += ty;
    }
}

pub struct RenderableIterator<'a> {
    renderables: &'a Vec<f32>,
    i: usize,
}

impl RenderableIterator<'_> {
    pub fn new(renderables: &Vec<f32>) -> RenderableIterator {
        RenderableIterator { renderables, i: 0 }
    }
}

impl Iterator for RenderableIterator<'_> {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        if self.i < self.renderables.len() {
            let out = Some(self.i);
            self.i = next_renderable(&self.renderables, self.i);
            out
        } else {
            None
        }
    }
}

I sort of understand why it's complaining - but to me it doesn't look any less safe than the while loop version. Is there a way to get the iterator version to work?

Edit: Playground link, as requested

  • Can you try to create a [mcve]? E.g. what is `RenderableIterator`, what is `renderables`, `stacking_order`, `translate` and so on? Please go to [the playground](https://play.rust-lang.org) and try to create a example that reproduces your problem. Then copy and paste the code into your question (after hitting `rustfmt` in the upper right corner) by [edit]ing your question. – hellow Aug 06 '19 at 07:53
  • Added a link to the playgroud – fdasfdsafsdaf Aug 06 '19 at 08:25
  • Please read: https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-to-a-string-string-vec-vec-or – hellow Aug 06 '19 at 08:32
  • @hellow That looks like a good idea - I'll look into it! Thanks (but my issue is still there) – fdasfdsafsdaf Aug 06 '19 at 09:06
  • Iterators are really not convenient for this kind of thing. I don't think you'll be able to be more concise than your original code, which seems perfectly fine. – Peter Hall Aug 06 '19 at 22:01

0 Answers0