#![doc(hidden)]
use crate::ndarray;
use core::any::type_name;
#[allow(non_snake_case)]
pub trait FunctionTraits<F, Args> {
fn invoke(fp: F, mode: u32, ndarray_value_bit: u32, buffer: *mut u8);
}
fn is_pointer<T>() -> bool {
type_name::<T>().starts_with("*mut ") || type_name::<T>().starts_with("*const ")
}
fn is_ndarray<T>() -> bool {
type_name::<T>().contains("::NDArray<")
}
unsafe fn read_arg<T1>(
buffer: *const u8,
offset: usize,
mode: u32,
ndarray_value_bit: u32,
) -> (T1, usize)
where
T1: Copy,
{
let ptr_array = buffer as *const usize;
let raw_addr = *ptr_array.add(offset);
let is_ptr = is_pointer::<T1>();
let is_ndarray_bit = ((ndarray_value_bit >> offset) & 1) != 0;
let read_ndarray = |raw: usize| -> *const T1 {
let arr = raw as *const ndarray::NDArray<u8>;
let data_ptr = unsafe { (&*arr).data() };
if !is_ptr && !mode_is_normal(mode) && !is_ndarray::<T1>() {
unsafe { *(data_ptr as *const *const T1) }
} else if is_ptr && !is_ndarray::<T1>() {
data_ptr as *const T1
} else {
unsafe { *(raw_addr as *const *const T1) }
}
};
let arg_ptr: *const T1 = if is_ndarray_bit {
read_ndarray(raw_addr)
} else if !is_ptr && !mode_is_normal(mode) {
unsafe { *(raw_addr as *const *const T1) }
} else {
raw_addr as *const T1
};
let value = *arg_ptr;
(value, offset + 1)
}
pub struct CallHelper;
#[inline(always)]
fn mode_is_normal(mode: u32) -> bool {
mode == 0
}
macro_rules! impl_function_traits {
() => {
impl FunctionTraits<extern "C" fn(), ()> for CallHelper {
fn invoke(fp: extern "C" fn(), _mode: u32, _ndarray_value_bit: u32, _buffer: *mut u8) {
fp();
}
}
};
($($T:ident),*) => {
#[allow(unused_parens)]
impl<$($T: Copy + 'static),*> FunctionTraits<extern "C" fn($($T),*), ($($T),*)> for CallHelper {
fn invoke(fp: extern "C" fn($($T),*), mode: u32, ndarray_value_bit: u32, buffer: *mut u8) {
unsafe {
let buf = buffer as *const u8;
let mut _offset = 0;
$(
let (arg, new_offset) = read_arg::<$T>(buf, _offset, mode, ndarray_value_bit);
_offset = new_offset;
let $T = arg;
)*
fp($($T),*);
}
}
}
};
}
#[allow(non_snake_case)]
mod impls {
use super::*;
impl_function_traits!();
impl_function_traits!(T1);
impl_function_traits!(T1, T2);
impl_function_traits!(T1, T2, T3);
impl_function_traits!(T1, T2, T3, T4);
impl_function_traits!(T1, T2, T3, T4, T5);
impl_function_traits!(T1, T2, T3, T4, T5, T6);
impl_function_traits!(T1, T2, T3, T4, T5, T6, T7);
impl_function_traits!(T1, T2, T3, T4, T5, T6, T7, T8);
impl_function_traits!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
}
pub fn call_main<FP, Args>(func: FP, mode: u32, ndarray_value_bit: u32, buffer: *mut u8)
where
CallHelper: FunctionTraits<FP, Args>,
{
CallHelper::invoke(func, mode, ndarray_value_bit, buffer);
}