use std::{
os::raw::c_int,
mem,
};
use crate::{
prelude::*,
ruby::VALUE,
};
pub unsafe trait MethodFn<Receiver: Object> {
type Output: Object;
const ARITY: c_int;
fn raw_fn(self) -> unsafe extern "C" fn() -> VALUE;
}
#[macro_export]
macro_rules! def_method {
(
$class:expr,
$name:expr,
|
$this:ident $(: $this_ty:ty)?
$(, $args:ident $(: $args_ty:ty)?)*
$(,)?
|
$body:expr
) => { {
type __AnyObject = $crate::AnyObject;
type __Class = $crate::Class;
macro_rules! _replace {
($__t:tt $sub:tt) => { $sub }
}
macro_rules! _substitute_any_object {
() => { __AnyObject };
($__t:ty) => { $__t };
}
macro_rules! _cast_class {
($c:expr,) => { __Class::into_any_class($c) };
($c:expr, $_t:ty) => { $c };
}
extern "C" fn _method(
$this : _substitute_any_object!($($this_ty)?),
$( $args : _substitute_any_object!($($args_ty)?) ),*
) -> AnyObject { $body.into() }
let _method: extern "C" fn(_, $( _replace!($args _) ),*) -> _ = _method;
let _class = _cast_class!($class, $($this_ty)?);
$crate::Class::def_method(_class, $name, _method)
} };
}
#[macro_export]
macro_rules! def_method_unchecked {
(
$class:expr,
$name:expr,
|
$this:ident $(: $this_ty:ty)?
$(, $args:ident $(: $args_ty:ty)?)*
$(,)?
|
$body:expr
) => { {
type __AnyObject = $crate::AnyObject;
type __Class = $crate::Class;
macro_rules! _replace {
($__t:tt $sub:tt) => { $sub }
}
macro_rules! _substitute_any_object {
() => { __AnyObject };
($__t:ty) => { $__t };
}
macro_rules! _cast_class {
($c:expr,) => { __Class::into_any_class($c) };
($c:expr, $_t:ty) => { $c };
}
extern "C" fn _method(
$this : _substitute_any_object!($($this_ty)?),
$( $args : _substitute_any_object!($($args_ty)?) ),*
) -> AnyObject { $body.into() }
let _method: extern "C" fn(_, $( _replace!($args _) ),*) -> _ = _method;
let _class = _cast_class!($class, $($this_ty)?);
$crate::Class::def_method_unchecked(_class, $name, _method)
} };
}
macro_rules! impl_trait {
($($a:expr $(,$args:ty)*;)+) => { $(
impl_trait!(@fn $a, unsafe extern "C" fn(this: R $(,$args)*));
impl_trait!(@fn $a, extern "C" fn(this: R $(,$args)*));
)+ };
(@fn $a:expr, $($f:tt)+) => {
unsafe impl<R: Object, O: Object> MethodFn<R> for $($f)+ -> O {
type Output = O;
const ARITY: c_int = $a;
#[inline]
fn raw_fn(self) -> unsafe extern "C" fn() -> VALUE {
unsafe { mem::transmute(self) }
}
}
};
}
impl_trait! {
-2, Array;
-1, c_int, *const AnyObject;
}
macro_rules! replace {
($_t:tt $sub:tt) => { $sub };
}
macro_rules! count {
($($t:tt)*) => { 0 $(+ replace!($t 1))* };
}
macro_rules! impl_trait_many {
() => {
impl_trait! { 0; }
};
(, $($t:tt)*) => {
impl_trait_many!($($t)*);
impl_trait! { 1 + count!($($t)*), AnyObject $(, replace!($t AnyObject))* ; }
};
}
impl_trait_many!(,,,,, ,,,,, ,,,,,);