2016-09-05 6 views
3

私はRust bindingsを、組み込みのコンストラクタとデストラクタを使用するCライブラリ用に書いています。 Cヘッダの生さびコード:メモリーから漏れなくCからRust構造体とメソッドをVecとして実装する方法は?

// Opaque structures transform to enumerate 
pub enum UdbEntity_ {} 
pub enum UdbReference_ {} 
... 
pub type UdbEntity = *mut UdbEntity_; 
pub type UdbReference = *mut UdbReference_; 
... 

// Return a non-allocated, permanent list of all entities. This list may be 
// used in places where an allocated entity list is required and may be 
// safely passed to udbListEntityFree(). 
pub fn udbListEntity(list: *mut *mut UdbEntity, items: *mut c_int); 

// Free an allocated list of entities. 
pub fn udbListEntityFree(list: *mut UdbEntity); 
... 

// Return an allocated list of all references for entity. 
// Free the list with udbListReferenceFree(). 
pub fn udbListReference(entity : UdbEntity, 
         refs : *mut *mut UdbReference, 
         items : *mut c_int); 

// Free the allocated references list. 
pub fn udbListReferenceFree(refs: *mut UdbReference); 

これはgit2-rsのように安全なさびコードの実装である:

/// Structure of Entity. 
pub struct Entity<'ents> { 
    raw: UdbEntity, 
    _marker: PhantomData<&'ents UdbEntity>, 
} 

/// Opaque structure of list of entities. 
pub struct ListEntity<'db> { 
    raw: *mut UdbEntity, 
    len: usize, 
    _marker: PhantomData<&'db Db>, 
} 

/// An iterator over the Entity in list of entities. 
pub struct EntityIter<'ents> { 
    range: Range<usize>, 
    ents: &'ents ListEntity<'ents>, 
} 

impl<'db> Drop for ListEntity<'db> { 
    fn drop(&mut self) { 
     unsafe { udbListEntityFree(self.raw) }; 
    } 
} 

すぎるListReferenceReferenceため。

Vec<Entity>(イテレータ、ソート用のスライスなど)と同じようにListEntityと一緒に作業する必要がありますが、実装できません。実装の私のバージョンでは、私はスライスを作成することはできません:from_raw_partsUdbEntity以上のスライスを返しますが、Entityではありません。

私はEntityListVec<Entity>を維持し、私は(それを動かす)Vec<Entity>を編集するときに、後で、EntityListが低下し、割り当てられたリスト*mut UdbEntityを解放しています。私も正しい生涯が必要です。

純粋な錆のコードを書き込むためにいくつかのシンプルな構造体(たとえばKindListKind)を逆にしましたが、もっと慣用的なパスが存在すると思います。

答えて

1

問題は、コード内に2つの互いに素な構造があることです。一方では、UdbEntityの生の配列を所有し、必要に応じて解放する一方、UdbEntityをラップするEntityがありますが、ListEntityで参照されることはありません。ListEntityがあります。

ここには2つのオプションがあります。

  1. は、あなたがそれのスライスを作成することができます、その場合にはEntityの配列、にUdbEntityの配列を核変換します。そのためには、同じメモリ内表現が必要です。
  2. UdbEntityとは別にEntityのベクトルを作成し、代わりに返します。

最初のアプローチが安全であると仮定して、私はそれに行きます。そうでない場合は、2番目のものが機能します。どちらの場合も、Entityの配列は、メモリが適切に管理されるようにListEntityが所有する必要があります。おそらくPhantomDataEntityに入れて、それらへの参照を返すだけです。

+0

私は最初のバージョンが好きだったので、私は試していません。 2番目のバージョンはどうでしょうか?もしVec がListEntityによって所有されていれば、Vecの修正はListEntityの削除を引き起こします。 – saruman9

+0

@ saruman9 'Vec'が' ListEntity'によって所有されていて参照によって外部に見える場合、 'Vec'はそれを失うことはできません - それはRustによって保証されています。 'Vec'を変更可能にする必要があるなら、むしろそれを使うのではなく、' ListEntity'自体に必要な特性を実装してください。ここでの問題は、 'Vec'とその基礎構造を同期して変更する必要があることです。これは非常に困難です。 – Malcolm

+0

私は配列 'UdbEntity'から' Entity'への 'Deref'特性の変換を実装しています(' FantomData'を使って、一部のFFI関数ではEntityを簡単に参照するのが難しいので)。 'ListEntity'ではこれが今動作します。私は 'ListReference'も実装しようとします。 – saruman9

関連する問題