#![allow(clippy::too_many_arguments)]
#![allow(clippy::many_single_char_names)]
#![allow(clippy::missing_safety_doc)]
use std::{ffi::c_void, os::raw::c_int, panic::AssertUnwindSafe, slice};
use seq_macro::seq;
use crate::{
block::{
do_yield_iter, do_yield_splat_iter, do_yield_values_iter, Proc, Yield, YieldSplat,
YieldValues,
},
error::{raise, Error, IntoError},
into_value::{ArgList, IntoValue},
r_array::RArray,
try_convert::TryConvert,
value::{ReprValue, Value},
Ruby,
};
mod private {
use super::*;
pub unsafe trait Method {
fn arity() -> i8;
#[allow(clippy::wrong_self_convention)]
fn as_ptr(self) -> *mut c_void;
}
unsafe impl Method for unsafe extern "C" fn(Value, RArray) -> Value {
fn arity() -> i8 {
-2
}
fn as_ptr(self) -> *mut c_void {
self as *mut c_void
}
}
unsafe impl Method for unsafe extern "C" fn(c_int, *const Value, Value) -> Value {
fn arity() -> i8 {
-1
}
fn as_ptr(self) -> *mut c_void {
self as *mut c_void
}
}
macro_rules! impl_method {
($n:literal) => {
seq!(_ in 0..=$n {
unsafe impl Method for unsafe extern "C" fn(#(Value,)*) -> Value {
fn arity() -> i8 {
$n
}
fn as_ptr(self) -> *mut c_void {
self as *mut c_void
}
}
});
}
}
seq!(N in 0..=15 {
impl_method!(N);
});
pub trait ReturnValue {
fn into_return_value(self) -> Result<Value, Error>;
}
impl<T, E> ReturnValue for Result<T, E>
where
T: IntoValue,
E: IntoError,
{
fn into_return_value(self) -> Result<Value, Error> {
let ruby = unsafe { Ruby::get_unchecked() };
self.map(|val| val.into_value_with(&ruby))
.map_err(|err| err.into_error(&ruby))
}
}
impl<T> ReturnValue for T
where
T: IntoValue,
{
fn into_return_value(self) -> Result<Value, Error> {
Ok::<T, Error>(self).into_return_value()
}
}
impl<I, T, E> ReturnValue for Result<Yield<I>, E>
where
I: Iterator<Item = T>,
T: IntoValue,
E: IntoError,
{
fn into_return_value(self) -> Result<Value, Error> {
let ruby = unsafe { Ruby::get_unchecked() };
self.map(|i| match i {
Yield::Iter(iter) => unsafe {
do_yield_iter(iter);
ruby.qnil().as_value()
},
Yield::Enumerator(e) => e.into_value_with(&ruby),
})
.map_err(|err| err.into_error(&ruby))
}
}
impl<I, T> ReturnValue for Yield<I>
where
I: Iterator<Item = T>,
T: IntoValue,
{
fn into_return_value(self) -> Result<Value, Error> {
Ok::<Self, Error>(self).into_return_value()
}
}
impl<I, T, E> ReturnValue for Result<YieldValues<I>, E>
where
I: Iterator<Item = T>,
T: ArgList,
E: IntoError,
{
fn into_return_value(self) -> Result<Value, Error> {
let ruby = unsafe { Ruby::get_unchecked() };
self.map(|i| match i {
YieldValues::Iter(iter) => unsafe {
do_yield_values_iter(iter);
ruby.qnil().as_value()
},
YieldValues::Enumerator(e) => e.into_value_with(&ruby),
})
.map_err(|err| err.into_error(&ruby))
}
}
impl<I, T> ReturnValue for YieldValues<I>
where
I: Iterator<Item = T>,
T: ArgList,
{
fn into_return_value(self) -> Result<Value, Error> {
Ok::<Self, Error>(self).into_return_value()
}
}
impl<I, E> ReturnValue for Result<YieldSplat<I>, E>
where
I: Iterator<Item = RArray>,
E: IntoError,
{
fn into_return_value(self) -> Result<Value, Error> {
let ruby = unsafe { Ruby::get_unchecked() };
self.map(|i| match i {
YieldSplat::Iter(iter) => unsafe {
do_yield_splat_iter(iter);
ruby.qnil().as_value()
},
YieldSplat::Enumerator(e) => e.into_value_with(&ruby),
})
.map_err(|err| err.into_error(&ruby))
}
}
impl<I> ReturnValue for YieldSplat<I>
where
I: Iterator<Item = RArray>,
{
fn into_return_value(self) -> Result<Value, Error> {
Ok::<Self, Error>(self).into_return_value()
}
}
pub trait InitReturn {
fn into_init_return(self) -> Result<(), Error>;
}
impl InitReturn for () {
fn into_init_return(self) -> Result<(), Error> {
Ok(())
}
}
impl<E> InitReturn for Result<(), E>
where
E: IntoError,
{
fn into_init_return(self) -> Result<(), Error> {
self.map_err(|err| err.into_error(&unsafe { Ruby::get_unchecked() }))
}
}
pub trait BlockReturn {
fn into_block_return(self) -> Result<Value, Error>;
}
impl<T> BlockReturn for Result<T, Error>
where
T: IntoValue,
{
fn into_block_return(self) -> Result<Value, Error> {
self.map(|val| unsafe { val.into_value_unchecked() })
}
}
impl<T> BlockReturn for T
where
T: IntoValue,
{
fn into_block_return(self) -> Result<Value, Error> {
Ok(self).into_block_return()
}
}
}
pub trait Method: private::Method {}
impl<T> Method for T where T: private::Method {}
pub trait ReturnValue: private::ReturnValue {}
impl<T> ReturnValue for T where T: private::ReturnValue {}
pub trait InitReturn: private::InitReturn {}
impl<T> InitReturn for T where T: private::InitReturn {}
pub trait BlockReturn: private::BlockReturn {}
impl<T> BlockReturn for T where T: private::BlockReturn {}
#[doc(hidden)]
pub trait Init<Res>
where
Self: Sized + Fn() -> Res,
Res: InitReturn,
{
#[inline]
unsafe fn call_handle_error(self) {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| (self)().into_init_return())) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Res> Init<Res> for Func
where
Func: Fn() -> Res,
Res: InitReturn,
{
}
#[doc(hidden)]
pub trait RubyInit<Res>
where
Self: Sized + Fn(&Ruby) -> Res,
Res: InitReturn,
{
#[inline]
unsafe fn call_handle_error(self) {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
(self)(&Ruby::get_unchecked()).into_init_return()
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Res> RubyInit<Res> for Func
where
Func: Fn(&Ruby) -> Res,
Res: InitReturn,
{
}
#[doc(hidden)]
pub trait Block<Res>
where
Self: Sized + FnOnce(&Ruby, &[Value], Option<Proc>) -> Res,
Res: BlockReturn,
{
#[inline]
unsafe fn call_convert_value(
self,
argc: c_int,
argv: *const Value,
blockarg: Value,
) -> Result<Value, Error> {
let ruby = Ruby::get_unchecked();
let args = slice::from_raw_parts(argv, argc as usize);
(self)(&ruby, args, Proc::from_value(blockarg)).into_block_return()
}
#[inline]
unsafe fn call_handle_error(self, argc: c_int, argv: *const Value, blockarg: Value) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(argc, argv, blockarg)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Res> Block<Res> for Func
where
Func: FnOnce(&Ruby, &[Value], Option<Proc>) -> Res,
Res: BlockReturn,
{
}
#[doc(hidden)]
pub trait Thread<Res>
where
Self: Sized + FnOnce(&Ruby) -> Res,
Res: BlockReturn,
{
#[inline]
unsafe fn call_convert_value(self) -> Result<Value, Error> {
(self)(&Ruby::get_unchecked()).into_block_return()
}
#[inline]
unsafe fn call_handle_error(self) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| self.call_convert_value())) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Res> Thread<Res> for Func
where
Func: FnOnce(&Ruby) -> Res,
Res: BlockReturn,
{
}
#[doc(hidden)]
pub trait Synchronize<Res>
where
Self: Sized + FnOnce() -> Res,
Res: BlockReturn,
{
#[inline]
unsafe fn call_convert_value(self) -> Result<Value, Error> {
(self)().into_block_return()
}
#[inline]
unsafe fn call_handle_error(self) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| self.call_convert_value())) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Res> Synchronize<Res> for Func
where
Func: FnOnce() -> Res,
Res: BlockReturn,
{
}
#[doc(hidden)]
pub trait MethodRbAry<RbSelf, Args, Res>
where
Self: Sized + Fn(RbSelf, Args) -> Res,
RbSelf: TryConvert,
Args: TryConvert,
Res: ReturnValue,
{
#[inline]
fn call_convert_value(self, rb_self: Value, args: RArray) -> Result<Value, Error> {
(self)(
TryConvert::try_convert(rb_self)?,
TryConvert::try_convert(args.as_value())?,
)
.into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, rb_self: Value, args: RArray) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(rb_self, args)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, RbSelf, Args, Res> MethodRbAry<RbSelf, Args, Res> for Func
where
Func: Fn(RbSelf, Args) -> Res,
RbSelf: TryConvert,
Args: TryConvert,
Res: ReturnValue,
{
}
#[doc(hidden)]
pub trait RubyMethodRbAry<RbSelf, Args, Res>
where
Self: Sized + Fn(&Ruby, RbSelf, Args) -> Res,
RbSelf: TryConvert,
Args: TryConvert,
Res: ReturnValue,
{
#[inline]
fn call_convert_value(self, rb_self: Value, args: RArray) -> Result<Value, Error> {
(self)(
&Ruby::get_with(rb_self),
TryConvert::try_convert(rb_self)?,
TryConvert::try_convert(args.as_value())?,
)
.into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, rb_self: Value, args: RArray) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(rb_self, args)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, RbSelf, Args, Res> RubyMethodRbAry<RbSelf, Args, Res> for Func
where
Func: Fn(&Ruby, RbSelf, Args) -> Res,
RbSelf: TryConvert,
Args: TryConvert,
Res: ReturnValue,
{
}
#[doc(hidden)]
pub trait MethodCAry<RbSelf, Res>
where
Self: Sized + Fn(RbSelf, &[Value]) -> Res,
RbSelf: TryConvert,
Res: ReturnValue,
{
#[inline]
unsafe fn call_convert_value(
self,
argc: c_int,
argv: *const Value,
rb_self: Value,
) -> Result<Value, Error> {
let args = slice::from_raw_parts(argv, argc as usize);
(self)(TryConvert::try_convert(rb_self)?, args).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, argc: c_int, argv: *const Value, rb_self: Value) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(argc, argv, rb_self)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, RbSelf, Res> MethodCAry<RbSelf, Res> for Func
where
Func: Fn(RbSelf, &[Value]) -> Res,
RbSelf: TryConvert,
Res: ReturnValue,
{
}
#[doc(hidden)]
pub trait RubyMethodCAry<RbSelf, Res>
where
Self: Sized + Fn(&Ruby, RbSelf, &[Value]) -> Res,
RbSelf: TryConvert,
Res: ReturnValue,
{
#[inline]
unsafe fn call_convert_value(
self,
argc: c_int,
argv: *const Value,
rb_self: Value,
) -> Result<Value, Error> {
let args = slice::from_raw_parts(argv, argc as usize);
(self)(
&Ruby::get_with(rb_self),
TryConvert::try_convert(rb_self)?,
args,
)
.into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, argc: c_int, argv: *const Value, rb_self: Value) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(argc, argv, rb_self)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, RbSelf, Res> RubyMethodCAry<RbSelf, Res> for Func
where
Func: Fn(&Ruby, RbSelf, &[Value]) -> Res,
RbSelf: TryConvert,
Res: ReturnValue,
{
}
macro_rules! method_n {
($name:ident, $ruby_name:ident, $n:literal) => {
seq!(N in 0..$n {
#[doc(hidden)]
pub trait $name<RbSelf, #(T~N,)* Res>
where
Self: Sized + Fn(RbSelf, #(T~N,)*) -> Res,
RbSelf: TryConvert,
#(T~N: TryConvert,)*
Res: ReturnValue,
{
#[inline]
fn call_convert_value(self, rb_self: Value, #(arg~N: Value,)*) -> Result<Value, Error> {
(self)(
TryConvert::try_convert(rb_self)?,
#(TryConvert::try_convert(arg~N)?,)*
).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, rb_self: Value, #(arg~N: Value,)*) -> Value {
let res =
match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(rb_self, #(arg~N,)*)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, RbSelf, #(T~N,)* Res> $name<RbSelf, #(T~N,)* Res> for Func
where
Func: Fn(RbSelf, #(T~N,)*) -> Res,
RbSelf: TryConvert,
#(T~N: TryConvert,)*
Res: ReturnValue,
{}
#[doc(hidden)]
pub trait $ruby_name<RbSelf, #(T~N,)* Res>
where
Self: Sized + Fn(&Ruby, RbSelf, #(T~N,)*) -> Res,
RbSelf: TryConvert,
#(T~N: TryConvert,)*
Res: ReturnValue,
{
#[inline]
fn call_convert_value(self, rb_self: Value, #(arg~N: Value,)*) -> Result<Value, Error> {
(self)(
&Ruby::get_with(rb_self),
TryConvert::try_convert(rb_self)?,
#(TryConvert::try_convert(arg~N)?,)*
).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, rb_self: Value, #(arg~N: Value,)*) -> Value {
let res =
match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(rb_self, #(arg~N,)*)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, RbSelf, #(T~N,)* Res> $ruby_name<RbSelf, #(T~N,)* Res> for Func
where
Func: Fn(&Ruby, RbSelf, #(T~N,)*) -> Res,
RbSelf: TryConvert,
#(T~N: TryConvert,)*
Res: ReturnValue,
{}
});
}
}
seq!(N in 0..=15 {
method_n!(Method~N, RubyMethod~N, N);
});
#[macro_export]
macro_rules! method {
($name:expr, -2) => {{
unsafe extern "C" fn anon(rb_self: $crate::Value, args: $crate::RArray) -> $crate::Value {
use $crate::method::{MethodRbAry, RubyMethodRbAry};
$name.call_handle_error(rb_self, args)
}
anon as unsafe extern "C" fn($crate::Value, $crate::RArray) -> $crate::Value
}};
($name:expr, -1) => {{
unsafe extern "C" fn anon(
argc: std::os::raw::c_int,
argv: *const $crate::Value,
rb_self: $crate::Value,
) -> $crate::Value {
use $crate::method::{MethodCAry, RubyMethodCAry};
$name.call_handle_error(argc, argv, rb_self)
}
anon as unsafe extern "C" fn(
std::os::raw::c_int,
*const $crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 0) => {{
unsafe extern "C" fn anon(rb_self: $crate::Value) -> $crate::Value {
use $crate::method::{Method0, RubyMethod0};
$name.call_handle_error(rb_self)
}
anon as unsafe extern "C" fn($crate::Value) -> $crate::Value
}};
($name:expr, 1) => {{
unsafe extern "C" fn anon(rb_self: $crate::Value, a: $crate::Value) -> $crate::Value {
use $crate::method::{Method1, RubyMethod1};
$name.call_handle_error(rb_self, a)
}
anon as unsafe extern "C" fn($crate::Value, $crate::Value) -> $crate::Value
}};
($name:expr, 2) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method2, RubyMethod2};
$name.call_handle_error(rb_self, a, b)
}
anon as unsafe extern "C" fn($crate::Value, $crate::Value, $crate::Value) -> $crate::Value
}};
($name:expr, 3) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method3, RubyMethod3};
$name.call_handle_error(rb_self, a, b, c)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 4) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method4, RubyMethod4};
$name.call_handle_error(rb_self, a, b, c, d)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 5) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method5, RubyMethod5};
$name.call_handle_error(rb_self, a, b, c, d, e)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 6) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method6, RubyMethod6};
$name.call_handle_error(rb_self, a, b, c, d, e, f)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 7) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method7, RubyMethod7};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 8) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method8, RubyMethod8};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 9) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method9, RubyMethod9};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h, i)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 10) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method10, RubyMethod10};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h, i, j)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 11) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method11, RubyMethod11};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h, i, j, k)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 12) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method12, RubyMethod12};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h, i, j, k, l)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 13) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
m: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method13, RubyMethod13};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h, i, j, k, l, m)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 14) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
m: $crate::Value,
n: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method14, RubyMethod14};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h, i, j, k, l, m, n)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 15) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
m: $crate::Value,
n: $crate::Value,
o: $crate::Value,
) -> $crate::Value {
use $crate::method::{Method15, RubyMethod15};
$name.call_handle_error(rb_self, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, $arity:expr) => {
compile_error!("arity must be an integer literal between -2..=15")
};
}
#[doc(hidden)]
pub trait FunctionRbAry<Args, Res>
where
Self: Sized + Fn(Args) -> Res,
Args: TryConvert,
Res: ReturnValue,
{
#[inline]
fn call_convert_value(self, args: RArray) -> Result<Value, Error> {
(self)(TryConvert::try_convert(args.as_value())?).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, args: RArray) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| self.call_convert_value(args)))
{
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Args, Res> FunctionRbAry<Args, Res> for Func
where
Func: Fn(Args) -> Res,
Args: TryConvert,
Res: ReturnValue,
{
}
#[doc(hidden)]
pub trait RubyFunctionRbAry<Args, Res>
where
Self: Sized + Fn(&Ruby, Args) -> Res,
Args: TryConvert,
Res: ReturnValue,
{
#[inline]
fn call_convert_value(self, args: RArray) -> Result<Value, Error> {
(self)(
&Ruby::get_with(args),
TryConvert::try_convert(args.as_value())?,
)
.into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, args: RArray) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| self.call_convert_value(args)))
{
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Args, Res> RubyFunctionRbAry<Args, Res> for Func
where
Func: Fn(&Ruby, Args) -> Res,
Args: TryConvert,
Res: ReturnValue,
{
}
#[doc(hidden)]
pub trait FunctionCAry<Res>
where
Self: Sized + Fn(&[Value]) -> Res,
Res: ReturnValue,
{
#[inline]
unsafe fn call_convert_value(self, argc: c_int, argv: *const Value) -> Result<Value, Error> {
let args = slice::from_raw_parts(argv, argc as usize);
(self)(args).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, argc: c_int, argv: *const Value) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(argc, argv)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Res> FunctionCAry<Res> for Func
where
Func: Fn(&[Value]) -> Res,
Res: ReturnValue,
{
}
#[doc(hidden)]
pub trait RubyFunctionCAry<Res>
where
Self: Sized + Fn(&Ruby, &[Value]) -> Res,
Res: ReturnValue,
{
#[inline]
unsafe fn call_convert_value(self, argc: c_int, argv: *const Value) -> Result<Value, Error> {
let args = slice::from_raw_parts(argv, argc as usize);
(self)(&Ruby::get_unchecked(), args).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, argc: c_int, argv: *const Value) -> Value {
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(argc, argv)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, Res> RubyFunctionCAry<Res> for Func
where
Func: Fn(&Ruby, &[Value]) -> Res,
Res: ReturnValue,
{
}
macro_rules! function_n {
($name:ident, $ruby_name:ident, $n:literal) => {
seq!(N in 0..$n {
#[doc(hidden)]
pub trait $name<#(T~N,)* Res>
where
Self: Sized + Fn(#(T~N,)*) -> Res,
#(T~N: TryConvert,)*
Res: ReturnValue,
{
#[inline]
fn call_convert_value(self, #(arg~N: Value,)*) -> Result<Value, Error> {
(self)(
#(TryConvert::try_convert(arg~N)?,)*
).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, #(arg~N: Value,)*) -> Value {
let res =
match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(#(arg~N,)*)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, #(T~N,)* Res> $name<#(T~N,)* Res> for Func
where
Func: Fn(#(T~N,)*) -> Res,
#(T~N: TryConvert,)*
Res: ReturnValue,
{}
#[doc(hidden)]
pub trait $ruby_name<#(T~N,)* Res>
where
Self: Sized + Fn(&Ruby, #(T~N,)*) -> Res,
#(T~N: TryConvert,)*
Res: ReturnValue,
{
#[inline]
unsafe fn call_convert_value(self, #(arg~N: Value,)*) -> Result<Value, Error> {
(self)(
&Ruby::get_unchecked(),
#(TryConvert::try_convert(arg~N)?,)*
).into_return_value()
}
#[inline]
unsafe fn call_handle_error(self, #(arg~N: Value,)*) -> Value {
let res =
match std::panic::catch_unwind(AssertUnwindSafe(|| {
self.call_convert_value(#(arg~N,)*)
})) {
Ok(v) => v,
Err(e) => Err(Error::from_panic(e)),
};
match res {
Ok(v) => v,
Err(e) => raise(e),
}
}
}
impl<Func, #(T~N,)* Res> $ruby_name<#(T~N,)* Res> for Func
where
Func: Fn(&Ruby, #(T~N,)*) -> Res,
#(T~N: TryConvert,)*
Res: ReturnValue,
{}
});
}
}
seq!(N in 0..=15 {
function_n!(Function~N, RubyFunction~N, N);
});
#[macro_export]
macro_rules! function {
($name:expr, -2) => {{
unsafe extern "C" fn anon(rb_self: $crate::Value, args: $crate::RArray) -> $crate::Value {
use $crate::method::{FunctionRbAry, RubyFunctionRbAry};
$name.call_handle_error(args)
}
anon as unsafe extern "C" fn($crate::Value, $crate::RArray) -> $crate::Value
}};
($name:expr, -1) => {{
unsafe extern "C" fn anon(
argc: std::os::raw::c_int,
argv: *const $crate::Value,
rb_self: $crate::Value,
) -> $crate::Value {
use $crate::method::{FunctionCAry, RubyFunctionCAry};
$name.call_handle_error(argc, argv)
}
anon as unsafe extern "C" fn(
std::os::raw::c_int,
*const $crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 0) => {{
unsafe extern "C" fn anon(rb_self: $crate::Value) -> $crate::Value {
use $crate::method::{Function0, RubyFunction0};
$name.call_handle_error()
}
anon as unsafe extern "C" fn($crate::Value) -> $crate::Value
}};
($name:expr, 1) => {{
unsafe extern "C" fn anon(rb_self: $crate::Value, a: $crate::Value) -> $crate::Value {
use $crate::method::{Function1, RubyFunction1};
$name.call_handle_error(a)
}
anon as unsafe extern "C" fn($crate::Value, $crate::Value) -> $crate::Value
}};
($name:expr, 2) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function2, RubyFunction2};
$name.call_handle_error(a, b)
}
anon as unsafe extern "C" fn($crate::Value, $crate::Value, $crate::Value) -> $crate::Value
}};
($name:expr, 3) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function3, RubyFunction3};
$name.call_handle_error(a, b, c)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 4) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function4, RubyFunction4};
$name.call_handle_error(a, b, c, d)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 5) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function5, RubyFunction5};
$name.call_handle_error(a, b, c, d, e)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 6) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function6, RubyFunction6};
$name.call_handle_error(a, b, c, d, e, f)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 7) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function7, RubyFunction7};
$name.call_handle_error(a, b, c, d, e, f, g)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 8) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function8, RubyFunction8};
$name.call_handle_error(a, b, c, d, e, f, g, h)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 9) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function9, RubyFunction9};
$name.call_handle_error(a, b, c, d, e, f, g, h, i)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 10) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function10, RubyFunction10};
$name.call_handle_error(a, b, c, d, e, f, g, h, i, j)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 11) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function11, RubyFunction11};
$name.call_handle_error(a, b, c, d, e, f, g, h, i, j, k)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 12) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function12, RubyFunction12};
$name.call_handle_error(a, b, c, d, e, f, g, h, i, j, k, l)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 13) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
m: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function13, RubyFunction13};
$name.call_handle_error(a, b, c, d, e, f, g, h, i, j, k, l, m)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 14) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
m: $crate::Value,
n: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function14, RubyFunction14};
$name.call_handle_error(a, b, c, d, e, f, g, h, i, j, k, l, m, n)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, 15) => {{
unsafe extern "C" fn anon(
rb_self: $crate::Value,
a: $crate::Value,
b: $crate::Value,
c: $crate::Value,
d: $crate::Value,
e: $crate::Value,
f: $crate::Value,
g: $crate::Value,
h: $crate::Value,
i: $crate::Value,
j: $crate::Value,
k: $crate::Value,
l: $crate::Value,
m: $crate::Value,
n: $crate::Value,
o: $crate::Value,
) -> $crate::Value {
use $crate::method::{Function15, RubyFunction15};
$name.call_handle_error(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
}
anon as unsafe extern "C" fn(
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
$crate::Value,
) -> $crate::Value
}};
($name:expr, $arity:expr) => {
compile_error!("arity must be an integer literal between -2..=15")
};
}