I'm writing Rust bindings for a C library which uses an embedded constructor and destructor. Raw Rust code of C header:
// 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);
This is implementation of safe Rust code as in 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) };
}
}
And for ListReference and Reference too.
I need to work with ListEntity as with Vec<Entity> (iterators, slices for sorting and etc.), but I can't implement it. In my versions of implementing I can't create slices: from_raw_parts returns slices over UdbEntity, not Entity.
When I keep Vec<Entity> in EntityList and later when I edit Vec<Entity> (moving it), EntityList is dropped and frees the allocated list *mut UdbEntity. I need correct lifetimes too.
I reversed some simple structs (Kind, ListKind for example) for writing pure Rust code, but I think a more idiomatic path exists.
The problem is that you have two rather disjoint structures in your code. On the one hand, you have a ListEntity which owns a raw array of UdbEntity and frees it when required, on the other hand you have an Entity which wraps the UdbEntity, but is not in any way referenced in ListEntity.
You have two options here.
UdbEntity into an array of Entity, in which case you will be able to create slices of it. To do that, they need to have the same in-memory representation.Entity separately from UdbEntity and return them instead.Assuming the first approach is safe, I would go with that. If not, then the second one can work. In both cases arrays of Entity should be owned by ListEntityso that the memory is properly managed. I would probably ditch the PhantomData in Entity and simply return references to them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With