I have an iterator that reads a [u8] slice one value at a time. Every time it returns Some it moves forward in the slice. It never goes backwards or reads the same value twice.
At the same time as using this iterator, I want to be able to write to a value as soon as it has done reading that value. I'm not sure how to do this safely. Any ideas?
A silly example:
// Removes vowels in place using an iterator. Returns the new sub-slice.
// Can I do this safely?
fn remove_vowels_unsafe(ascii: &mut [u8]) -> &mut [u8] {
let mut length = 0;
// unsafe?
unsafe {
let ptr = ascii.as_mut_ptr(); // subvert Rust's rules
for chr in no_vowels_filter(ascii.iter().copied()).take(ascii.len()) {
*ptr.add(length) = chr;
length += 1;
}
}
&mut ascii[0..length]
}
I believe that what you are doing is actually sound, but this relies on an implementation detail of slice::iter, namely that the slice iterator is implemented using raw pointers, and that you only modify values after the iterator has read them.
However, in your case you can just use safe code:
use std::cell::Cell;
// Removes vowels in place and returns the new sub-slice.
fn remove_vowels_unsafe(ascii: &mut [u8]) -> &mut [u8] {
let mut length = 0;
{
let ascii = Cell::from_mut(ascii).as_slice_of_cells();
for chr in no_vowels_filter(ascii.iter().map(|i| i.get())).take(ascii.len()) {
ascii[length].set(chr);
length += 1;
}
}
&mut ascii[0..length]
}