I have an external library (e.g. libcisland.so) with interface like this:
size_t lib_handle_size();
typedef void* handle;
int lib_init(handle h);
int lib_store(handle h, int value);
int lib_restore(handle h, int *pvalue);
The user of this library is expected to do following:
// allocate some buffer in client address space
handle h = malloc(lib_handle_size());
// pass this buffer to library for initialization
if (lib_init(h)) { /* handle errors */ }
// library initializes this handle by some opaque fashion
// then user uses it
lib_store(h,42);
int r;
lib_restore(h,&r);
// after all work is done, user frees this handle
free(h);
I can't figure out how to properly wrap this interface to Rust. This is what I ended up:
pub struct Island {
h: Handle,
v: Vec<u8>,
}
impl Island {
pub fn new() -> Island {
let len = unsafe { lib_handle_size() };
let mut v: Vec<u8> = Vec::with_capacity(len);
let h: Handle = v.as_mut_ptr();
Island { v:v, h:h, }
}
pub fn store(&mut self, v: i32) {
unsafe { lib_store(self.h, v); }
}
pub fn restore(&mut self) -> i32 {
let mut v = 0;
unsafe { lib_restore(self.h, &mut v); }
v
}
}
impl Drop for Island {
fn drop(&mut self) {
drop(&mut self.v);
}
}
/// unsafe part
use libc::size_t;
pub type Handle = *mut u8;
#[link(name="cisland")]
extern {
pub fn lib_handle_size() -> size_t;
pub fn lib_init(h: Handle) -> i32;
pub fn lib_store(h: Handle, value: i32) -> i32;
pub fn lib_restore(h: Handle, pvalue: &mut i32) -> i32;
}
Is it Ok to use Vec(u8)
for this purpose? Is this Drop
trait implemented properly?
Is it Ok to use Vec(u8) for this purpose?
I think Vec<u8>
is ok, but you should initialize it rather than using a zero-length vector, pointing at uninitialized memory. It would also be more robust to use Box<[u8]>
because that will enforce that it can't be reallocated accidentally.
Is this Drop trait implemented properly?
It should not be necessary to implement Drop
at all. The fields of Island
each will drop correctly anyway.
Rather than store the handle, I would get it each time using a method. Then your struct is much simpler.
use libc::c_void;
pub struct Island {
buf: Box<[u8]>,
}
impl Island {
pub fn new() -> Island {
let len = unsafe { lib_handle_size() };
let v: Vec<u8> = vec![0; len];
Island { buf: v.into_boxed_slice() }
}
pub fn store(&mut self, v: i32) {
unsafe { lib_store(self.handle_mut(), v); }
}
pub fn restore(&mut self) -> i32 {
let mut v = 0;
unsafe { lib_restore(self.handle_mut(), &mut v); }
v
}
fn handle_mut(&mut self) -> *mut c_void {
self.buf.as_mut_ptr() as *mut c_void
}
}
You don't need a Drop
implementation because the Box
will drop automatically when it goes out of scope (as would a Vec
).
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