use std::io;
use std::mem::MaybeUninit;
use std::os::raw::{c_int, c_void};
#[cfg(unix)]
use std::os::unix::io::RawFd;
#[cfg(windows)]
use std::os::windows::io::RawHandle;
use libxev_sys as sys;
use crate::Loop;
use crate::watcher::{CbAction, Completion, CompletionRef, LoopRef, trampoline};
use super::completion::{CompletionExt, trampoline_isize};
pub struct File {
raw: Box<sys::xev_watcher>,
}
unsafe impl Send for File {}
fn decode_rw(result: isize) -> io::Result<usize> {
if result >= 0 {
Ok(result as usize)
} else {
Err(io::Error::from_raw_os_error((-result) as i32))
}
}
impl File {
#[cfg(unix)]
pub fn new(fd: RawFd) -> io::Result<Self> {
let fd_word = fd as isize as usize;
Self::from_handle_word(fd_word)
}
#[cfg(windows)]
pub fn new(handle: RawHandle) -> io::Result<Self> {
Self::from_handle_word(handle as usize)
}
fn from_handle_word(handle: usize) -> io::Result<Self> {
let mut raw: Box<MaybeUninit<sys::xev_watcher>> = Box::new(MaybeUninit::zeroed());
let rc = unsafe { sys::xev_file_init(raw.as_mut_ptr(), handle) };
if rc != 0 {
return Err(io::Error::from_raw_os_error(rc));
}
let raw: Box<sys::xev_watcher> = unsafe { Box::from_raw(Box::into_raw(raw).cast()) };
Ok(Self { raw })
}
pub fn as_raw(&mut self) -> *mut sys::xev_watcher {
&mut *self.raw
}
pub fn close<F>(&mut self, ev: &mut Loop, c: &mut Completion, cb: F)
where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, io::Result<()>) -> CbAction
+ Send
+ 'static,
{
let mut cb = cb;
let wrapped = move |lr: &mut LoopRef<'_>, cr: &mut CompletionRef<'_>, result: c_int| {
let r = if result == 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(result))
};
cb(lr, cr, r)
};
let userdata = c.install_callback(wrapped);
unsafe {
sys::xev_file_close(
self.as_raw(),
ev.as_raw(),
c.as_raw(),
userdata,
Some(trampoline),
);
}
}
pub unsafe fn read_raw<F>(
&mut self,
ev: &mut Loop,
c: &mut Completion,
buf: *mut u8,
len: usize,
cb: F,
) where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, io::Result<usize>) -> CbAction
+ Send
+ 'static,
{
let mut cb = cb;
let wrapped = move |lr: &mut LoopRef<'_>, cr: &mut CompletionRef<'_>, result: isize| {
cb(lr, cr, decode_rw(result))
};
let userdata = c.install_callback_isize(wrapped);
unsafe {
sys::xev_file_read(
self.as_raw(),
ev.as_raw(),
c.as_raw(),
buf as *mut c_void,
len,
userdata,
Some(trampoline_isize),
);
}
}
pub unsafe fn pread_raw<F>(
&mut self,
ev: &mut Loop,
c: &mut Completion,
buf: *mut u8,
len: usize,
offset: u64,
cb: F,
) where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, io::Result<usize>) -> CbAction
+ Send
+ 'static,
{
let mut cb = cb;
let wrapped = move |lr: &mut LoopRef<'_>, cr: &mut CompletionRef<'_>, result: isize| {
cb(lr, cr, decode_rw(result))
};
let userdata = c.install_callback_isize(wrapped);
unsafe {
sys::xev_file_pread(
self.as_raw(),
ev.as_raw(),
c.as_raw(),
buf as *mut c_void,
len,
offset,
userdata,
Some(trampoline_isize),
);
}
}
pub unsafe fn write_raw<F>(
&mut self,
ev: &mut Loop,
c: &mut Completion,
buf: *const u8,
len: usize,
cb: F,
) where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, io::Result<usize>) -> CbAction
+ Send
+ 'static,
{
let mut cb = cb;
let wrapped = move |lr: &mut LoopRef<'_>, cr: &mut CompletionRef<'_>, result: isize| {
cb(lr, cr, decode_rw(result))
};
let userdata = c.install_callback_isize(wrapped);
unsafe {
sys::xev_file_write(
self.as_raw(),
ev.as_raw(),
c.as_raw(),
buf as *const c_void,
len,
userdata,
Some(trampoline_isize),
);
}
}
pub unsafe fn pwrite_raw<F>(
&mut self,
ev: &mut Loop,
c: &mut Completion,
buf: *const u8,
len: usize,
offset: u64,
cb: F,
) where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, io::Result<usize>) -> CbAction
+ Send
+ 'static,
{
let mut cb = cb;
let wrapped = move |lr: &mut LoopRef<'_>, cr: &mut CompletionRef<'_>, result: isize| {
cb(lr, cr, decode_rw(result))
};
let userdata = c.install_callback_isize(wrapped);
unsafe {
sys::xev_file_pwrite(
self.as_raw(),
ev.as_raw(),
c.as_raw(),
buf as *const c_void,
len,
offset,
userdata,
Some(trampoline_isize),
);
}
}
pub fn read_owned<F>(&mut self, ev: &mut Loop, c: &mut Completion, mut buf: Vec<u8>, cb: F)
where
F: FnOnce(&mut LoopRef<'_>, &mut CompletionRef<'_>, io::Result<Vec<u8>>) -> CbAction
+ Send
+ 'static,
{
let cap = buf.capacity();
let ptr = buf.as_mut_ptr();
let mut buf_holder = Some(buf);
let mut cb_holder = Some(cb);
unsafe {
self.read_raw(ev, c, ptr, cap, move |lr, cr, r| {
let cb = cb_holder.take().expect("read_owned callback fired twice");
let mut buf = buf_holder.take().expect("read_owned buffer taken twice");
let r = r.map(|n| {
buf.set_len(n);
buf
});
cb(lr, cr, r)
});
}
}
pub fn write_owned<F>(&mut self, ev: &mut Loop, c: &mut Completion, buf: Vec<u8>, cb: F)
where
F: FnOnce(&mut LoopRef<'_>, &mut CompletionRef<'_>, Vec<u8>, io::Result<usize>) -> CbAction
+ Send
+ 'static,
{
let ptr = buf.as_ptr();
let len = buf.len();
let mut buf_holder = Some(buf);
let mut cb_holder = Some(cb);
unsafe {
self.write_raw(ev, c, ptr, len, move |lr, cr, r| {
let cb = cb_holder.take().expect("write_owned callback fired twice");
let buf = buf_holder.take().expect("write_owned buffer taken twice");
cb(lr, cr, buf, r)
});
}
}
}
impl Drop for File {
fn drop(&mut self) {
unsafe { sys::xev_file_deinit(&mut *self.raw) };
}
}