将数组从 Rust 返回到 FFI
Returning array from Rust to FFI
我需要在 Rust 中编写一个 returns u16 整数数组的函数。然后这个函数应该被FFI使用。
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *const uint16_t {
let test: [u16;4] = [1,2,3,4];
test.as_ptr()
}
Rust 代码编译没有错误。我使用 Ruby 来测试 ffi 调用:
# coding: utf-8
require 'ffi'
module MyMod
extend FFI::Library
ffi_lib 'my_ffi_test_lib'
attach_function :ffi_test, [], :pointer
end
a_ptr = MyMod.ffi_test
size = 4
result_array = a_ptr.read_array_of_uint16(size)
p result_array
但结果完全错误(预期:[1, 2, 3, 4]
):
$ ruby ffi_test.rb
[57871, 25191, 32767, 0]
好像我正在读取完全不同的内存地址。我想也许我不应该在 Rust 数组上使用 #as_ptr()
?
编辑
根据@FrenchBoiethios 的建议,我尝试将数组装箱:
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *mut uint16_t {
let test: [u16;4] = [1,2,3,4];
let b = Box::new(test);
Box::into_raw(b)
}
这给出了编译错误:
note: expected type `std::boxed::Box<u16>`
found type `std::boxed::Box<[u16; 4]>`
你的数组在堆栈上,所以当你 returns 它作为指针(返回的指向局部变量的指针)时存在生命周期问题。您必须在堆中分配它:
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let mut test = vec![1, 2, 3, 4];
let ptr = test.as_mut_ptr();
std::mem::forget(test); // so that it is not destructed at the end of the scope
ptr
}
或
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let test = Box::new([1u16, 2, 3, 4]); // type must be explicit here...
Box::into_raw(test) as *mut _ // ... because this cast can convert
// *mut [i32; 4] to *mut u16
}
我正在尝试学习 Rust ffi,这些实现是来自互联网上不同来源的科学怪人创作。因此,请对它持保留态度。
目前我有两种方法:
a) 从 rust GC 和 return 点中移除数组。用户需要承诺以后免费拨打。
#[repr(C)]
pub struct V2 {
pub x: i32,
pub y: i32,
}
#[repr(C)]
struct Buffer {
len: i32,
data: *mut V2,
}
#[no_mangle]
extern "C" fn generate_data() -> Buffer {
let mut buf = vec![V2 { x: 1, y: 0 }, V2 { x: 2, y: 0}].into_boxed_slice();
let data = buf.as_mut_ptr();
let len = buf.len() as i32;
std::mem::forget(buf);
Buffer { len, data }
}
#[no_mangle]
extern "C" fn free_buf(buf: Buffer) {
let s = unsafe { std::slice::from_raw_parts_mut(buf.data, buf.len as usize) };
let s = s.as_mut_ptr();
unsafe {
Box::from_raw(s);
}
}
b) 通过FFI回调函数发送数组。用户需要承诺不保留引用,但不需要免费拨打。
#[no_mangle]
pub extern "C" fn context_get_byte_responses(callback: extern "stdcall" fn (*mut u8, i32)) -> bool {
let bytes: Vec<u8> = vec![];
callback(bytes.as_mut_ptr(), bytes.len() as i32);
true
}
我需要在 Rust 中编写一个 returns u16 整数数组的函数。然后这个函数应该被FFI使用。
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *const uint16_t {
let test: [u16;4] = [1,2,3,4];
test.as_ptr()
}
Rust 代码编译没有错误。我使用 Ruby 来测试 ffi 调用:
# coding: utf-8
require 'ffi'
module MyMod
extend FFI::Library
ffi_lib 'my_ffi_test_lib'
attach_function :ffi_test, [], :pointer
end
a_ptr = MyMod.ffi_test
size = 4
result_array = a_ptr.read_array_of_uint16(size)
p result_array
但结果完全错误(预期:[1, 2, 3, 4]
):
$ ruby ffi_test.rb
[57871, 25191, 32767, 0]
好像我正在读取完全不同的内存地址。我想也许我不应该在 Rust 数组上使用 #as_ptr()
?
编辑
根据@FrenchBoiethios 的建议,我尝试将数组装箱:
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *mut uint16_t {
let test: [u16;4] = [1,2,3,4];
let b = Box::new(test);
Box::into_raw(b)
}
这给出了编译错误:
note: expected type `std::boxed::Box<u16>`
found type `std::boxed::Box<[u16; 4]>`
你的数组在堆栈上,所以当你 returns 它作为指针(返回的指向局部变量的指针)时存在生命周期问题。您必须在堆中分配它:
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let mut test = vec![1, 2, 3, 4];
let ptr = test.as_mut_ptr();
std::mem::forget(test); // so that it is not destructed at the end of the scope
ptr
}
或
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let test = Box::new([1u16, 2, 3, 4]); // type must be explicit here...
Box::into_raw(test) as *mut _ // ... because this cast can convert
// *mut [i32; 4] to *mut u16
}
我正在尝试学习 Rust ffi,这些实现是来自互联网上不同来源的科学怪人创作。因此,请对它持保留态度。
目前我有两种方法:
a) 从 rust GC 和 return 点中移除数组。用户需要承诺以后免费拨打。
#[repr(C)]
pub struct V2 {
pub x: i32,
pub y: i32,
}
#[repr(C)]
struct Buffer {
len: i32,
data: *mut V2,
}
#[no_mangle]
extern "C" fn generate_data() -> Buffer {
let mut buf = vec![V2 { x: 1, y: 0 }, V2 { x: 2, y: 0}].into_boxed_slice();
let data = buf.as_mut_ptr();
let len = buf.len() as i32;
std::mem::forget(buf);
Buffer { len, data }
}
#[no_mangle]
extern "C" fn free_buf(buf: Buffer) {
let s = unsafe { std::slice::from_raw_parts_mut(buf.data, buf.len as usize) };
let s = s.as_mut_ptr();
unsafe {
Box::from_raw(s);
}
}
b) 通过FFI回调函数发送数组。用户需要承诺不保留引用,但不需要免费拨打。
#[no_mangle]
pub extern "C" fn context_get_byte_responses(callback: extern "stdcall" fn (*mut u8, i32)) -> bool {
let bytes: Vec<u8> = vec![];
callback(bytes.as_mut_ptr(), bytes.len() as i32);
true
}