use std::os::raw::c_void;
use std::ptr::null_mut;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
#[derive(Debug)]
pub enum ListResult<T> {
Item(T),
End,
Error,
}
pub(crate) struct MultiUseCallback<ClosureProto: ?Sized, ProxyProto> {
saved: Option<*mut Box<ClosureProto>>,
proxy: PhantomData<*const ProxyProto>,
}
impl<ClosureProto: ?Sized, ProxyProto> Default for MultiUseCallback<ClosureProto, ProxyProto> {
#[inline(always)]
fn default() -> Self {
MultiUseCallback::<ClosureProto, ProxyProto> { saved: None, proxy: PhantomData }
}
}
impl<ClosureProto: ?Sized, ProxyProto> MultiUseCallback<ClosureProto, ProxyProto> {
#[inline]
pub fn new(cb: Option<Box<ClosureProto>>) -> Self {
match cb {
Some(f) => MultiUseCallback::<ClosureProto, ProxyProto> {
saved: Some(Box::into_raw(Box::new(f))),
proxy: PhantomData,
},
None => Default::default(),
}
}
#[inline]
pub fn get_capi_params(&self, proxy: ProxyProto) -> (Option<ProxyProto>, *mut c_void) {
match self.saved {
Some(ref f) => (Some(proxy), *f as *mut c_void),
None => (None, null_mut::<c_void>()),
}
}
#[inline(always)]
pub fn get_callback<'a>(ptr: *mut c_void) -> &'a mut Box<ClosureProto> {
assert!(!ptr.is_null());
unsafe { &mut *(ptr as *mut Box<ClosureProto>) }
}
}
impl<ClosureProto: ?Sized, ProxyProto> Drop for MultiUseCallback<ClosureProto, ProxyProto> {
#[inline]
fn drop(&mut self) {
if self.saved.is_some() {
let _to_drop = unsafe { Box::from_raw(self.saved.unwrap()) };
}
}
}
#[inline(always)]
pub(crate) fn box_closure_get_capi_ptr<ClosureProto: ?Sized>(callback: Box<ClosureProto>)
-> *mut c_void
{
Box::into_raw(Box::new(callback)) as *mut c_void
}
#[inline]
pub(crate) fn get_su_capi_params<ClosureProto: ?Sized, ProxyProto>(
callback: Option<Box<ClosureProto>>, proxy: ProxyProto) -> (Option<ProxyProto>, *mut c_void)
{
match callback {
Some(f) => (Some(proxy), box_closure_get_capi_ptr::<ClosureProto>(f)),
None => (None, null_mut::<c_void>()),
}
}
#[inline(always)]
pub(crate) fn get_su_callback<ClosureProto: ?Sized>(ptr: *mut c_void) -> Box<Box<ClosureProto>> {
assert!(!ptr.is_null());
unsafe { Box::from_raw(ptr as *mut Box<ClosureProto>) }
}
#[inline]
pub(crate) fn callback_for_list_instance<Item, ItemRaw, Conv>(i: *const ItemRaw, eol: i32,
userdata: *mut c_void, conv: Conv)
where Conv: Fn(*const ItemRaw) -> Item {
assert!(!userdata.is_null());
let mut callback = ManuallyDrop::new(unsafe {
Box::from_raw(userdata as *mut Box<dyn FnMut(ListResult<&Item>)>)
});
use std::ops::DerefMut;
#[allow(unused_mut)]
let mut callback_ref = callback.deref_mut();
match eol {
0 => {
assert!(!i.is_null());
let item = conv(i); (callback_ref)(ListResult::Item(&item));
return;
},
i if i > 0 => {
(callback_ref)(ListResult::End);
},
_ => {
(callback_ref)(ListResult::Error);
},
}
unsafe { ManuallyDrop::drop(&mut callback) };
}