Я создаю привязки Rust для библиотеки C, которая определяет списки стандартных констант значений по умолчанию:
// 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
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 без необходимости дублировать значения C вручную в Rust.
В настоящее время Я дублирую код C в Rust:
// Rust
// Works but unsatisfying
pub const QOS_PROFILE_SENSOR_DATA: QoSProfile = QoSProfile {
depth: 5,
reliability: QoSReliabilityPolicy::BestEffort,
// ...
};
Но это не удовлетворяет. Когда вышестоящая C библиотека обновит эти значения, пользователи столкнутся с непоследовательным поведением и ошибками.
Каковы возможные решения для удобного переноса этих глобальных констант?
идеальное решение:
- Автоматически обновлять значения при изменении библиотеки C восходящего потока
- Предоставлять глобальные
const
s, чтобы эти значения могли быть встроены компилятором - Если это невозможно, предоставьте глобальные неизменяемые переменные
- Если все еще невозможно, по крайней мере, не требуется
unsafe
Проблема, с которой я столкнулся, заключается в том, что, поскольку static const
C структуры хранятся в памяти, они не могут быть легко переведены в const
, и, вероятно, именно поэтому Bindgen переводит его, используя ключевое слово static
.
Итак, возможности, которые Я могу себе представить, но не знаю, как выполнить:
- Есть ли более разумный разбор кода C для генерации кода Rust?
- Использование some f orm of macro ?
- Инициализировать из памяти C stati c в прелюдии?
- Явно инициализировать из памяти C lib stati c явно?
- Другие решения?