use core::mem;
use core::ptr;
use objc2::encode::EncodeArguments;
use objc2::encode::{EncodeArgument, EncodeReturn};
use crate::{Block, StackBlock};
mod private {
pub trait Sealed<A, R> {}
}
pub unsafe trait BlockFn: private::Sealed<Self::Args, Self::Output> {
type Args: EncodeArguments;
type Output: EncodeReturn;
#[doc(hidden)]
unsafe fn __call_block(
invoke: unsafe extern "C" fn(),
block: *mut Block<Self>,
args: Self::Args,
) -> Self::Output;
}
pub unsafe trait IntoBlock<'f, A, R>: private::Sealed<A, R>
where
A: EncodeArguments,
R: EncodeReturn,
{
type Dyn: ?Sized + BlockFn<Args = A, Output = R>;
#[doc(hidden)]
fn __get_invoke_stack_block() -> unsafe extern "C" fn();
}
macro_rules! impl_traits {
($($a:ident: $t:ident),*) => (
impl<$($t: EncodeArgument,)* R: EncodeReturn, Closure> private::Sealed<($($t,)*), R> for Closure
where
Closure: ?Sized + Fn($($t),*) -> R,
{}
unsafe impl<$($t: EncodeArgument,)* R: EncodeReturn> BlockFn for dyn Fn($($t),*) -> R + '_ {
type Args = ($($t,)*);
type Output = R;
#[inline]
unsafe fn __call_block(
invoke: unsafe extern "C" fn(),
block: *mut Block<Self>,
($($a,)*): Self::Args,
) -> Self::Output {
let invoke: unsafe extern "C" fn(*mut Block<Self> $(, $t)*) -> R = unsafe {
mem::transmute(invoke)
};
unsafe { invoke(block $(, $a)*) }
}
}
unsafe impl<'f, $($t,)* R, Closure> IntoBlock<'f, ($($t,)*), R> for Closure
where
$($t: EncodeArgument,)*
R: EncodeReturn,
Closure: Fn($($t),*) -> R + 'f,
{
type Dyn = dyn Fn($($t),*) -> R + 'f;
#[inline]
fn __get_invoke_stack_block() -> unsafe extern "C" fn() {
unsafe extern "C" fn invoke<'f, $($t,)* R, Closure>(
block: *mut StackBlock<'f, ($($t,)*), R, Closure>,
$($a: $t,)*
) -> R
where
Closure: Fn($($t),*) -> R + 'f
{
let closure = unsafe { &*ptr::addr_of!((*block).closure) };
(closure)($($a),*)
}
unsafe {
mem::transmute::<
unsafe extern "C" fn(*mut StackBlock<'f, ($($t,)*), R, Closure>, $($t,)*) -> R,
unsafe extern "C" fn(),
>(invoke)
}
}
}
);
}
impl_traits!();
impl_traits!(t0: T0);
impl_traits!(t0: T0, t1: T1);
impl_traits!(t0: T0, t1: T1, t2: T2);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, t10: T10);
impl_traits!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, t10: T10, t11: T11);