Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert a Vec<T> into a C-friendly *mut T?

Tags:

rust

ffi

I have a Rust library that returns a u8 array to a C caller via FFI. The library also handles dropping the array after the client is done with it. The library has no state, so the client needs to own the array until it is passed back to the library for freeing.

Using box::from_raw and boxed::into_raw would be nice, but I couldn't manage to work out how to convert the array into the return type.

like image 468
urubi Avatar asked Feb 27 '15 05:02

urubi


1 Answers

A Vec<T> is described by 3 values:

  • A pointer to its first element, that can be obtained with .as_mut_ptr()
  • A length, that can be obtained with .len()
  • A capacity, that can be obtained with .capacity()

In terms of a C array, the capacity is the size of memory allocated, while the length is the number of elements actually contained in the array. Both are counting in number of T. You normally would need to provide these 3 values to your C code.

If you want them to be equals, you can use .shrink_to_fit() on the vector to reduce its capacity as near as its size as possible depending on the allocator.

If you give back the ownership of the Vec<T> to your C code, don't forget to call std::mem::forget(v) on it once you have retrieved the 3 values described before, to avoid having its destructor running at the end of the function.

Afterwards, you can create back a Vec from these 3 values using from_raw_parts(..) like this:

let v = unsafe { Vec::<T>::from_raw_parts(ptr, length, capacity) };

and when its destructor will run the memory will be correctly freed. Be careful, the 3 values need to be correct for deallocation of memory to be correct. It's not very important for a Vec<u8>, but the destructor of Vec will run the destructor of all data it contains according to its length.

like image 153
Levans Avatar answered Oct 08 '22 11:10

Levans