The compiler does not inspect enums for ABI compatibility, and as such does not provide a direct way to convert values between these types. A few possible solutions follow.
1. One-by-one matching
This is trivial and safe, albeit leading to exhaustive code.
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. Casting + FromPrimitive
Rust allows you to convert field-less enums into an integer type using the as
operator. The opposite conversion is not always safe however. Derive FromPrimitive
using the num
crate to obtain the missing piece.
#[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. Need an enum?
In the event that you just want an abstraction to low-level bindings, you might go without a new enum type.
#[repr(transparent)]
pub struct QoSHistoryPolicy(rmw_qos_history_policy_t);
The type above contains the same information and binary representation, but can expose an encapsulated API. The conversion from the low-level type to the high-level type becomes trivial. The main downside is that you lose pattern matching over its variants.
4. You're on your own
When absolutely sure that the two enums are equivalent in their binary representation, you can transmute
between them. The compiler won't help you here, this is far from recommended.
unsafe {
let policy: QoSHistoryPolicy = std::mem::transmute(val);
}
See also: