【问题标题】:Shared option-like serializable type with C/C++与 C/C++ 共享的类似选项的可序列化类型
【发布时间】:2022-09-28 20:44:56
【问题描述】:

我正在编写一个 rust 库,并且我有一个结构(这里只显示了我的罪魁祸首字段)。在许多情况下,我将实际的可序列化结构或其他数据分配给my_field,但有时我没有数据,因此想要分配null 或不分配项目。

我试图通过像这样返回(在创建这些消息结构的函数中)来做到这一点:Message<[u8; 0]>,并且我有 ffi 函数返回这种类型,它转换为Message<uint8_t[0]> 作为生成标头中这些函数的返回类型文件(使用cbindgen)。

但是,使用大小为 0 的数组编译 C++ 程序会给出警告:

数组的大小必须大于 0

我可以使用什么锈类型/技术来解决这个问题? *const u8 不可序列化,Option 在 C++ 中不存在

#[repr(C)]
#[derive(Serialize, Deserialize)]
pub struct Message<T: Serialize> {
    pub my_field: T
}
  • 没有“C/C++”这样的东西。 std::optional 非常多地存在于 C++ 中。我不知道 rust 是否会利用它。
  • cbindgen knows Option&lt;&amp;T&gt; 是什么(而 iirc 只是将其转换为可能为空的原始指针),但我认为它在一般情况下不处理 Option 或将其转换为 std::optional。
  • @Caesar 它生成一个结构选项,但没有正文。如果我添加或不添加正文,序列化会生成一个值为 0 的空字节来代替 None... 我不需要存在字节
  • @Caesar 同样,如果我在生成的标头中写了一个空选项结构,my_field 之后的字段将重置为 0
  • @Caesar 已经尝试过但它不起作用,因为结构 Nil 在 C++ 中有一些空间,如果我尝试从 C++ 访问我的结构内的任何数据,my_field 之后的任何字段都将错位(因为 Nil 需要C++ 中的空间),因此所有这些字段都将被损坏。

标签: rust serde


【解决方案1】:

因为类型特征 Deserialize 在所有类型 Option&lt;T&gt; 上实现,给定 T 实现 Deserialize,您可以使用 Option&lt;T&gt; 捕获可选数据。您可以查看文档here

#[repr(C)]
#[derive(Serialize, Deserialize)]
pub struct Message<T: Serialize> {
    pub my_field: Option<T>
}

【讨论】:

  • 但是随后我的 cbindgen 标头将显示带有 Option 的返回类型,这在 c++ 中不存在...
  • 对不起,我没有仔细阅读你的问题。我以为你只需要使用 Rust。
【解决方案2】:

我认为只有两种方法可以绕过这个警告:

  • 关闭 ISO C++ 警告。 Iirc,ISO C++ 根本不允许零大小的结构。 (我现在能找到的最好的参考是sizeof:“sizeof 的结果总是非零”)
  • 为T 使用一些自定义的虚拟结构,它具有1 字节大小的内存表示。您仍然可以通过跳过所有字段(或使用自定义反序列化器)来确保序列化表示的大小为 0:
#[repr(C)]
#[derive(Serialize, Default)]
pub struct Nil {
    #[serde(skip)]
    _dummy: u8,
}

#[no_mangle]
pub extern "C" fn mk_Nil() -> Nil {
    Default::default()
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多