How to expose a Rust `Vec` to FFI?

后端 未结 2 1332
不知归路
不知归路 2020-12-15 18:21

I\'m trying to construct a pair of elements:

  • array: *mut T
  • array_len: usize

array is intended to

相关标签:
2条回答
  • 2020-12-15 18:34

    If you just want some C function to mutably borrow the Vec, you can do it like this:

    extern "C" {
        fn some_c_function(ptr: *mut i32, len: ffi::size_t);
    }
    
    fn safe_wrapper(a: &mut [i32]) {
        unsafe {
            some_c_function(a.as_mut_ptr(), a.len() as ffi::size_t);
        }
    }
    

    Of course, the C function shouldn't store this pointer somewhere else because that would break aliasing assumptions.

    If you want to "pass ownership" of the data to C code, you'd do something like this:

    use std::mem;
    
    extern "C" {
        fn c_sink(ptr: *mut i32, len: ffi::size_t);
    }
    
    fn sink_wrapper(mut vec: Vec<i32>) {
        vec.shrink_to_fit();
        assert!(vec.len() == vec.capacity());
        let ptr = vec.as_mut_ptr();
        let len = vec.len();
        mem::forget(vec); // prevent deallocation in Rust
                          // The array is still there but no Rust object
                          // feels responsible. We only have ptr/len now
                          // to reach it.
        unsafe {
            c_sink(ptr, len as ffi::size_t);
        }
    }
    

    Here, the C function "takes ownership" in the sense that we expect it to eventually return the pointer and length to Rust, for example, by calling a Rust function to deallocate it:

    #[no_mangle]
    /// This is intended for the C code to call for deallocating the
    /// Rust-allocated i32 array.
    unsafe extern "C" fn deallocate_rust_buffer(ptr: *mut i32, len: ffi::size_t) {
        let len = len as usize;
        drop(Vec::from_raw_parts(ptr, len, len));
    }
    

    Because Vec::from_raw_parts expects three parameters, a pointer, a size and a capacity, we either have to keep track of the capacity as well somehow, or we use Vec's shrink_to_fit before passing the pointer and length to the C function. This might involve a reallocation, though.

    0 讨论(0)
  • 2020-12-15 18:54

    You could use [T]::as_mut_ptr to obtain the *mut T pointer directly from Vec<T>, Box<[T]> or any other DerefMut-to-slice types.

    use std::mem;
    
    let mut boxed_slice: Box<[T]> = vector.into_boxed_slice();
    
    let array: *mut T = boxed_slice.as_mut_ptr();
    let array_len: usize = boxed_slice.len();
    
    // Prevent the slice from being destroyed (Leak the memory).
    mem::forget(boxed_slice);
    
    0 讨论(0)
提交回复
热议问题