If you don't need vecs, the other correct way to do this would be to write a wrapper which dereferences into a slice. Something like
struct GrbVec { ... }
impl Deref for GrbVec {
type Target = [f64];
fn deref(&self) -> &[f64] {
// code to construct a reference to the malloced memory
}
}
impl Drop for GrbVec {
fn drop(&mut self) {
// call the proper C api to deallocate memory
}
}
See also the nomicon chapter on FFI, if you haven't already read it: FFI - The Rustonomicon
let mut I = Vec::<GrB_Index>::with_capacity(nvals);
let mut X = Vec::<f64>::with_capacity(nvals);
unsafe {
GrB_Vector_extractTuples_FP64(
I.as_mut_ptr(),
X.as_mut_ptr(),
&mut nvals,
GrB_Vector /* ... */,
);
/* Check that the result code is OK (skipped here) */
I.set_len(nvals);
X.set_len(nvals);
}