1

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!

1 Answer 1

3

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);
}
Sign up to request clarification or add additional context in comments.

4 Comments

Prefer .cast() to as, and std::slice::from_raw_parts() to std::ptr::slice_from_raw_parts().
@chayimfriedman, prefer core::slice::from_raw_parts to std::slice::from_raw_parts :)
@Miiao Only when in #![no_std] mode.
Other than the question of the exact function calls to use (which btw, how is a relative newcomer supposed to know the virtues of each?), would this example be substantially different if one wanted the resulting reference to be mutable, so you could update said array from rust?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.