I'm writing a c-binding to a Rust function. The Rust function takes a 3D slice where 2 dimensions are of size two. Essentially it's a slice of 2D line segments where a line segment is represented by 2 points.
This means the segments have type:
segments: [[[f32; 2]; 2]]
Now since I call this from C I only have a simple f32
pointer at the FFI boundary. My multi-dimensional array from c is in row-major memory order which I understand matches what Rust would expect. So morally I should be able to say to rust: It's just that type.
I have looked at https://doc.rust-lang.org/std/ptr/fn.slice_from_raw_parts.html but I don't see how I can handle a more complex structure with that.
So to make it very concrete I want to be able to call foo
from foo_c
and foo
should handle the conversion from pointer to the 3D slice/array structure.
#[no_mangle]
pub unsafe extern fn foo_c(segments: *f32, n_segments: usize) {
foo(...)
}
fn foo(segments: [[[f32; 2]; 2]]) {
...
}
If possible I would like to do this without copying any data around.
Any help is appreciated!
CodePudding user response:
First I think you made some typos, so I'm assuming your code is:
#[no_mangle]
// missing `const`
pub unsafe extern fn foo_c(segments: *const f32, n_segments: usize) {
foo(...)
}
// missing `&`
fn foo(segments: &[[[f32; 2]; 2]]) {
...
}
The solution is:
#[no_mangle]
pub unsafe extern fn foo_c(segments: *const f32,n_segments: usize) {
// first we cast the pointer to get the slice `T`
// so from a generic `*const f32` to `*const T` where T is `[[f32; 2]; 2]`
let ptr = segments as *const [[f32; 2]; 2];
// we construct the slice using `slice_from_raw_parts`
// after we got the correct pointer.
let segments_slice = std::ptr::slice_from_raw_parts::<[[f32;2];2]>(ptr,n_segments);
// we still have `*const [[f32; 2]; 2]` which we need to convert
// to `&[[f32; 2]; 2]` so we use `&*` (dereference then borrow).
foo(&*segments_slice)
}
fn foo(segments: &[[[f32; 2]; 2]]) {
println!("segments {:?}",segments);
}