首页 > 解决方案 > 从 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

标签: rustshared-libraries

解决方案


可以采取这种方法:

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已被删除,因为它仅用于解决问题。


推荐阅读