6

This question is related, however it moreso covers the reason why the compiler cannot infer a safe lifetime when returning a mutable reference from Iterator::next, which I think I understand.

My question is:

What are the specific steps you can take when designing your own iterator so that it can produce mutable references? Ultimately, I'm hoping for a concise-as-possible, step-by-step, commented example of both an Iterator and its next implementation that I (and anyone) can go to as a clear reference when they run into this situation. unsafe examples are fine, I imagine they are probably necessary!

NOTE: I understand that MutItems is normally the recommended example, however its implementation can be difficult to follow as there isn't any documentation on 1. How the markers work in that situation and 2. What the iterator! macro expands to and how it works. If you use MutItems as your example could you please clarify these things?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
mindTree
  • 916
  • 9
  • 18
  • 1
    The `iterator` macro is just a little earlier in the file: http://doc.rust-lang.org/src/core/home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libcore/slice.rs.html#1042-1105 – Chris Morgan Nov 25 '14 at 04:23

1 Answers1

10

Here's a way of having a mutable iterator over a hypothetical Point struct. I find it very useful to annotate every unsafe block in a similar fashion, since I'm only shooting myself in the foot if I get it wrong!

The Rust compiler does not know that you will get a different mutable reference every time you advance the iterator. This unsafe block is safe because the programmer guarantees that this iterator can never return the same mutable reference twice, or allow any other way to get to the same address.

#[derive(Debug)]
struct Point {
    x: u8,
    y: u8,
    z: u8,
}

impl Point {
    fn iter_mut(&mut self) -> IterMut {
        IterMut {
            point: self,
            idx: 0,
        }
    }
}

struct IterMut<'a> {
    point: &'a mut Point,
    idx: u8,
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut u8;

    fn next(&mut self) -> Option<&'a mut u8> {
        let retval = match self.idx {
            0 => &mut self.point.x,
            1 => &mut self.point.y,
            2 => &mut self.point.z,
            _ => return None,
        };

        self.idx += 1;

        // I copied this code from Stack Overflow without paying attention to
        // the prose which described why this code is actually safe.
        unsafe { Some(&mut *(retval as *mut u8)) }
    }
}

fn main() {
    let mut p1 = Point { x: 1, y: 2, z: 3 };

    for x in p1.iter_mut() {
        *x += 1;
    }

    println!("{:?}", p1);
}

See also

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    Thanks! I ended up doing exactly this in my own use-case. For anyone unsure of what `transmute` does, here's the summary of its behaviour [from the docs](http://doc.rust-lang.org/std/mem/fn.transmute.html), "Unsafely transforms a value of one type into a value of another type." In this situation transmute infers the correct return type while assuring the borrow checker that the mutable borrow is safe. – mindTree Dec 26 '14 at 06:58