How to convert a Vec of Point2f into a mutable slice of f32?

Maybe this is trivial, but right now I would not know how to do this:

``````#[derive(Debug)]
struct Point2f {
x: f32,
y: f32,
}

fn some_fn(to_swap: &mut [f32]) {
to_swap.swap(0_usize, 3_usize);
}

fn main() {
let mut swap_me: Vec<Point2f> = Vec::new();
swap_me.push(Point2f { x: 0.0, y: 1.0 });
swap_me.push(Point2f { x: 2.0, y: 3.0 });
println!("replace");
println!("{:?}", swap_me[0]);
println!("{:?}", swap_me[1]);
// some_fn(&mut swap_me[..]);
let tmp = swap_me[0].x;
swap_me[0].x = swap_me[1].y;
swap_me[1].y = tmp;
// replace three lines above through function call
assert!(swap_me[0].x == 3.0);
assert!(swap_me[1].y == 0.0);
println!("by");
println!("{:?}", swap_me[0]);
println!("{:?}", swap_me[1]);
}
``````

Can this be done via `From` and `Into`?

An inefficient way could be to iterate over the `Vec` and collect the into a flat `Vec<f32>` which you can then slice. (Experienced FMs may provide more efficient alternatives.)

``````let flat_arr: Vec<f32> = swap_me.iter().map(|p| vec![p.x, p.y]).flatten().collect();
// You can use &flat_arr or slice it as needed
``````

However, if you wish to limit to just swapping the `Point2f` types then you could operate on `&mut [Point2f]` slice directly:

``````#[derive(Debug)]
struct Point2f {
x: f32,
y: f32,
}

trait SwapXY {
fn swap_xy(&mut self, x_idx: usize, y_idx: usize);
}

impl SwapXY for &mut [Point2f] {
fn swap_xy(&mut self, x_idx: usize, y_idx: usize) {
let tmp = self[x_idx].x;
self[x_idx].x = self[y_idx].y;
self[y_idx].y = tmp;
}
}

fn main() {
let mut swap_me: Vec<Point2f> = Vec::new();
swap_me.push(Point2f { x: 0.0, y: 1.0 });
swap_me.push(Point2f { x: 2.0, y: 3.0 });

println!("Before: {:?}", swap_me);

let mut swap_me_slice = &mut swap_me[..];
swap_me_slice.swap_xy(0, 1);

println!("After: {:?}", swap_me);

}
``````
1 Like

Hi @osrust, thanks for your answer. I solved my particular problem in a similar way (operating on `&mut [Point2f]` directly):

https://www.janwalter.org/doc/rust/src/pbrt/core/sampling.rs.html#275-308

But this works here only because the C++ counterpart was actually using that function only once:

``````> rg -tcpp LatinHypercube
samplers/stratified.cpp
68:            LatinHypercube(&sampleArray2D[i][j * count].x, count, 2, rng);

core/sampling.h
54:void LatinHypercube(Float *samples, int nSamples, int nDim, RNG &rng);

core/sampling.cpp
62:void LatinHypercube(Float *samples, int nSamples, int nDim, RNG &rng) {
``````

I was just wondering if there is another way, because from what I have read so far the memory layout of a vector would be an owning pointer, followed by two `usize` values for the capacity and length of the `Vec` (on the stack), whereas the reference to the (mutable) slice should be a pointer (on the stack) into the same memory block (on the heap) with an additional size value (on the stack). The `Point2f` values would be (on the heap) just twice as many `f32` values. Swapping any of the valid `f32` values should be easy (and efficient), as long as you know how to index into them (and what that index really means, e.g. x- or y-coordinate). Anyway, problem solved, but maybe someone has another idea how to deal with such a situation...

I think this will work:

``````slice::from_raw_parts_mut(
vec.as_mut_ptr().cast::<f32>(),
vec.len() * 2,
)
``````

But you should also tag your struct `#[repr(C)]`, or else the layout (including field order) is not guaranteed to be predictable.

5 Likes

Yup, that's the right solution. I'd recommend moving that code to a function that takes `&mut Vec` and returns the slice, so that the lifetime of the Vec is still bound to lifetime of the returned slice. If that code is pasted somewhere in the middle of a larger function, the borrow checker won't know the Vec and the slice are related, and could allow incorrect use of the Vec or slice.

5 Likes

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