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...
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:
&mut [f32]
has more information than just the address of the f32
data — more information than C stores.&mut [T]
then there must be some location in memory where T
s are stored adjacent to each other.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:
Vec<&mut [f32]>
with the appropriate lengths for each inner slice, and return that.[&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 &mut
s.