Writing adjacent planes

Using either the bytes crate or the builtin Vec<u8> is it possible to iterate over a stream of RGB pixels (one pass) and produce a single byte vector that contains all the red pixels, followed by all the green pixels, followed by all the blue pixels? I can't figure out how to do it without resorting to unsafe code, zeroing the vector, or allocating two extra vectors and copying from them at the end, which are all pretty bad. Something like this, but legal:

struct Rgb(u8, u8, u8);

let mut out = Vec::with_capacity(count*3);

for (i, Rgb(r, g, b)) in pixels.enumerate() {
    out[i] = r;
    out[count + i] = g;
    out[2*count + i] = b;
1 Like

I think this is a perfectly fine place to use unsafe { out.set_len(out.capacity()); }. The compiler isn't smart enough to verify that all the memory in the Vec will be written before it is read, but it is easy enough for the programmer to check. These are exactly the cases where unsafe blocks are necessary.


:slight_smile: Thanks, guess I'll just stick with that then. Hopefully in the future the compiler gets smarter, but after trying Idris I feel like that probably won't happen without adding a lot of complexity.

If you don't need all 3 in the same vector, I wrote unzip3.

let (r_vec, g_vec, b_vec) = pixels.iter().map(|&Rgb(r, g, b)| (r,g,b)).unzip3();

Thanks, but the adjacency is sort of the whole point.