【问题标题】:Returning a pointer to an object from a Rust library for later reuse?从 Rust 库返回指向对象的指针以供以后重用?
【发布时间】:2019-01-26 18:33:03
【问题描述】:

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

我已经成功测试了不需要持久“增量机”的功能“加法”,但我想使用 engine 模式(显然比增加@987654329 更复杂的事情@)。我调查了许多关于跨库边界传递数据的站点,并且有很多关于传递结构等的信息,但关于“持久指针”的信息并不多。唯一接近解决方案的是in the Nomicon,Rust 库在其中回调调用者,这允许对象持续存在,但它实际上不适用于我的用例。

示例中的engine_idint,但可能是指向set_increment_engine 创建的对象的某种指针。

【问题讨论】:

  • 我不想将所有权转移给 C(因为我不得不一直来回转移它),但乍一看,“Rust FFI Omnibus”似乎很有希望,我会仔细看看。
  • 更具体地说,关于所有权 - 示例从 Rust 调用 C 函数,但我反过来 - 我从 C 调用 rust 函数。
  • 我必须来回传送它——你为什么相信?您是否认为传输指针是一项昂贵的操作?
  • 也许它也可以使用,但它提出了更多问题:如何将所有权作为结果返回给调用 C 函数?如何在 C 代码中重用它?当稍后从 C 代码调用时,我如何将它以 rust 的形式“重新键入”回它所指的对象?但是,我将查看这两个链接并返回。非常感谢这两个链接。

标签: rust shared-libraries


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

【讨论】:

  • @Shepmaster 如果您查看我编制的答案,我将不胜感激。我已经对其进行了测试,它似乎运行良好,但也许您可以获得一些有价值的见解。感谢您提供鼓舞人心的链接,这个答案的功劳应该归您所有,但是我不知道该怎么做...
  • 唯一我不太确定的是在 java 端 long got 指针的用法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 2020-12-11
  • 2023-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多