2013-08-07 9 views
3

Berkeley DB를 저장소 백엔드로 사용하는 기존 C++ 프로그램이 있습니다. 녹에서 다시 쓰고 싶습니다. Berkeley DB를 사용하기 위해 Rust에 Foreign Function Interface를 작성하는 방법이 있습니까? 튜토리얼 Rust Foreign Function Interface을 찾았지만 BDB에서 사용되는 복잡한 C 구조체의 경우 너무 단순한 것처럼 보입니다. 예를 들어 데이터베이스를 열려면 DB 구조체를 선언하고 DB->open()을 호출해야합니다. 그러나 자습서에 나와있는 예제를 사용하여이를 수행하는 방법을 알지 못합니다.Rust와 Berkeley DB의 인터페이스

아무도 도와 드릴 수 있습니까?

답변

0

DB 구조체의 크기와 복잡성을 감안할 때, 모든 것을 녹에 노출시키는 "깨끗한"방법은 아닙니다. C2HS과 유사한 도구를 사용하면 C 헤더에서 FFI를 생성 할 수 있지만 좋지 않을 것입니다.

녹 음 FFI는 현재 C++ 라이브러리를 호출 할 수 없으므로 대신 C API를 사용해야합니다.

저는 DB API에 익숙하지 않지만 DB 구조체의 인스턴스를 실제로 생성하기 위해 C에서 작은 지원 라이브러리를 만든 다음 getter 및 setter를 통해 struct __db의 공용 멤버를 노출하는 것이 그럴듯한 것으로 보입니다 기능.

귀하의 구현은 다음과 같이 표시 될 수 있습니다

[#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 
} 

특별히 매개 변수로 DB.db 멤버 C 함수를 호출하여 일부 추가 작업에서 자신을 저장할 수 있지만이 안전하지 않은 상황에서 작업을 요구하는 가능하다면 피해야한다. 그렇지 않은 경우 libdb으로 내 보낸 각 함수는 고유 한 struct DB에 자체 래퍼가 있어야합니다.

+2

C 라이브러리에 바인딩 할 때 많은 양 (전부는 아님)을 제거하는 [rust-bindgen] (https://github.com/crabtw/rust-bindgen)이 있습니다. – huon

3

글쎄, BDB의 C API를 살펴보면 함수를 가리키는 요소 인 포인터가있는 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을 입력하도록하십시오.