2013-08-07 2 views
3

У меня есть существующая программа на C++, которая использует Berkeley DB в качестве хранилища. Я хотел бы переписать его в Rust. Есть ли способ написать интерфейс внешней функции в Rust для использования Berkeley DB? Я нашел учебник Rust Foreign Function Interface, но он кажется слишком простым примером для сложных C-структур, используемых в BDB; например, чтобы открыть базу данных Мне нужно объявить структуру БД и позвонить DB->open(). Но я не знаю, как это сделать, используя пример, показанный в учебнике.Интерфейс Rust с Berkeley DB

Может ли кто-нибудь помочь в этом?

ответ

0

Учитывая явный размер и сложность структуры БД, кажется, нет «чистого» способа разоблачить все это до ржавчины. Инструмент, похожий на C2HS для создания FFI из заголовков C, будет приятным, но, увы, у нас его нет.

Обратите внимание, что Rust FFI в настоящее время не может звонить в библиотеки C++, поэтому вам придется использовать API C.

Я вообще не знаком с API БД, но для создания небольшой библиотеки поддержки в C фактически создается экземпляр структуры БД, а затем выставляются публичные элементы struct __db через getter и setter функции.

Ваша реализация может выглядеть примерно так:

[#link_args = "-lrust_dbhelper"] 
extern { 
    fn create_DB() -> *c_void; 
    fn free_DB(db: *c_void); 
} 

struct DB { 
    priv db: *c_void 
} 

impl Drop for DB { 
    fn drop(&self) { 
     free_DB(self.db); 
    } 
} 

priv struct DBAppMembers { 
    pgsize: u32, 
    priority: DBCachePriority 
    // Additional members omitted for brevity 
} 

impl DB { 
    pub fn new() -> DB { 
     DB { 
      db: create_DB() 
     } 
    } 

    pub fn set_pgsize(&mut self, u32 pgsize) { 
     unsafe { 
      let x: *mut DBAppMembers = ::std::ptr::transmute(self.db); 
      x.pgsize = pgsize; 
     } 
    } 
    // Additional methods omitted for brevity 
} 

Вы можете спасти себя от некоторой дополнительной работы по специально вызова функций C с DB.db элемента в качестве параметра, но это требует работы в небезопасных условиях, которые следует, по возможности, избегать. В противном случае каждая функция, экспортированная libdb, должна иметь свою собственную оболочку в вашем родном struct DB.

+2

Обратите внимание, что существует [rust-bindgen] (https://github.com/crabtw/rust-bindgen), который удаляет много (но не все) ножки в привязке к C libs. – huon

3

Ну, изучая C API BDB, я обнаружил, что он состоит из структур C с элементами-указателями на функции. Это не объяснено в учебнике (что очень странно), но Rust в настоящее время поддерживает pointers to foreign functions. Это также упоминается в Rust reference manual.

Вы можете создать все необходимые структуры примерно на основе тех, которые определены в db.h, а так как структура памяти структуры Rust и C одинакова, вы можете передать эти структуры в/из библиотеки и ожидать, чтобы в них присутствовали правильные указатели.

Например, ваш DB->open() вызов может выглядеть следующим образом:

struct DB { 
    open: extern "C" fn() 
} 

let db = ... // Get DB from somewhere 
(db.open)() // Parentheses around db.open are needed to disambiguate field access 

Это, однако, на самом деле должны быть обернуто в каком-то impl-интерфейсе, потому что вызов функции Экстерна является небезопасной операцией, и вы не хотите, чтобы ваши пользователи помещали unsafe во все взаимодействия с базами данных.

Смежные вопросы