web-dev-qa-db-ja.com

Rust `Vec <T>`をFFIに公開する方法は?

私は要素のペアを構築しようとしています:

  • array: *mut T
  • array_len: usize

arrayはデータを所有することを目的としています

ただし、 Box::into_raw*mut [T]を返します。生のポインタをスライスに変換するための情報が見つかりません。メモリ内のレイアウトは何ですか? Cからどのように使用しますか? *mut Tに変換する必要がありますか?もしそうなら、どのように?

17
vinipsmaker

C関数でVecを可変的に借用したいだけの場合は、次のように実行できます。

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);
    }
}

もちろん、エイリアシングの仮定を破る可能性があるため、C関数はこのポインタを別の場所に格納しないでください。

データの「所有権をCコードに渡す」場合は、次のようにします。

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);
    }
}

ここで、C関数は、たとえばRust関数を呼び出して割り当てを解除することにより、最終的にポインターと長さをRustに返すことを期待するという意味で「所有権を取得」します。

#[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));
}

Vec::from_raw_partsは、ポインター、サイズ、容量の3つのパラメーターを想定しているため、何らかの方法で容量も追跡するか、ポインターと長さをCに渡す前にVecのshrink_to_fitを使用する必要があります。関数。ただし、これには再割り当てが含まれる場合があります。

16
sellibitze

[T]::as_mut_ptr を使用して、*mut TVec<T>、またはその他のDerefMut-to-sliceタイプから直接Box<[T]>ポインタを取得できます。

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);
9
kennytm