vrust 0.0.1

VRust game engine
use std::mem;
use std::any::Any;
use super::Id;
use super::objc::runtime::{Class, Object, Sel};
use super::objc::MessageArguments;

type Imp = unsafe extern "C" fn();

#[cfg(all(any(target_os = "macos", target_os = "ios"), target_arch = "x86_64"))]
fn msg_send_fn<R>(obj: Id, _: Sel) -> (Imp, Id) {
    extern "C" {
        fn objc_msgSend();
        fn objc_msgSend_stret();
    }
    let msg_fn = if mem::size_of::<R>() <= 16 {
        objc_msgSend
    } else {
        objc_msgSend_stret
    };
    (msg_fn, obj)
}


#[cfg(all(any(target_os = "macos", target_os = "ios"), target_arch = "aarch64"))]
fn msg_send_fn<R>(obj: Id, _: Sel) -> (Imp, Id) {
    extern "C" {
        fn objc_msgSend();
    }
    (objc_msgSend, obj)
}

#[cfg(all(any(target_os = "macos", target_os = "ios"), target_arch = "arm"))]
fn msg_send_fn<R: Any>(obj: Id, _: Sel) -> (Imp, Id) {
    extern "C" {
        fn objc_msgSend();
        fn objc_msgSend_stret();
    }
    let type_id = TypeId::of::<R>();
    let msg_fn = if mem::size_of::<R>() <= 4 || type_id == TypeId::of::<i64>() ||
        type_id == TypeId::of::<u64>() || type_id == TypeId::of::<f64>()
    {
        objc_msgSend
    } else {
        objc_msgSend_stret
    };
    (msg_fn, obj)
}

pub trait Receiver {}

impl Receiver for Object {}
impl Receiver for Class {}

pub fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A) -> R
where
    T: Receiver,
    A: MessageArguments,
    R: Any,
{
    let (msg_send_fn, receiver) = msg_send_fn::<R>(unsafe { mem::transmute(obj) }, sel);
    unsafe { A::invoke(msg_send_fn, receiver, sel, args) }
}