Getting an array out of chunks_exact

Hello,

I'm trying to extract a list of 3D vectors out of a a float buffer. Ideally, I'd like to write something like this:

use nalgebra_glm as glm;

// buf: Vec<f32>

let verts = buf.chunks_exact(3)
    .map(|&[x, y, z]| glm::vec3(x, y, z))
    .collect::<Vec<_>>()

I understand that the compiler cannot ensure the size of the slice returned by the ChunksExact iterator:

.map(|&[x, y, z]| glm::vec3(x, y, z))
      ^^^^^^^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered

I can get away by doing so:

let verts = buf.chunks_exact(3)
    .map(|chunk| {
        let x = unsafe { *chunk.get_unchecked(0) };
        let y = unsafe { *chunk.get_unchecked(1) };
        let z = unsafe { *chunk.get_unchecked(2) };

        glm::vec3(x, y, z)
    })
    .collect::<Vec<_>>()

but it feels a bit overwhelming to write and will be even worse when I'll do the same for a 4x4 matrix.

Is there a (unsafe) way to "cast" a &[T] to a &[T; 3] ?

Ok I've foud a solution right after posting this...

let &[x, y, z] = unsafe{ &*(chunk.as_ptr() as *const [_; 3]) };

even better, in the case of nalgebra-glm, it has a make_vec3 function:

data.chunks_exact(3)
    .map(glm::make_vec3)
    .collect()

No please don't use any unsafe. It seems totally safe Rust can produce even less opcodes than your unsafe version, though the output asm is not trivial so I can't sure anything before benchmark.

1 Like

this line seems pretty neat into asm code

let &[x, y, z] = unsafe{ &*(chunk.as_ptr() as *const [_; 3]) };
  mov esi, dword ptr [edx]
  mov edi, dword ptr [edx + 4]
  mov ebx, dword ptr [edx + 8]

Yes but using unsafe for something like this is not warranted. If you still need the manual conversion, you could perform it even more simply, as [T: Copy; N] implements TryFrom<&[T]>:

let verts = buf.chunks_exact(3)
    .map(|slice| {
        let [x, y, z] = <[_; 3]>::try_from(slice).expect("3 items");
        glm::vec3(x, y, z)
    })
    .collect::<Vec<_>>();

Ok, now your unsafe code can produce identical machine code with the totally safe Rust.

I thought the panic possibility would add much more code, I'm gonna stick to the glm::make_vec3 for this particular case.
I'm gonna go for try_from / try_into whenever I need it.

Thanks!

Optimizing compilers are amazing, aren't they?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.