use std;
use capi;
use std::os::raw::c_void;
use std::rc::Rc;
use libc::timeval;
use super::events::io::{IoEvent, IoEventRef, IoEventInternal, IoEventFlagSet};
use super::events::timer::{TimeEvent, TimeEventRef, TimeEventInternal};
use super::events::deferred::{DeferEvent, DeferEventRef, DeferEventInternal};
use time::{UnixTs, MonotonicTs, Timeval, USEC_INVALID};
pub(crate) use capi::pa_mainloop_api as ApiInternal;
pub trait MainloopInternalType {}
pub trait MainloopInnerType {
type I: MainloopInternalType;
fn get_ptr(&self) -> *mut Self::I;
fn get_api(&self) -> &MainloopApi;
fn supports_rtclock(&self) -> bool;
}
pub struct MainloopInner<T>
where T: MainloopInternalType
{
pub ptr: *mut T,
pub api: *const MainloopApi,
pub dropfn: fn(&mut MainloopInner<T>),
pub supports_rtclock: bool,
}
impl<T> Drop for MainloopInner<T>
where T: MainloopInternalType
{
fn drop(&mut self) {
(self.dropfn)(self);
}
}
impl<T> MainloopInnerType for MainloopInner<T>
where T: MainloopInternalType
{
type I = T;
fn get_ptr(&self) -> *mut T {
self.ptr
}
fn get_api(&self) -> &MainloopApi {
assert!(!self.api.is_null());
unsafe { &*self.api }
}
fn supports_rtclock(&self) -> bool {
self.supports_rtclock
}
}
pub trait Mainloop {
type MI: MainloopInnerType;
fn inner(&self) -> Rc<Self::MI>;
fn new_io_event(&mut self, fd: i32, events: IoEventFlagSet,
mut callback: Box<dyn FnMut(IoEventRef<Self::MI>, i32, IoEventFlagSet) + 'static>)
-> Option<IoEvent<Self::MI>>
{
let inner_for_wrapper = self.inner();
let wrapper_cb = Box::new(move |ptr, fd, flags| {
let ref_obj = IoEventRef::<Self::MI>::from_raw(ptr, Rc::clone(&inner_for_wrapper));
callback(ref_obj, fd, flags);
});
let to_save = super::events::io::EventCb::new(Some(wrapper_cb));
let (cb_fn, cb_data) = to_save.get_capi_params(super::events::io::event_cb_proxy);
let inner = self.inner();
let api = inner.get_api();
let fn_ptr = api.io_new.unwrap();
let ptr = fn_ptr(api, fd, events, cb_fn, cb_data);
match ptr.is_null() {
false => Some(IoEvent::<Self::MI>::from_raw(ptr, Rc::clone(&inner), to_save)),
true => None,
}
}
fn new_timer_event(&mut self, tv: &UnixTs,
mut callback: Box<dyn FnMut(TimeEventRef<Self::MI>) + 'static>)
-> Option<TimeEvent<Self::MI>>
{
let inner_for_wrapper = self.inner();
let wrapper_cb = Box::new(move |ptr| {
let ref_obj = TimeEventRef::<Self::MI>::from_raw(ptr, Rc::clone(&inner_for_wrapper));
callback(ref_obj);
});
let to_save = super::events::timer::EventCb::new(Some(wrapper_cb));
let (cb_fn, cb_data) = to_save.get_capi_params(super::events::timer::event_cb_proxy);
let inner = self.inner();
let api = inner.get_api();
let fn_ptr = api.time_new.unwrap();
let ptr = fn_ptr(api, &(tv.0).0, cb_fn, cb_data);
match ptr.is_null() {
false => Some(TimeEvent::<Self::MI>::from_raw(ptr, Rc::clone(&inner), to_save)),
true => None,
}
}
fn new_timer_event_rt(&mut self, t: MonotonicTs,
mut callback: Box<dyn FnMut(TimeEventRef<Self::MI>) + 'static>)
-> Option<TimeEvent<Self::MI>>
{
assert_ne!(t.0, USEC_INVALID);
let inner_for_wrapper = self.inner();
let wrapper_cb = Box::new(move |ptr| {
let ref_obj = TimeEventRef::<Self::MI>::from_raw(ptr, Rc::clone(&inner_for_wrapper));
callback(ref_obj);
});
let to_save = super::events::timer::EventCb::new(Some(wrapper_cb));
let (cb_fn, cb_data) = to_save.get_capi_params(super::events::timer::event_cb_proxy);
let inner = self.inner();
let mut tv = Timeval::new_zero();
tv.set_rt(t.0, inner.supports_rtclock());
let api = inner.get_api();
let fn_ptr = api.time_new.unwrap();
let ptr = fn_ptr(api, &tv.0, cb_fn, cb_data);
match ptr.is_null() {
false => Some(TimeEvent::<Self::MI>::from_raw(ptr, Rc::clone(&inner), to_save)),
true => None,
}
}
fn new_deferred_event(&mut self,
mut callback: Box<dyn FnMut(DeferEventRef<Self::MI>) + 'static>)
-> Option<DeferEvent<Self::MI>>
{
let inner_for_wrapper = self.inner();
let wrapper_cb = Box::new(move |ptr| {
let ref_obj = DeferEventRef::<Self::MI>::from_raw(ptr, Rc::clone(&inner_for_wrapper));
callback(ref_obj);
});
let to_save = super::events::deferred::EventCb::new(Some(wrapper_cb));
let (cb_fn, cb_data) = to_save.get_capi_params(super::events::deferred::event_cb_proxy);
let inner = self.inner();
let api = inner.get_api();
let fn_ptr = api.defer_new.unwrap();
let ptr = fn_ptr(api, cb_fn, cb_data);
match ptr.is_null() {
false => Some(DeferEvent::<Self::MI>::from_raw(ptr, Rc::clone(&inner), to_save)),
true => None,
}
}
fn once_event(&mut self, callback: Box<dyn FnMut() + 'static>) {
let (cb_fn, cb_data): (Option<extern "C" fn(_, _)>, _) =
::callbacks::get_su_capi_params::<_, _>(Some(callback), once_cb_proxy);
let inner = self.inner();
let api = inner.get_api();
unsafe { capi::pa_mainloop_api_once(api.as_ref(), cb_fn, cb_data) };
}
fn quit(&mut self, retval: ::def::Retval) {
let inner = self.inner();
let api = inner.get_api();
let fn_ptr = api.quit.unwrap();
fn_ptr(api, retval.0);
}
}
pub type IoEventCb = extern "C" fn(a: *const MainloopApi, e: *mut IoEventInternal, fd: i32,
events: IoEventFlagSet, userdata: *mut c_void);
pub type IoEventDestroyCb = extern "C" fn(a: *const MainloopApi, e: *mut IoEventInternal,
userdata: *mut c_void);
pub type TimeEventCb = extern "C" fn(a: *const MainloopApi, e: *mut TimeEventInternal,
tv: *const timeval, userdata: *mut c_void);
pub type TimeEventDestroyCb = extern "C" fn(a: *const MainloopApi, e: *mut TimeEventInternal,
userdata: *mut c_void);
pub type DeferEventCb = extern "C" fn(a: *const MainloopApi, e: *mut DeferEventInternal,
userdata: *mut c_void);
pub type DeferEventDestroyCb = extern "C" fn(a: *const MainloopApi, e: *mut DeferEventInternal,
userdata: *mut c_void);
#[repr(C)]
pub struct MainloopApi {
pub userdata: *mut c_void,
pub io_new: Option<extern "C" fn(a: *const MainloopApi, fd: i32, events: IoEventFlagSet,
cb: Option<IoEventCb>, userdata: *mut c_void) -> *mut IoEventInternal>,
pub io_enable: Option<extern "C" fn(e: *mut IoEventInternal, events: IoEventFlagSet)>,
pub io_free: Option<extern "C" fn(e: *mut IoEventInternal)>,
pub io_set_destroy: Option<extern "C" fn(e: *mut IoEventInternal, cb: Option<IoEventDestroyCb>)>,
pub time_new: Option<extern "C" fn(a: *const MainloopApi, tv: *const timeval,
cb: Option<TimeEventCb>, userdata: *mut c_void) -> *mut TimeEventInternal>,
pub time_restart: Option<extern "C" fn(e: *mut TimeEventInternal, tv: *const timeval)>,
pub time_free: Option<extern "C" fn(e: *mut TimeEventInternal)>,
pub time_set_destroy: Option<extern "C" fn(e: *mut TimeEventInternal,
cb: Option<TimeEventDestroyCb>)>,
pub defer_new: Option<extern "C" fn(a: *const MainloopApi, cb: Option<DeferEventCb>,
userdata: *mut c_void) -> *mut DeferEventInternal>,
pub defer_enable: Option<extern "C" fn(e: *mut DeferEventInternal, b: i32)>,
pub defer_free: Option<extern "C" fn(e: *mut DeferEventInternal)>,
pub defer_set_destroy: Option<extern "C" fn(e: *mut DeferEventInternal,
cb: Option<DeferEventDestroyCb>)>,
pub quit: Option<extern "C" fn(a: *const MainloopApi, retval: ::def::RetvalActual)>,
}
#[test]
fn api_compare_capi(){
assert_eq!(std::mem::size_of::<ApiInternal>(), std::mem::size_of::<capi::pa_mainloop_api>());
assert_eq!(std::mem::align_of::<ApiInternal>(), std::mem::align_of::<capi::pa_mainloop_api>());
}
impl AsRef<capi::pa_mainloop_api> for MainloopApi {
#[inline]
fn as_ref(&self) -> &capi::pa_mainloop_api {
unsafe { &*(self as *const Self as *const capi::pa_mainloop_api) }
}
}
impl<'a> From<*const ApiInternal> for &'a MainloopApi {
#[inline]
fn from(a: *const ApiInternal) -> Self {
unsafe { std::mem::transmute(a) }
}
}
impl<'a> From<&'a MainloopApi> for *const ApiInternal {
#[inline]
fn from(a: &'a MainloopApi) -> Self {
unsafe { std::mem::transmute(a) }
}
}
extern "C"
fn once_cb_proxy(_: *const ApiInternal, userdata: *mut c_void) {
let _ = std::panic::catch_unwind(|| {
let mut callback = ::callbacks::get_su_callback::<dyn FnMut()>(userdata);
(callback)();
});
}