I'm trying to write a wrapper for the epoll Linux API. I forked this repository, but this crate doesn't use the union
type used by the epoll
API. I decided to use Rust's C union feature to create a complete wrapper where user will not need to use unsafe code.
This union causes me some trouble.
How could I lock the used type of the union to one type at compile time? epoll's union can't be differentiated; you can only use one member of the union by epoll fd. Well, you can but that will not be safe.
The user could use an enum type as the ptr
field of the union to use multiple types but this will be safe because it will use Rust's enum
.
I searched with "generic" or "macro" but I can't find any way that will fit my will.
extern crate libc;
#[derive(Clone, Copy)]
pub union Data {
pub ptr: *mut libc::c_void,
pub fd: std::os::unix::io::RawFd,
pub u32: libc::uint32_t,
pub u64: libc::uint64_t,
}
#[repr(C)]
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct Event {
pub data: Data,
}
impl Event {
fn new(data: Data) -> Event {
Event { data: data }
}
}
fn main() {
let event = Event::new(Data {
ptr: Box::into_raw(Box::new(42)) as *mut libc::c_void,
});
unsafe { Box::from_raw(event.data.ptr) };
}
I would like something like that:
fn main() {
let event = event!(ptr, Box::new(42));
let _ = event.ptr();
let _ = event.fd(); // fails to compile; we can only use ptr
}
My fork can be found here. I don't know what macro, generic or other could be the suitable solution. You can look at my code, especially the integration test, there is a lot of unsafe code, I want to remove as much as possible of unsafe code from user side. Currently it looks very ugly.