Search code examples
rustreferenceslicevec

Zero-copy reference a slice of bytes by a step


I have a large Vec<u8> representing the raw pixel values of a gray image. Since the pixel format is actually 16-bit width, two u8 makes one pixel.

Now I'd like to use the image as if it was 8-bit width, so I only take the higher 8-bit part of a pixel.

As an instance, given a raw vec v = vec![0,1,2,3,4,5], how can I view it by a step 2 to a reference view : &[u8] (without the need to copy them into a new Vec, for performance), such that view can be used equivalent to &[0,2,4]. Thanks very much.


Solution

  • The exact thing you're asking for is impossible, because slices are, by definition, continuous chunks of memory. To have an &[0u8, 2, 4], you need to have something equivalent to [0u8, 2, 4], i.e. these exact three bytes positioned directly next to each other.

    The thing you're conceptually asking for looks like a stride, that is, something which yields a sequence of elements while skipping some of them. This can be relatively easily done with iterators, for example, like this:

    fn only_first_byte_from_pair<'a>(data: &'a [u8]) -> impl Iterator<Item = u8> + 'a {
        return data.chunks(2).map(|chunk| chunk[0])
    }
    

    Alternatively, you can have a look on ndarray, which has the relevant functionality out of the box, but could be a bit too complex for the actual task.