Enums 如何将bindgen生成的C样式枚举转换为另一个枚举?

Enums 如何将bindgen生成的C样式枚举转换为另一个枚举?,enums,rust,rust-bindgen,Enums,Rust,Rust Bindgen,我正在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_AL

我正在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库
const rmw\u qos\u history\u policy\u从\u C=rmw\u qos\u policy\u history\u SYSTEM\u默认值中获取一些\u值;
我想做一些类似的事情:

let some_value: QoSHistoryPolicy = some_value_from_C;

我该怎么办呢?

它似乎是
QoSHistoryPolicy
上的
的一个很好的候选人

impl From for QoSHistoryPolicy{
fn from(原始:rmw\u qos\u history\u policy\t)->Self{
火柴{
rmw_qos_history_policy_t::rmw_qos_policy_history_SYSTEM_DEFAULT=>QoSHistoryPolicy::SystemDefault,
rmw\U qos\U history\U policy\U t::rmw\U qos\U policy\U history\U KEEP\U LAST=>QoSHistoryPolicy::KeepLast,
rmw\U qos\U history\U policy\U t::rmw\U qos\U policy\U history\U KEEP\U ALL=>QoSHistoryPolicy::KeepAll,
rmw_qos_history_policy_t::rmw_qos_policy_history_UNKNOWN=>QoSHistoryPolicy::UNKNOWN
}
}
}
所以现在应该可以了

let some_value:qohistorypolicy=some_value_from_C.into();

编译器不检查枚举的ABI兼容性,因此不提供在这些类型之间转换值的直接方法。以下是一些可能的解决方案

1.一一匹配 这是琐碎和安全的,尽管会导致代码穷尽

impl From for QoSHistoryPolicy{
fn from(x:rmw\u qos\u history\u policy\t)->Self{
使用rmw_qos_history_policy_t::*;
匹配x{
RMW_QOS_策略_历史_系统_默认=>QoSHistoryPolicy::SystemDefault,
RMW_QOS_策略_历史_保留_最后=>QoSHistoryPolicy::KeepLast,
RMW_QOS_策略_历史_保留所有=>QoSHistoryPolicy::KeepAll,
RMW_QOS_策略_历史_未知=>QoSHistoryPolicy::未知,
}
}
}
2.铸造+原始 Rust允许您使用
as
运算符将无字段枚举转换为整数类型。然而,相反的转换并不总是安全的。使用
num
板条箱从原语中派生
from
,以获取缺少的片段

#[派生(原始)]
发布枚举QoSHistoryPolicy{…}
QoSHistoryPolicy的impl From{
fn from(x:rmw\u qos\u history\u policy\t)->Self{
FromPrimitive::from_32(x为32).expect(“1:1枚举变量匹配,一切正常”)
}
}
3.需要枚举吗? 如果您只需要对低级绑定进行抽象,则可能不需要新的枚举类型

#[repr(transparent)]
pub struct QoSHistoryPolicy(rmw_qos_history_policy_t);
上面的类型包含相同的信息和二进制表示,但可以公开封装的API。从低级类型到高级类型的转换变得微不足道。主要的缺点是,与它的变体相比,您会丢失模式匹配

4.你得靠自己 当绝对确定这两个枚举在二进制表示中是等效的时,您可以
在它们之间转换
。编译器在这里帮不了你,这远远不是推荐的

unsafe {
    let policy: QoSHistoryPolicy = std::mem::transmute(val);
}
另请参见:


谢谢!想想看,如果上游API发生变化,我希望编译失败,所以我选择选项1:)对于其他解决方案,不仅有可能出现恐慌,而且还有运行时检查,因此会受到惩罚。选项1是详尽的,但您可以看到长,将长名称转换为简单名称的整洁命名空间系统:)