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

时间:2020-03-18 11:14:47

标签: 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_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;

我该怎么办?

2 个答案:

答案 0 :(得分:7)

编译器不检查枚举是否具有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);
}

另请参见:

答案 1 :(得分:3)

它似乎很适合From上的QoSHistoryPolicy trait

impl From<rmw_qos_history_policy_t> for QoSHistoryPolicy {
    fn from(raw: rmw_qos_history_policy_t) -> Self {
        match raw {
            rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT => QoSHistoryPolicy::SystemDefault,
            rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_KEEP_LAST => QoSHistoryPolicy::KeepLast,
            rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_KEEP_ALL => QoSHistoryPolicy::KeepAll,
            rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_UNKNOWN => QoSHistoryPolicy::Unknown
        }
    }
}

所以现在应该可以了

let some_value: QoSHistoryPolicy = some_value_from_C.into();