rust - 从 Rust 库返回指向对象的指针以供以后重用?
问题描述
我想调用一个 Rust 库,它将increment_engine
为我创建一个对象并返回一个指向它的指针(或任何持久的)。该引擎将在创建时获得一个参数。
稍后我可以调用这个对象的increment(a)
方法,它会将记住的参数添加到a
并返回结果。这是代码:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class App {
public interface MyLibrary extends Library {
MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("myjavarust", MyLibrary.class);
double addition(double a , double b);
int set_increment_engine(double parameter);
double use_increment_engine(int engine_id, double a);
}
public static void main() {
int sum = MyLibrary.INSTANCE.addition(13.0,5.0);
System.out.println(sum); // this works and prints 18 (=13+5)
engine_id = MyLibrary.INSTANCE.get_increment_engine(13.0);
double result = MyLibrary.INSTANCE.use_increment_engine(engine_id,5.0);
System.out.println(result); // this should also return 18
}
}
最后三行main()
显示我想如何使用“增量引擎”
Rust 伪代码应该是这样的。
extern crate libc;
use libc::{c_double, uint32_t};
#[no_mangle]
pub extern "C" fn addition(a: f64, b: f64) -> f64 {
a + b
}
#[no_mangle]
pub extern "C" fn set_increment_engine(param: c_double) -> uint32_t {
let engine = IncrementEngine { param: param };
return_engine_id_somehow
}
#[no_mangle]
pub extern "C" fn use_increment_engine(engine_id: uint32_t, a: c_double) -> c_double {
let engine = find_engine_somehow(engine_id);
engine.increment(a)
}
struct IncrementEngine {
param: c_double,
}
impl IncrementEngine {
pub fn increment(&self, a: f64) -> f64 {
a + self.param
}
}
我已经成功测试了不需要持久的“增量机”的功能“加法”,但我想使用引擎模式(显然用于比增加 a 更复杂的事情double
)。我调查了许多关于跨库边界传递数据的站点,并且有很多关于传递结构等的信息,但关于“持久指针”的信息并不多。唯一接近解决方案的是Nomicon,Rust 库在其中回调调用者,这允许对象持久存在,但它实际上不适用于我的用例。
engine_id
在这个例子中是一个int
,但大概它是某种指向由 . 创建的对象的指针set_increment_engine
。
解决方案
可以采取这种方法:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class App {
public interface MyLibrary extends Library {
MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("myjavarust", MyLibrary.class);
long set_increment_engine(double parameter);
double use_increment_engine(long engine, double a);
void free_increment_engine(long engine);
}
public static void main(String[] args) {
long engine = MyLibrary.INSTANCE.set_increment_engine(13.0);
double result = MyLibrary.INSTANCE.use_increment_engine(engine, 5.0);
System.out.println(result); // returns correctly 18.0
MyLibrary.INSTANCE.free_increment_engine(engine);
}
}
使用此lib.rs代码:
extern crate libc;
use libc::c_double;
#[no_mangle]
pub extern "C" fn set_increment_engine(param: c_double) -> *mut IncrementEngine {
let engine = IncrementEngine { param: param };
Box::into_raw(Box::new(engine))
}
#[no_mangle]
pub extern "C" fn use_increment_engine(engine_ptr: *mut IncrementEngine, a: c_double) -> c_double {
let engine = unsafe {
assert!(!engine_ptr.is_null());
&mut *engine_ptr
};
engine.increment(a)
}
#[no_mangle]
pub extern "C" fn free_increment_engine(engine_ptr: *mut IncrementEngine) {
if engine_ptr.is_null() {
return;
}
unsafe {
Box::from_raw(engine_ptr);
}
}
pub struct IncrementEngine {
param: c_double,
}
impl IncrementEngine {
pub fn increment(&self, a: f64) -> f64 {
a + self.param
}
}
请注意,该功能addition
已被删除,因为它仅用于解决问题。