How to return Rust Vec of unknown size over FFI?

Issue

This Content is from Stack Overflow. Question asked by mwlon

I have a Rust library that returns Vecs of size that cannot be predicted by the caller, and I’m wondering if I can find an elegant way to do implement the FFI interface.
Since Vecs can’t be passed over FFI, I understand I need to first return the length, and then fill a buffer with the contents.

Here’s my current solution, which works by manually managing memory of the Vec and trusting the caller to

  1. Compute the FfiVec
  2. Create a buffer of appropriate size to copy into
  3. Copy from the FfiVec, cleaning it up in the process
#[repr(C)]
pub struct FfiVec<T: Sized> {
  ptr: *mut Vec<T>,
  len: c_uint, // necessary for C process to know length of Rust Vec
}

impl<T: Sized> FfiVec<T> {
  pub fn from_vec(v: Vec<T>) -> Self {
    let len = v.len() as c_uint;
    FfiVec {
      ptr: Box::into_raw(Box::new(v)),
      len,
    }
  }

  pub fn drop(self) {
    unsafe {
      std::ptr::drop_in_place(self.ptr);
      std::alloc::dealloc(self.ptr as *mut u8, Layout::new::<Vec<T>>())
    }
  }
}

#[no_mangle]
pub extern compute_my_vec() -> FfiVec<u8> {...}

#[no_mangle]
pub extern copy_from_my_vec(ffi_vec: FfiVec<u8>, buffer: *mut u8) -> {
  let len = c_vec.len as usize;
  let buffer_slice = unsafe { std::slice::from_raw_parts_mut(buffer, len) };
  for (i, &item) in c_vec.slice().iter().take(len).enumerate() {
    buffer_slice[i] = item;
  }
  c_vec.drop()
}

Is there a simpler way to do this? Or a common library that can do this for me?



Solution

This question is not yet answered, be the first one who answer using the comment. Later the confirmed answer will be published as the solution.

This Question and Answer are collected from stackoverflow and tested by JTuto community, is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?