use std::ffi::c_void;
use std::io;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::os::raw::c_int;
use libxev_sys as sys;
use crate::Loop;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CbAction {
Disarm,
Rearm,
}
impl CbAction {
pub(crate) fn to_raw(self) -> sys::xev_cb_action {
match self {
CbAction::Disarm => sys::xev_cb_action_XEV_DISARM,
CbAction::Rearm => sys::xev_cb_action_XEV_REARM,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionState {
Dead,
Active,
}
impl CompletionState {
fn from_raw(v: sys::xev_completion_state_t) -> Self {
if v == sys::xev_completion_state_t_XEV_COMPLETION_ACTIVE {
CompletionState::Active
} else {
CompletionState::Dead
}
}
}
pub struct LoopRef<'a> {
raw: *mut sys::xev_loop,
_marker: PhantomData<&'a mut Loop>,
}
impl<'a> LoopRef<'a> {
pub(crate) unsafe fn from_raw(raw: *mut sys::xev_loop) -> Self {
Self {
raw,
_marker: PhantomData,
}
}
pub fn now(&self) -> i64 {
unsafe { sys::xev_loop_now(self.raw) }
}
pub fn update_now(&mut self) {
unsafe { sys::xev_loop_update_now(self.raw) }
}
pub fn as_raw(&mut self) -> *mut sys::xev_loop {
self.raw
}
}
pub struct CompletionRef<'a> {
raw: *mut sys::xev_completion,
_marker: PhantomData<&'a mut Completion>,
}
impl<'a> CompletionRef<'a> {
pub(crate) unsafe fn from_raw(raw: *mut sys::xev_completion) -> Self {
Self {
raw,
_marker: PhantomData,
}
}
pub fn state(&mut self) -> CompletionState {
CompletionState::from_raw(unsafe { sys::xev_completion_state(self.raw) })
}
pub fn as_raw(&mut self) -> *mut sys::xev_completion {
self.raw
}
}
struct CallbackOwner {
ptr: *mut (),
drop_fn: unsafe fn(*mut ()),
}
impl Drop for CallbackOwner {
fn drop(&mut self) {
unsafe { (self.drop_fn)(self.ptr) };
}
}
pub struct Completion {
raw: Box<sys::xev_completion>,
callback: Option<CallbackOwner>,
}
unsafe impl Send for Completion {}
impl Completion {
pub fn new() -> Self {
let raw: Box<MaybeUninit<sys::xev_completion>> = Box::new(MaybeUninit::zeroed());
let raw: Box<sys::xev_completion> = unsafe { Box::from_raw(Box::into_raw(raw).cast()) };
Self {
raw,
callback: None,
}
}
pub fn zero(&mut self) {
unsafe { sys::xev_completion_zero(&mut *self.raw) };
self.callback = None;
}
pub fn state(&mut self) -> CompletionState {
CompletionState::from_raw(unsafe { sys::xev_completion_state(&mut *self.raw) })
}
pub fn as_raw(&mut self) -> *mut sys::xev_completion {
&mut *self.raw
}
pub(crate) fn install_callback<F>(&mut self, cb: F) -> *mut c_void
where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, c_int) -> CbAction + Send + 'static,
{
let inner: Box<DynCb> = Box::new(cb);
let outer: Box<Box<DynCb>> = Box::new(inner);
let ptr = Box::into_raw(outer) as *mut ();
self.set_callback_owner(ptr, drop_dyn_cb);
ptr as *mut c_void
}
pub(crate) fn set_callback_owner(&mut self, ptr: *mut (), drop_fn: unsafe fn(*mut ())) {
self.callback = Some(CallbackOwner { ptr, drop_fn });
}
}
impl Default for Completion {
fn default() -> Self {
Self::new()
}
}
type DynCb = dyn FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, c_int) -> CbAction + Send;
unsafe fn drop_dyn_cb(ptr: *mut ()) {
let _ = unsafe { Box::from_raw(ptr as *mut Box<DynCb>) };
}
pub(crate) unsafe extern "C" fn trampoline(
l: *mut sys::xev_loop,
c: *mut sys::xev_completion,
result: c_int,
userdata: *mut c_void,
) -> sys::xev_cb_action {
let cb = unsafe { &mut *(userdata as *mut Box<DynCb>) };
let mut lr = unsafe { LoopRef::from_raw(l) };
let mut cr = unsafe { CompletionRef::from_raw(c) };
cb(&mut lr, &mut cr, result).to_raw()
}
pub struct Timer {
raw: Box<sys::xev_watcher>,
}
impl Timer {
pub fn new() -> io::Result<Self> {
let mut raw: Box<MaybeUninit<sys::xev_watcher>> = Box::new(MaybeUninit::zeroed());
let rc = unsafe { sys::xev_timer_init(raw.as_mut_ptr()) };
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 run<F>(&mut self, ev: &mut Loop, c: &mut Completion, next_ms: u64, cb: F)
where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, c_int) -> CbAction + Send + 'static,
{
let userdata = c.install_callback(cb);
unsafe {
sys::xev_timer_run(
&mut *self.raw,
ev.as_raw(),
&mut *c.raw,
next_ms,
userdata,
Some(trampoline),
);
}
}
pub fn reset<F>(
&mut self,
ev: &mut Loop,
c: &mut Completion,
c_cancel: &mut Completion,
next_ms: u64,
cb: F,
) where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, c_int) -> CbAction + Send + 'static,
{
let userdata = c.install_callback(cb);
unsafe {
sys::xev_timer_reset(
&mut *self.raw,
ev.as_raw(),
&mut *c.raw,
&mut *c_cancel.raw,
next_ms,
userdata,
Some(trampoline),
);
}
}
pub fn cancel<F>(
&mut self,
ev: &mut Loop,
c_timer: &mut Completion,
c_cancel: &mut Completion,
cb: F,
) where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, c_int) -> CbAction + Send + 'static,
{
let userdata = c_cancel.install_callback(cb);
unsafe {
sys::xev_timer_cancel(
&mut *self.raw,
ev.as_raw(),
&mut *c_timer.raw,
&mut *c_cancel.raw,
userdata,
Some(trampoline),
);
}
}
}
impl Drop for Timer {
fn drop(&mut self) {
unsafe { sys::xev_timer_deinit(&mut *self.raw) };
}
}
pub struct Async {
raw: Box<sys::xev_watcher>,
}
unsafe impl Send for Async {}
unsafe impl Sync for Async {}
impl Async {
pub fn new() -> io::Result<Self> {
let mut raw: Box<MaybeUninit<sys::xev_watcher>> = Box::new(MaybeUninit::zeroed());
let rc = unsafe { sys::xev_async_init(raw.as_mut_ptr()) };
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 notify(&self) -> io::Result<()> {
let p = (&*self.raw as *const sys::xev_watcher) as *mut sys::xev_watcher;
let rc = unsafe { sys::xev_async_notify(p) };
if rc != 0 {
return Err(io::Error::from_raw_os_error(rc));
}
Ok(())
}
pub fn wait<F>(&mut self, ev: &mut Loop, c: &mut Completion, cb: F)
where
F: FnMut(&mut LoopRef<'_>, &mut CompletionRef<'_>, c_int) -> CbAction + Send + 'static,
{
let userdata = c.install_callback(cb);
unsafe {
sys::xev_async_wait(
&mut *self.raw,
ev.as_raw(),
&mut *c.raw,
userdata,
Some(trampoline),
);
}
}
}
impl Drop for Async {
fn drop(&mut self) {
unsafe { sys::xev_async_deinit(&mut *self.raw) };
}
}