#![no_std]
#![doc = include_str!("../README.md")]
#![cfg_attr(
feature = "nightly",
feature(unsize, fn_ptr_trait, unboxed_closures, fn_traits, tuple_trait)
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use alloc::boxed::Box;
use cc::{AsExtern, CallingConvention, IntoExtern, C};
use core::{ffi::c_void, marker::PhantomData, mem::ManuallyDrop};
use docfg::docfg;
extern crate alloc;
pub mod cc;
pub struct Closure<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention = C> {
f: T::Extern,
user_data: *mut c_void,
destructor: Option<Cc::Destructor>,
_phtm: PhantomData<T>,
}
impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> Closure<T, Cc> {
#[inline]
pub fn new<F: IntoExtern<T, Cc>>(f: F) -> Self {
return Box::new(f).into_extern();
}
#[inline]
pub unsafe fn from_extern(
f: T::Extern,
user_data: *mut c_void,
destructor: Option<Cc::Destructor>,
) -> Self {
return Self {
f,
user_data,
destructor,
_phtm: PhantomData,
};
}
pub fn into_parts(self) -> (*mut c_void, T::Extern, Option<Cc::Destructor>) {
let this = ManuallyDrop::new(self);
return (this.user_data, this.f, this.destructor);
}
#[inline(always)]
pub fn has_destructor(&self) -> bool {
return self.destructor.is_some();
}
#[inline(always)]
pub fn user_data(&self) -> *mut c_void {
return self.user_data;
}
#[inline(always)]
pub fn fn_ptr(&self) -> T::Extern {
return self.f;
}
#[inline(always)]
pub fn as_extern_parts(&self) -> (T::Extern, *mut c_void) {
return (self.fn_ptr(), self.user_data);
}
#[inline(always)]
pub fn call(&mut self, args: T::Args) -> T::Output {
unsafe { T::call_mut(self.f, args, self.user_data) }
}
}
#[docfg(feature = "nightly")]
impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> FnOnce<T::Args> for Closure<T, Cc>
where
T::Args: core::marker::Tuple,
{
type Output = <T as AsExtern<Cc>>::Output;
#[inline(always)]
extern "rust-call" fn call_once(self, args: T::Args) -> Self::Output {
unsafe { T::call_mut(self.f, args, self.user_data) }
}
}
#[docfg(feature = "nightly")]
impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> FnMut<T::Args> for Closure<T, Cc>
where
T::Args: core::marker::Tuple,
{
#[inline(always)]
extern "rust-call" fn call_mut(&mut self, args: T::Args) -> Self::Output {
unsafe { T::call_mut(self.f, args, self.user_data) }
}
}
impl<T: ?Sized + AsExtern<Cc>, Cc: CallingConvention> Drop for Closure<T, Cc> {
#[inline]
fn drop(&mut self) {
if let Some(f) = self.destructor.take() {
unsafe { Cc::destroy(f, self.user_data) }
}
}
}
unsafe impl<T: ?Sized + AsExtern<Cc> + Send, Cc: CallingConvention> Send for Closure<T, Cc> {}
unsafe impl<T: ?Sized + AsExtern<Cc> + Sync, Cc: CallingConvention> Sync for Closure<T, Cc> {}
#[doc(hidden)]
mod compile_fail {}