Rust 与其他语言互操作时管理模型的最佳方法是什么?

Rus*_*rop 5 c# interop rust typescript

背景

我目前正在开发一个完全用 Rust 编写的库,但它将被 Rust 以外的编程语言使用。虽然跨越 FFI 边界进行讨论很简单,但用其他编程语言编写与 Rust 模型 1:1 映射的模型却并非如此。这个问题围绕是否存在工具或最佳实践来简化跨 FFI 边界的模型生成的想法

目前的方法

我目前的做法如下:

  • 跨 FFI 边界通信所需的所有模型都是 Serde 可串行化的。
  • 所有函数都extern接受指向字符串的指针并返回指向字符串的指针。
  • 函数调用采用 JSON 序列化参数的字符串并返回 JSON 序列化响应的字符串。这意味着客户端语言需要有一组模型,其序列化方式与 Rust 编写的模型相同。

问题

正如背景中提到的,虽然跨 FFI 边界的通信非常简单,但编写与 Rust 编写的模型完全映射(和序列化)的模型却并非如此。目前,我的 Rust 库有 5 个用 5 种不同编程语言编写的包装器,编写、测试和迭代这些 DTO 模型的过程远非简单。

问题

  • 是否存在一种以合理的方式描述从我的库导出的模型和函数的方法,然后可以由某些工具使用它来生成模型或至少是最小的包装器?
  • 跨 FFI 边界发送 JSON 是否存在任何问题?
  • 这里有我忽略的最佳实践吗?或这些问题的解决方案?

尝试过的替代方法

  • Protocol Buffers:我尝试过使用 Protocol Buffers 代替 JSON 和手写模型。然而,协议缓冲区存在两个主要问题,这使得它们不适合我的用例:
    • 协议缓冲区没有我需要的一些原始类型。例如:8 位整数、16 位整数和 128 位整数类型。我想强制执行某些类型仅限于 8 位,并且这些类型生成的模型应使用其他语言中可用的 8 位整数类型。
    • 协议缓冲区假定所有字段都是可选的,并且不能以其他方式创建它们。虽然这对于大多数应用程序来说都很好,但我正在构建的库在运行时宁愿恐慌,也不愿处理可选字段的默认值。
  • Cap'n'proto:这与上面的问题大多相似,它强制所有字段都应该是可选的,这对于我的用例来说是不行的。
  • OpenAPI:我尝试了很短的一段时间,使用 OpenAPI 模式描述所有模型,然后客户端语言可以使用该模式来生成模型。这有以下问题:
    • 通过 OpenAPI 代码生成器生成的模型通常不可读、无法编译,并且难以理解或迭代。

vel*_*sta 0

您是否考虑过使用普通旧的jsonschema来达到此目的?虽然 OpenAPI 更专门针对 Web API,但您可以为模型编写该架构,并为您的库和客户端使用从该架构生成的模型。

编辑:我能看到的“通过 FFI 边界发送 json 字符串”的唯一主要问题是,您必然会增加序列化/反序列化的开销,这可能不是微不足道的。