PHP FFI - return 数组 rom Rust 函数返回 PHP
PHP FFI - return array rom Rust function back to PHP
我需要 return 来自 rust 函数的几个值。试图声明 return 数组
的函数
$ffi = FFI::cdef('float get_arr()[2];', './target/release/libphp_rust.dylib');
$array = $ffi->get_arr();
但是出现错误:
PHP Fatal error: Uncaught FFI\ParserException: function returning array is not allowed at line 1 in /array.php:3
似乎PHP FFI 不能直接使用数组。所以我找到了另一个解决方案。
我从 PHP 创建了 C 数组,然后将指向它的指针传递给 Rust 代码,然后用 Rust 函数填充它:
$ffi = FFI::cdef('bool get_arr(float (*res)[2]);', './target/release/libphp_rust.dylib');
$array = $ffi->new('float[2]');
$result = $ffi->get_arr(FFI::addr($array));
if ($result) {
var_dump($array);
} else {
//... something went wrong
}
#[no_mangle]
pub extern fn get_arr(array_pointer: *mut [f32;2]) -> bool {
let res = unsafe {
assert!(!array_pointer.is_null());
&mut *array_pointer
};
res[0] = 0.1;
res[1] = 0.2;
return true;
}
这个解决方案似乎工作正常,但我对此有一些疑问:
- 将指针传递给 FFI 是否足够安全,我将来可能会遇到什么问题?
- Rust 数组是否完全兼容 C,以便我能够通过索引直接为其赋值?
- 我有更好的方法来实现我所需要的吗?或者是否有一些关于使用 FFI 传递复杂数据结构的良好实践?
谢谢
围绕此的规则仍然悬而未决,因此您的示例是否安全值得怀疑。这应该没问题,但需要夜间功能:
#![feature(maybe_uninit_extra)]
#![feature(ptr_as_uninit)]
// Make sure you use `extern "C"`. `extern` alone means `extern "Rust"`.
#[no_mangle]
pub extern "C" fn get_arr(array_pointer: *mut [f32; 2]) -> bool {
let fat: *mut [f32] = array_pointer;
let res = unsafe { fat.as_uninit_slice_mut().unwrap() };
res[0].write(0.1);
res[1].write(0.2);
true
}
在稳定频道上就没那么优雅了:
// Make sure you use `extern "C"`. `extern` alone means `extern "Rust"`.
#[no_mangle]
pub extern "C" fn get_arr(array_pointer: *mut [f32; 2]) -> bool {
assert!(!array_pointer.is_null());
unsafe {
let res = array_pointer as *mut f32;
res.add(0).write(0.1);
res.add(1).write(0.2);
}
true
}
我需要 return 来自 rust 函数的几个值。试图声明 return 数组
的函数$ffi = FFI::cdef('float get_arr()[2];', './target/release/libphp_rust.dylib');
$array = $ffi->get_arr();
但是出现错误:
PHP Fatal error: Uncaught FFI\ParserException: function returning array is not allowed at line 1 in /array.php:3
似乎PHP FFI 不能直接使用数组。所以我找到了另一个解决方案。 我从 PHP 创建了 C 数组,然后将指向它的指针传递给 Rust 代码,然后用 Rust 函数填充它:
$ffi = FFI::cdef('bool get_arr(float (*res)[2]);', './target/release/libphp_rust.dylib');
$array = $ffi->new('float[2]');
$result = $ffi->get_arr(FFI::addr($array));
if ($result) {
var_dump($array);
} else {
//... something went wrong
}
#[no_mangle]
pub extern fn get_arr(array_pointer: *mut [f32;2]) -> bool {
let res = unsafe {
assert!(!array_pointer.is_null());
&mut *array_pointer
};
res[0] = 0.1;
res[1] = 0.2;
return true;
}
这个解决方案似乎工作正常,但我对此有一些疑问:
- 将指针传递给 FFI 是否足够安全,我将来可能会遇到什么问题?
- Rust 数组是否完全兼容 C,以便我能够通过索引直接为其赋值?
- 我有更好的方法来实现我所需要的吗?或者是否有一些关于使用 FFI 传递复杂数据结构的良好实践?
谢谢
围绕此的规则仍然悬而未决,因此您的示例是否安全值得怀疑。这应该没问题,但需要夜间功能:
#![feature(maybe_uninit_extra)]
#![feature(ptr_as_uninit)]
// Make sure you use `extern "C"`. `extern` alone means `extern "Rust"`.
#[no_mangle]
pub extern "C" fn get_arr(array_pointer: *mut [f32; 2]) -> bool {
let fat: *mut [f32] = array_pointer;
let res = unsafe { fat.as_uninit_slice_mut().unwrap() };
res[0].write(0.1);
res[1].write(0.2);
true
}
在稳定频道上就没那么优雅了:
// Make sure you use `extern "C"`. `extern` alone means `extern "Rust"`.
#[no_mangle]
pub extern "C" fn get_arr(array_pointer: *mut [f32; 2]) -> bool {
assert!(!array_pointer.is_null());
unsafe {
let res = array_pointer as *mut f32;
res.add(0).write(0.1);
res.add(1).write(0.2);
}
true
}