rustsliceffi

How does one convert a C pointer-to-pointer to a Rust slice of slices?


Say I have a C float**, which I index in C like float[x][y]. Is it possible to pass that float** to Rust and convert it to an &mut [&mut [f32]] so I can handle it more "rustily" within Rust?

It wasn't too complicated to convert an one-dimensional array pointer using std::slice::from_raw_parts_mut, but I'm completely stumped on how to do the same with a two-dimensional array pointer without angering the borrow checker or incurring unnecessary allocations...


Solution

  • The most you can possibly do by just converting the pointer itself is &mut [*mut f32]. This is because of two facts about the Rust types involved:

    What you get from C is described in Rust syntax as *mut *mut f32. This pointer points to a contiguous sequence of just addresses (pointers) — no lengths. Therefore, you do not have a [*mut [f32]], which would have both addresses and lengths; only an [*mut f32], with addresses only. Since you don't have an [*mut [f32]] anywhere, you definitely can't construct an &mut [*mut [f32]].

    You have two choices:

    1. Perform the allocation you didn't want to do — build a Vec<&mut [f32]> with the appropriate lengths for each inner slice, and return that.
    2. Instead of trying to produce an [&mut [f32]] of any sort, write a custom wrapper type around the pointer, with a method or std::ops::IndexMut implementation that produces &mut [f32]s on demand. Or, write an iterator which returns &mut [f32], if you only need sequential rather than random access.

    The good news is, option 2 is perfectly good idiomatic Rust! Even in pure Rust code with no FFI involved, you shouldn't use &mut [&mut [f32]], because it almost always demands a temporary allocation to hold the inner &muts.