How to flatten a Vec<MyStruct> to Vec<T>?

I have a Point3D struct that I have implemented

pub struct Point3D<T> {
    pub x: T,
    pub y: T,
    pub z: T
}

In the course of my program I have to flatten this into a Vec and use the data in this format. What would be the most efficient/idiomatic way to do this? I have seen the From and Into traits and the idea of doing something like

Vec<Point3D<f32>> my_vec;
fn use_vector_of_points(in_data: Vec<f32>);
use_vector_of_points(my_vec.into());

If this is the best way, how would I implement the necessary traits to do this, if this is not the best way to do this, then how ought I do do this?

Rust has in-progress project to add safe API for this: https://github.com/rust-lang/project-safe-transmute

For now you will have to juggle pointers:

https://doc.rust-lang.org/std/vec/struct.Vec.html#examples-4

If you want to only view it temporarily as [T], that's less unsafe with .as_ptr().cast() + slice::from_raw_parts()

1 Like

You can also do this with iterators, and hope that the optimizer will do the right thing:

fn main() {
    let points: Vec<Point3D<u32>>=vec![
        Point3D { x: 1, y: 2, z: 3 },
        Point3D { x: 4, y: 5, z: 6 },
    ];

    let ints: Vec<u32> = points.into_iter().flat_map(
        |p| once(p.x).chain(once(p.y)).chain(once(p.z))
    ).collect();
    
    println!("{:?}", ints);
}

(Playground)

You also need to mark your struct as #[repr(C)] if you use any of the "transmute" or raw pointer methods to do this. Otherwise, the order of the fields in memory is not guaranteed.

2 Likes