use core::marker::PhantomData;
use core::mem;
use objc2::encode::{EncodeArgument, EncodeReturn, Encoding, RefEncode};
use crate::ffi;
pub unsafe trait BlockArguments: Sized {
#[doc(hidden)]
unsafe fn __call_block<R: EncodeReturn>(
invoke: unsafe extern "C" fn(),
block: *mut Block<Self, R>,
args: Self,
) -> R;
}
macro_rules! block_args_impl {
($($a:ident: $t:ident),*) => (
unsafe impl<$($t: EncodeArgument),*> BlockArguments for ($($t,)*) {
#[inline]
unsafe fn __call_block<R: EncodeReturn>(
invoke: unsafe extern "C" fn(),
block: *mut Block<Self, R>,
($($a,)*): Self,
) -> R {
let invoke: unsafe extern "C" fn(*mut Block<Self, R> $(, $t)*) -> R = unsafe {
mem::transmute(invoke)
};
unsafe { invoke(block $(, $a)*) }
}
}
);
}
block_args_impl!();
block_args_impl!(a: A);
block_args_impl!(a: A, b: B);
block_args_impl!(a: A, b: B, c: C);
block_args_impl!(a: A, b: B, c: C, d: D);
block_args_impl!(a: A, b: B, c: C, d: D, e: E);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
block_args_impl!(
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K
);
block_args_impl!(
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K,
l: L
);
#[repr(C)]
pub struct Block<A, R> {
_inner: [u8; 0],
_layout: PhantomData<ffi::Block_layout>,
_p: PhantomData<fn(A) -> R>,
}
unsafe impl<A: BlockArguments, R: EncodeReturn> RefEncode for Block<A, R> {
const ENCODING_REF: Encoding = Encoding::Block;
}
impl<A: BlockArguments, R: EncodeReturn> Block<A, R> {
pub unsafe fn call(&self, args: A) -> R {
let ptr: *const Self = self;
let layout = unsafe { ptr.cast::<ffi::Block_layout>().as_ref().unwrap_unchecked() };
let invoke = layout.invoke.unwrap_or_else(|| unreachable!());
unsafe { A::__call_block(invoke, ptr as *mut Self, args) }
}
}