在 C/Rust 代码中为 Node-FFI 创建结构
Create struct in C/Rust code for Node-FFI
我正在尝试 return 从 Rust 函数到 Node.js 的结构,该结构是嵌套的,并且包含一个数组,所以它非常复杂,我想在 Rust 中进行分配并让 Node.JS 收到一个完整的对象,这里是简短的 Rust 代码:
一个 State
是 returned,其中包含许多 Config
、一条消息(例如错误消息或一些警告)和许多配置。
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,
}))
}
从 Node 方面来看,我们发现的所有示例和文档仅使用 StructType
来准备要传递给 FFI 的东西,或者透明地传递而不用询问它。
我们想做的是:
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对象,访问
到任何字段,或将其视为对象。我们没有在 https://tootallnate.github.io/ref, nor in https://github.com/node-ffi-napi/ref-struct-di
的测试或文档中找到合适的示例
我不希望从 Buffer()
支持的 C 对象到 JavaScript 有一个干净的传递,当然我们必须解码和移动东西,但我找不到任何 方式从JavaScript 访问该结构中包含的信息。任何 deref()
或 toObject()
的组合或获取单个字段似乎都没有帮助。
我预计这样的事情可能会成功,但它 either/or 会出现段错误或打印垃圾,这取决于我以某种方式进行的一些小调整:
console.log(ffiResult);
console.log(ref.deref().readCString(ffiResult, 0));
我知道在某种程度上在库中进行分配,并且在宿主语言中解压缩这些结构是不合常理的,但是由于数据的形状,并且我们无法更改库代码,所以我们不这样做有很多选择。
and contains an array so it is sufficiently complicated that I want to do the allocation in Rust and have Node.JS receive a complete object,
包含数组的是 tricky/trap 部分。 C 中的数组(ergo FFI)往往以零终止,但不能保证结构数组以特定方式工作。
这是我们必须做的:
- 在 Rust 中,公开一个带有长度成员的结构和一个指向单个项目的指针。
- 在 Rust 中,分配我们事物的向量并使用
into_boxed_slice()
忘记它,这给出了指向第一个的指针。
- 在我们的结构
上填充长度属性
一切都像我们首先发布的示例。
虽然在 node.js 中有点不同,但工作代码与我们的代码几乎相同,类型如下:
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...
进行了更改后,唯一的问题是数组在长度初始化之前无法使用,因此稍后我们只需要这样做:
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
就可以像普通数组一样使用了。
我正在尝试 return 从 Rust 函数到 Node.js 的结构,该结构是嵌套的,并且包含一个数组,所以它非常复杂,我想在 Rust 中进行分配并让 Node.JS 收到一个完整的对象,这里是简短的 Rust 代码:
一个 State
是 returned,其中包含许多 Config
、一条消息(例如错误消息或一些警告)和许多配置。
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,
}))
}
从 Node 方面来看,我们发现的所有示例和文档仅使用 StructType
来准备要传递给 FFI 的东西,或者透明地传递而不用询问它。
我们想做的是:
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对象,访问 到任何字段,或将其视为对象。我们没有在 https://tootallnate.github.io/ref, nor in https://github.com/node-ffi-napi/ref-struct-di
的测试或文档中找到合适的示例我不希望从 Buffer()
支持的 C 对象到 JavaScript 有一个干净的传递,当然我们必须解码和移动东西,但我找不到任何 方式从JavaScript 访问该结构中包含的信息。任何 deref()
或 toObject()
的组合或获取单个字段似乎都没有帮助。
我预计这样的事情可能会成功,但它 either/or 会出现段错误或打印垃圾,这取决于我以某种方式进行的一些小调整:
console.log(ffiResult);
console.log(ref.deref().readCString(ffiResult, 0));
我知道在某种程度上在库中进行分配,并且在宿主语言中解压缩这些结构是不合常理的,但是由于数据的形状,并且我们无法更改库代码,所以我们不这样做有很多选择。
and contains an array so it is sufficiently complicated that I want to do the allocation in Rust and have Node.JS receive a complete object,
包含数组的是 tricky/trap 部分。 C 中的数组(ergo FFI)往往以零终止,但不能保证结构数组以特定方式工作。
这是我们必须做的:
- 在 Rust 中,公开一个带有长度成员的结构和一个指向单个项目的指针。
- 在 Rust 中,分配我们事物的向量并使用
into_boxed_slice()
忘记它,这给出了指向第一个的指针。 - 在我们的结构 上填充长度属性
一切都像我们首先发布的示例。
虽然在 node.js 中有点不同,但工作代码与我们的代码几乎相同,类型如下:
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...
进行了更改后,唯一的问题是数组在长度初始化之前无法使用,因此稍后我们只需要这样做:
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
就可以像普通数组一样使用了。