我正在为定义标准常量默认值列表的 C 库创建 Rust 绑定:
// C
typedef struct RMW_PUBLIC_TYPE rmw_qos_profile_t
{
size_t depth;
enum rmw_qos_reliability_policy_t reliability;
// ...
} rmw_qos_profile_t;
enum RMW_PUBLIC_TYPE rmw_qos_reliability_policy_t
{
RMW_QOS_POLICY_RELIABILITY_RELIABLE,
RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
// ...
};
// Global value that needs wrapping
static const rmw_qos_profile_t rmw_qos_profile_sensor_data =
{
5,
RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
// ...
};
使用 Bindgen,static
生成 Rust 变量:
// Rust
extern "C" {
#[link_name = "\u{1}rmw_qos_profile_sensor_data"]
pub static rmw_qos_profile_sensor_data: rmw_qos_profile_t;
}
但是static
全局变量在 Rust 中使用起来非常不方便,必须将每个访问都封装在一个unsafe {}
块中。特别是当您不需要可变性时。
我已经用 Rust 包装了结构和枚举:
// Rust
pub enum QoSReliabilityPolicy {
Reliable = 0,
BestEffort = 1,
}
impl From<rmw_qos_reliability_policy_t> for QoSReliabilityPolicy {
fn from(raw: rmw_qos_reliability_policy_t) -> Self {
match raw {
rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_RELIABLE => QoSReliabilityPolicy::Reliable,
rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT => QoSReliabilityPolicy::BestEffort,
}
}
}
pub struct QoSProfile {
pub depth: usize,
pub reliability: QoSReliabilityPolicy,
// ...
}
impl From<rmw_qos_profile_t> for QoSProfile {
fn from(qos_profile: rmw_qos_profile_t) -> Self {
QoSProfile {
depth: qos_profile.depth,
reliability: qos_profile.reliability.into(),
// ...
}
}
}
impl From<rmw_qos_profile_t> for QoSProfile {
fn from(qos_profile: rmw_qos_profile_t) -> Self {
QoSProfile {
depth: qos_profile.depth,
reliability: qos_profile.reliability.into(),
// ...
}
}
}
现在,我正在寻找一种解决方案来rmw_qos_profile_sensor_data
向我的 Rust 用户公开相同的预定义配置文件,例如 ,而无需在 Rust 中手动复制 C 值。
目前我正在用 Rust 复制 C 代码:
// Rust
// Works but unsatisfying
pub const QOS_PROFILE_SENSOR_DATA: QoSProfile = QoSProfile {
depth: 5,
reliability: QoSReliabilityPolicy::BestEffort,
// ...
};
但这并不令人满意。当上游 C 库更新这些值时,用户会遇到不一致的行为和错误。
方便地包装这些全局常量的可能解决方案是什么?
理想的解决方案是:
- 上游 C 库更改时自动更新值
- 公开 global
const
以便编译器可以内联这些值 - 如果不可能,公开全局不可变变量
- 如果仍然不可能,至少不需要
unsafe
我一直面临的问题是,由于static const
C 结构存储在内存中,它们不能const
轻易翻译成 a,这可能就是 Bindgen 使用static
关键字翻译它的原因。
因此,我可以想象但不知道如何执行的可能性是:
- 对 C 代码进行更智能的解析以生成 Rust 代码?
- 使用某种形式的宏?
- 从前奏中的 C lib 的静态内存初始化?
- 显式地从 C lib 的静态内存初始化?
- 其他解决方案?