Компилятор не проверяет перечисления на совместимость с 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. Casting + 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. Нужно перечисление?
В случае, если вам нужна абстракция для низкоуровневых привязок, вы можете go без нового типа перечисления.
#[repr(transparent)]
pub struct QoSHistoryPolicy(rmw_qos_history_policy_t);
Тип выше содержит та же информация и двоичное представление, но может предоставить инкапсулированный API. Преобразование из типа низкого уровня в тип высокого уровня становится тривиальным. Основным недостатком является то, что вы теряете сопоставление с образцом по его вариантам.
4. Вы сами по себе
Когда абсолютно уверены , что два перечисления эквивалентны в их двоичном представлении, вы можете transmute
между ними. Компилятор вам здесь не поможет, это далеко не рекомендуется.
unsafe {
let policy: QoSHistoryPolicy = std::mem::transmute(val);
}
См. Также: