use std::os::raw::c_void;
use std::ptr::null_mut;
use crate::callbacks;
use capi::pa_operation as OperationInternal;
pub use capi::pa_operation_state_t as State;
pub struct Operation<ClosureProto: ?Sized> {
ptr: *mut OperationInternal,
saved_cb: Option<*mut Box<ClosureProto>>,
state_cb: NotifyCb,
}
unsafe impl<ClosureProto: ?Sized> Send for Operation<ClosureProto> {}
unsafe impl<ClosureProto: ?Sized> Sync for Operation<ClosureProto> {}
type NotifyCb = callbacks::MultiUseCallback<dyn FnMut(),
extern "C" fn(*mut OperationInternal, *mut c_void)>;
impl<ClosureProto: ?Sized> Operation<ClosureProto> {
pub(crate) fn from_raw(ptr: *mut OperationInternal, saved_cb: *mut Box<ClosureProto>) -> Self {
assert!(!ptr.is_null());
let saved_cb_actual = match saved_cb.is_null() {
true => Some(saved_cb),
false => None,
};
Self { ptr: ptr, saved_cb: saved_cb_actual, state_cb: Default::default() }
}
pub fn cancel(&mut self) {
unsafe { capi::pa_operation_cancel(self.ptr); }
let callback = self.saved_cb.take();
if let Some(ptr) = callback {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr as *mut Box<ClosureProto>) });
}
}
}
#[inline]
pub fn get_state(&self) -> State {
unsafe { capi::pa_operation_get_state(self.ptr) }
}
pub fn set_state_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
let saved = &mut self.state_cb;
*saved = NotifyCb::new(callback);
let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
unsafe { capi::pa_operation_set_state_callback(self.ptr, cb_fn, cb_data); }
}
}
impl<ClosureProto: ?Sized> Drop for Operation<ClosureProto> {
fn drop(&mut self) {
unsafe { capi::pa_operation_unref(self.ptr) };
self.ptr = null_mut::<OperationInternal>();
}
}
extern "C"
fn notify_cb_proxy(_: *mut OperationInternal, userdata: *mut c_void) {
let _ = std::panic::catch_unwind(|| {
let callback = NotifyCb::get_callback(userdata);
(callback)();
});
}