I have a custom iterator which reads data from a reference to a Vec in a non-contiguous manner. It will never return two references to the same memory, so I believe it is safe to implement a mutable counterpart.
However, the logic for the iterator itself is quite complex, and it would be entirely identical for the mutable version. In an attempt to avoid code duplication, I use my non-mut iterator under the hood, and then cast the result to add mutability. This works as expected, but I am unsure if it's invoking some kind of undefined behavior.
pub mod lib {
pub struct Data {
pub v: Vec<u64>,
}
impl Data {
pub fn iter(&self) -> MyIter {
MyIter {
data: &self.v,
i: 0,
}
}
pub fn iter_mut(&mut self) -> MyIterMut {
MyIterMut { iter: self.iter() }
}
}
pub struct MyIter<'a> {
data: &'a [u64],
i: usize,
}
impl<'a> Iterator for MyIter<'a> {
type Item = &'a u64;
fn next(&mut self) -> Option<Self::Item> {
if self.i == self.data.len() {
return None;
}
let res = &self.data[self.i];
self.i += 1;
Some(res)
}
}
pub struct MyIterMut<'a> {
iter: MyIter<'a>,
}
impl<'a> Iterator for MyIterMut<'a> {
type Item = &'a mut u64;
fn next(&mut self) -> Option<Self::Item> {
unsafe { std::mem::transmute(self.iter.next()) }
}
}
}
fn main() {
let mut d = lib::Data { v: vec![0; 8] };
for elem in d.iter_mut() {
*elem = 123;
}
println!("{:?}", d.v);
}
The mutable iterator is only constructed in the iter_mut method. This means the initial value will always start as a mutable variable, due to the &mut self. It wouldn't be possible to construct this mutable iterator from an immutable variable.
In C++, often times you will use a const_cast to avoid duplicating an implementation that only varies in constness.
Is this something I can do in Rust?
MyIterMut<'a>as owning aMyIter<'a>. Does theMyIter<'a>own theVecor only hold a reference to it? I'm assuming it holds a reference (based on the presence of the lifetime parameter). If that's the case then you face undefined behavior when another part of the code thinks it's getting an immutable reference to an element while code using your mutable iterator is changing it.iter_mut()method, meaning there is already a&mut self. Essentially, I am casting frommut, to immutable, tomutagain. But as the initial one is mutable, I believe it's safe? Not sure.