How do I reset the length of a slice when using transmute

I found that if I force convert a slice to a different type of slice, the length will keep the same, for example:

#[repr(C)]
struct Vertex {
    position: [f32; 3],
    normal: [f32; 3],
    texture: [f32; 2],
}

fn main() {
    let raw_data: &[f32] = &[0.0; 32]; // it's actually 4 vertices
    println!("{}", raw_data.len());

    let vertices: &[Vertex] = unsafe {std::mem::transmute(raw_data)};
    println!("{}", vertices.len());
}

Let's say the data aligned perfectly, how could I transmute vertices to &[Vertex], wihich length is 4, not 32?

I am not sure how to do it - but I can tell why it doesn't work this way. Slices in Rust are represented by what is known as wide pointers - pointers with twice the width as a regular one. The first 8 bytes (for a 64 bit machine) contains the pointer to the data, while the second contains the length of the slice. When you call transmute all that happens is that the "type" is forcibly changed, without touching the actual bits. So, the pointer to a f32 slice becomes a pointer to Vertex slice, while the length "field" is untouched.

So as far as I can tell, transmuting a slice will not work the way you want it to. You could try transmuting an array.

1 Like

You can use bytemuck.

Playground.

If you don't want that dependency or the bounds it requires, see how they implement it. In addition to handling the size difference like @RedDocMD mentioned, there is no guarantee that the wide pointer order is (data, length), or that the order of two different wide pointers is the same. Thus the use of from_raw_parts, len, size_of_val, etc. They also take care around zero-sized types, alignment, etc.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.