繁体   English   中英

如何从NodeJS中的Rust FFI函数返回字符串值?

[英]How to return string value from a Rust FFI function in NodeJS?

我想生成6个随机数,将它们推到向量上,然后使用rustc_serialize将该向量编码为JSON字符串,供rustc_serialize使用。

extern crate rand;
extern crate rustc_serialize;

use rand::{OsRng, Rng};
use rustc_serialize::json::{self, Json, ToJson};

#[no_mangle]
pub extern "C" fn generate() -> String {
    let choices: [u8; 6] = [1, 2, 3, 4, 5, 6];

    let mut rand_vec: Vec<u8> = Vec::new();

    let mut rng = match OsRng::new() {
        Ok(t) => t,
        Err(e) => panic!("Failed to create OsRng!, {}", e),
    };

    for _ in 0..5 {
        rand_vec.push(*rng.choose(&choices).unwrap());
    }

    json::encode(&rand_vec).unwrap()
}

此代码被编译为库generate_6_rand.dll 我有一个单独的二进制文件,用于测试此代码。

如果我跑步

println!("{:?}", &json::encode(&rand_vec).unwrap());

输出:

"[5,4,3,4,1,3]" //as expected

然后,我在NodeJS程序中使用我的.dll

var ffi = require('ffi');
var path = require('path');

var lib = ffi.Library(path.join(__dirname,
  './ffi/generate_6_rand.dll'), {
    generate: [ 'string', [ ]]
  });

console.log(lib.generate());

测试

console.log(lib.generate())

输出:

��.�
它是EcmaScript ArrayBuffer吗?

console.log(new ArrayBuffer(lib.generate())

输出:

 ArrayBuffer { byteLength: 0 } 
它的原始链属性是什么?

console.log(lib.generate().__proto__)

输出:

 [String: ''] 

将代码更改为:

 var ref = require('ref'); var ArrayType = require('ref-array'); var Int32Array = ArrayType(ref.types.int32); var lib = ffi.Library(path.join(__dirname, '../dice_lib/target/release/generate_6_rand.dll'), { generate: [ Int32Array, [ ]] }); console.log(new ArrayBuffer(lib.generate())); 

输出:

 ArrayBuffer { byteLength: 0 } 

为什么FFI函数不返回我期望的JSON字符串?

谢谢Wesley Wiser为我提供了有关CString的重要线索。 我在Rust FFI Omnibus中找到了答案。

无论我返回JSON字符串还是返回CString ,在我的NodeJS程序可以访问它之前,都已经释放了预期的JSON字符串的内存。

这是基于该文章的我的解决方案。 对于其他新手程序员,请记住,我的解决方案可能是理想的,也可能不是理想的:

extern crate rand;
extern crate rustc_serialize;
extern crate libc;

use libc::c_char;
use rand::{OsRng, Rng};
use std::ffi::CString;
use rustc_serialize::json;

#[no_mangle]
pub extern "C" fn generate() -> *mut c_char {
    let choices: [u8; 6] = [1, 2, 3, 4, 5, 6];

    let mut rand_vec: Vec<u8> = Vec::new();

    let mut rng = match OsRng::new() {
        Ok(t) => t,
        Err(e) => panic!("Failed to create OsRng!, {}", e),
    };

    for _ in 0..6 {
        rand_vec.push(*rng.choose(&choices).unwrap());
    }

    let json_string = CString::new(json::encode(&rand_vec).unwrap()).unwrap();

    json_string.into_raw()
}

#[no_mangle]
pub extern "C" fn free_memory(pointer: *mut c_char) {
    unsafe {
        if pointer.is_null() {
            return;
        }
        CString::from_raw(pointer)
    };
}

的NodeJS

var ffi = require('ffi');
var path = require('path');

var lib = ffi.Library(path.join(__dirname,
  './ffi/generate_6_rand.dll'), {
    generate: [ 'char *' , [ ]],
    free_memory: ['void', ['char *']]
  });

var json_string = lib.generate();

var save_json = JSON.parse(json_string.readCString());

console.log( json_string.readCString()); // Output: [6,1,6,4,1,4]
lib.free_memory(json_string);
console.log(json_string.readCString()); // Output: ��x�

我设置了两个console.log以显示释放之前和之后的输出。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM