首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为Node-FFI创建C/Rust代码中的结构

为Node-FFI创建C/Rust代码中的结构
EN

Stack Overflow用户
提问于 2021-04-09 21:51:48
回答 1查看 445关注 0票数 0

我试图将一个结构从一个锈蚀函数返回到Node.js,这个结构是嵌套的,包含一个数组,因此它非常复杂,所以我想在Rust中执行分配,并让Node.JS接收一个完整的对象,简而言之,下面是Rust代码:

返回的State包含许多Config、消息(例如错误消息或一些警告)和一些信任。

代码语言:javascript
复制
use std::ffi::CStr;
use std::os::raw::c_char;

#[derive(Debug)]
#[repr(C)]
pub struct Config {
    pub some_fields_here: String,
    // pub ...
}

#[derive(Debug)]
#[repr(C)]
pub struct State {
    pub message: String, // Even changing this to *mut c_char doesn't help the immediate problem
    pub configs: *mut Config,
    pub num_configs: usize,
}

#[no_mangle]
pub extern "C" fn config_from_file(_not_really_used_in_example: *const c_char) -> *mut Configuration {
    let mut configs: Vec<Config> = vec![];
    configs.push(Config {
      some_fields_here: String::from("hello world"), // should maybe be CString::from(...).into_raw()
    });
    Box::into_raw(Box::new(State {
        message: String::from("a message here"),
        configs: Box::into_raw(configs.into_boxed_slice()) as *mut Config,
        num_configs: 1,
    }))
}

从节点方面来说,我们发现的所有示例和文档都只是利用StructType来准备一些东西传递到FFI中,或者透明地传递,而不需要询问它。

我们想做的是:

代码语言:javascript
复制
var ffi = require("ffi-napi");
var ref = require("ref-napi");
var StructType = require("ref-struct-di")(ref);
var ArrayType = require("ref-array-di")(ref);

const Config = StructType({
  some_fields_here: ref.types.CString,
});

const State = StructType({
  message: ref.types.CString,
  configs: ref.refType(ArrayType(Config)),
  num_configs: ref.types.size_t,
});

const StatePtr = ref.refType(StatePtr);

var ourlib = ffi.Library("./target/debug/ourlib", {
  config_from_file: [StatePtr, [ref.types.CString]],
});

const ffiResult = ourlib.config_from_file("a file path, in the real code");
console.log(ffiResult)
// => <Buffer@0x47ce560 20 e2 83 04 00 00 00 00 57 00 00 00 00 00 00 00 57 00 00 00 00 00 00 00, 
type: { [Function: StructType] defineProperty: [Function: defineProperty], toString: [Function: 
toString], fields: { message: [Object], configs: [Object], num_configs: [Object] }, size: 24, 
alignment: 8, indirection: 1, isPacked: false, get: [Function: get], set: [Function: set] }>

在这里,我们需要获得一个Javscript对象(类似于上面的struct ),访问任何字段,或者将它看作一个对象。我们没有在https://tootallnate.github.io/ref的测试或文档中找到适当的示例,也没有在https://github.com/node-ffi-napi/ref-struct-di中找到合适的示例

我不希望从Buffer()支持的C对象中清晰地传递到JavaScript,当然,我们必须解码和移动事物,但我无法从JavaScript访问包含在该结构中的信息。任何deref()toObject()或获取单个字段的组合似乎都没有帮助。

我本以为这样的事情可能会起作用,但它可能会导致错误或打印垃圾,这取决于我所做的一些微小的调整:

代码语言:javascript
复制
console.log(ffiResult);
console.log(ref.deref().readCString(ffiResult, 0));

我知道在某种程度上在库中进行分配,并且在宿主语言中解压缩这些结构是不统一的,但是由于数据的形状,而且我们不能更改库代码,我们没有太多的选择。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-26 07:56:20

,包含一个数组,所以我想在Rust中进行分配,并让Node.JS接收一个完整的对象,这是非常复杂的,

包含数组是棘手的/陷阱部分。C (ergo )中的数组趋向于为零结束,但不能保证对结构数组的工作方式是特殊的。

以下是我们必须做的事情:

  1. In Rust,公开带有长度成员的结构,以及指向单个项的指针。在Rust中,
  2. 分配我们的东西的向量,并使用into_boxed_slice()来忘记它,这给出了指向第一个的指针。
  3. 填充了结构

上的length属性。

就像我们第一次发布的例子一样。

然而,在node.js中,它有一点不同,工作代码与我们所拥有的几乎完全相同,下面是类型:

代码语言:javascript
复制
const Config = StructType({
  some_fields_here: ref.types.CString,
});

const State = StructType({
  message: ref.types.CString,
  configs: ArrayType(Config), // we had refType(ArrayType(Config))
  num_configs: ref.types.size_t,
});

const StatePtr = ref.refType(StatePtr);

var ourlib = ffi.Library("./target/debug/ourlib", {
  config_f...

在进行了该更改之后,唯一的问题是,在初始化长度之前,数组是不可用的,因此,稍后我们只需这样做:

代码语言:javascript
复制
const ffiResult = ourlib.config_from_file("a file path, in the real code");
const ffiState = ffiResult.deref(); // it's a pointer, remember.
ffiState.configs.length = ffiState.num_configs; // see comment below

在设置ArrayType的长度之后,可以或多或少地使用它,就像普通数组一样。

他是this commit (dc0d7296) from about a decade ago!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67028734

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档