enums - 如何将由 bindgen 生成的 C 样式枚举转换为另一个枚举?
问题描述
我在 Rust 中为 C 库和 Bindgen 生成的枚举创建绑定,例如:
// Rust
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum rmw_qos_history_policy_t {
RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT = 0,
RMW_QOS_POLICY_HISTORY_KEEP_LAST = 1,
RMW_QOS_POLICY_HISTORY_KEEP_ALL = 2,
RMW_QOS_POLICY_HISTORY_UNKNOWN = 3,
}
我需要将这些转换为:
// Rust
pub enum QoSHistoryPolicy {
SystemDefault = 0,
KeepLast = 1,
KeepAll = 2,
Unknown = 3,
}
从该 C 库导入常量值时:
// C library
const rmw_qos_history_policy_t some_value_from_C = RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT;
我想做类似的事情:
let some_value: QoSHistoryPolicy = some_value_from_C;
我该怎么办?
解决方案
编译器不检查枚举的 ABI 兼容性,因此不提供在这些类型之间转换值的直接方法。以下是一些可能的解决方案。
1. 一对一匹配
这是微不足道且安全的,尽管会导致详尽的代码。
impl From<rmw_qos_history_policy_t> for QoSHistoryPolicy {
fn from(x: rmw_qos_history_policy_t) -> Self {
use rmw_qos_history_policy_t::*;
match x {
RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT => QoSHistoryPolicy::SystemDefault,
RMW_QOS_POLICY_HISTORY_KEEP_LAST => QoSHistoryPolicy::KeepLast,
RMW_QOS_POLICY_HISTORY_KEEP_ALL => QoSHistoryPolicy::KeepAll,
RMW_QOS_POLICY_HISTORY_UNKNOWN => QoSHistoryPolicy::Unknown,
}
}
}
2. 铸造+FromPrimitive
Rust 允许您使用运算符将无字段枚举转换为整数类型as
。然而,相反的转换并不总是安全的。FromPrimitive
使用板条箱派生num
以获得丢失的部分。
#[derive(FromPrimitive)]
pub enum QoSHistoryPolicy { ... }
impl From<rmw_qos_history_policy_t> for QoSHistoryPolicy {
fn from(x: rmw_qos_history_policy_t) -> Self {
FromPrimitive::from_u32(x as _).expect("1:1 enum variant matching, all good")
}
}
3. 需要枚举?
如果您只想对低级绑定进行抽象,则可能不需要新的枚举类型。
#[repr(transparent)]
pub struct QoSHistoryPolicy(rmw_qos_history_policy_t);
上述类型包含相同的信息和二进制表示,但可以公开封装的 API。从低级类型到高级类型的转换变得微不足道。主要的缺点是您失去了对其变体的模式匹配。
4. 你靠自己
当绝对确定这两个枚举在其二进制表示中是等价的时,您可以transmute
在它们之间。编译器在这里不会帮助你,这远非推荐。
unsafe {
let policy: QoSHistoryPolicy = std::mem::transmute(val);
}
也可以看看:
推荐阅读
- javascript - 不断等待点击(不管 DOM 的变化或其他点击)
- python - 如何编写代码将日志记录为 argv?
- angular - 如何使用 NX/Nrwl 为 Angular 创建应用程序特定配置?
- ansible - 一个悖论 - 将我的 Ansible 服务器置于 CM 控制之下?
- docker - 项目(https://github.com/TencentCloud/O266player.git)构建失败Windows错误(docker)
- c# - C# Xamarin Forms - 调用事件总是返回 null
- autodesk-forge - 如何在伪造查看器中移动到任何给定坐标
- r - 有没有办法用代表 R 中数字的命名元素对列表进行排序,以便它返回元素的名称 ratehr 而不是它们的值?
- vscode-extensions - 如何在新终端中运行程序作为 vs 代码扩展?
- cucumber - 错误:我们已尝试在 src/integration/ 解析您的步骤定义,但这似乎不存在