Каковы решения для обёртывания глобальной константы * stast * stati c const` в Rust с использованием Bindgen? - PullRequest
1 голос
/ 20 марта 2020

Я создаю привязки 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 явно?
  • Другие решения?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...