从Rust库返回指向对象的指针以供以后重用?

时间:2018-08-20 15:23:46

标签: rust shared-libraries

我想调用一个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
    }
}

我已经成功测试了功能“ addition”,该功能不需要持久的“增量机器”,但是我想使用 engine 模式(显然,比起增加{{ 1}})。我研究了许多有关跨库边界传递数据的站点,关于传递结构等有很多信息,但是关于“持久指针”的信息并不多。唯一接近该解决方案的地方是in the Nomicon,其中Rust库回调了调用者,该调用者允许该对象持久化,但实际上不适用于我的用例。

该示例中的

doubleengine_id,但大概是指向int创建的对象的某种指针。

1 个答案:

答案 0 :(得分:1)

This approach可以采取:

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