1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use rurust::Value;
use libc;
use std::mem;
pub struct Receiver;
pub type Method = fn(&mut Receiver) -> Value;
pub type Method1 = fn(&mut Receiver, Value) -> Value;
pub type Method2 = fn(&mut Receiver, Value, Value) -> Value;
pub type Method3 = fn(&mut Receiver, Value, Value, Value) -> Value;
pub type Method4 = fn(&mut Receiver, Value, Value, Value, Value) -> Value;
pub type Method5 = fn(&mut Receiver, Value, Value, Value, Value, Value) -> Value;
pub type Method6 = fn(&mut Receiver, Value, Value, Value, Value, Value, Value) -> Value;
pub type Method7 = fn(&mut Receiver, Value, Value, Value, Value, Value, Value, Value) -> Value;
pub type Method8 = fn(&mut Receiver, Value, Value, Value, Value, Value, Value, Value, Value) -> Value;
pub type Method9 = fn(&mut Receiver, Value, Value, Value, Value, Value, Value, Value, Value, Value) -> Value;
pub type Function = fn() -> Value;
pub type Function1 = fn(Value) -> Value;
pub type Function2 = fn(Value, Value) -> Value;
pub type Function3 = fn(Value, Value, Value) -> Value;
pub type Function4 = fn(Value, Value, Value, Value) -> Value;
pub type Function5 = fn(Value, Value, Value, Value, Value) -> Value;
pub type Function6 = fn(Value, Value, Value, Value, Value, Value) -> Value;
pub type Function7 = fn(Value, Value, Value, Value, Value, Value, Value) -> Value;
pub type Function8 = fn(Value, Value, Value, Value, Value, Value, Value, Value) -> Value;
pub type Function9 = fn(Value, Value, Value, Value, Value, Value, Value, Value, Value) -> Value;
macro_rules! dispatch {
( $method:expr => $method_type:ty => ( $( $arg:expr ),* ) ) => {
{
let method: $method_type = unsafe { mem::transmute($method) };
method ( $( $arg ),* )
}
}
}
pub extern fn ruby_method(argc: libc::c_int, argv: *const Value, object: Value) -> Value {
let (method, arguments) = helpers::process_method_arguments(argc, argv);
let receiver = helpers::reference_to_struct(object);
let a = arguments;
match arguments.len() {
0 => dispatch!(method => Method => (receiver)),
1 => dispatch!(method => Method1 => (receiver, a[0])),
2 => dispatch!(method => Method2 => (receiver, a[0], a[1])),
3 => dispatch!(method => Method3 => (receiver, a[0], a[1], a[2])),
4 => dispatch!(method => Method4 => (receiver, a[0], a[1], a[2], a[3])),
5 => dispatch!(method => Method5 => (receiver, a[0], a[1], a[2], a[3], a[4])),
6 => dispatch!(method => Method6 => (receiver, a[0], a[1], a[2], a[3], a[4], a[5])),
7 => dispatch!(method => Method7 => (receiver, a[0], a[1], a[2], a[3], a[4], a[5], a[6])),
8 => dispatch!(method => Method8 => (receiver, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7])),
9 => dispatch!(method => Method9 => (receiver, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])),
_ => panic!("too many arguments: {}", arguments.len()),
}
}
pub extern fn ruby_singleton_method(argc: libc::c_int, argv: *const Value, _class: Value) -> Value {
let (function, arguments) = helpers::process_function_arguments(argc, argv);
let a = arguments;
match arguments.len() {
0 => dispatch!(function => Function => ()),
1 => dispatch!(function => Function1 => (a[0])),
2 => dispatch!(function => Function2 => (a[0], a[1])),
3 => dispatch!(function => Function3 => (a[0], a[1], a[2])),
4 => dispatch!(function => Function4 => (a[0], a[1], a[2], a[3])),
5 => dispatch!(function => Function5 => (a[0], a[1], a[2], a[3], a[4])),
6 => dispatch!(function => Function6 => (a[0], a[1], a[2], a[3], a[4], a[5])),
7 => dispatch!(function => Function7 => (a[0], a[1], a[2], a[3], a[4], a[5], a[6])),
8 => dispatch!(function => Function8 => (a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7])),
9 => dispatch!(function => Function9 => (a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])),
_ => panic!("too many arguments: {}", arguments.len()),
}
}
mod helpers {
use super::{Receiver, Method, Function};
use rurust::Value;
use std::{mem, slice};
use libc;
struct Arguments<'a> {
function_ptr: Value,
full_arguments: &'a [Value],
}
pub fn process_method_arguments<'a>(argc: libc::c_int, argv: *const Value) -> (Method, &'a [Value]) {
let arguments = self::separate_arguments(argc, argv);
(self::method(arguments.function_ptr), arguments.full_arguments)
}
pub fn process_function_arguments<'a>(argc: libc::c_int, argv: *const Value) -> (Function, &'a [Value]) {
let arguments = self::separate_arguments(argc, argv);
(self::function(arguments.function_ptr), arguments.full_arguments)
}
fn separate_arguments<'a>(argc: libc::c_int, argv: *const Value) -> Arguments<'a> {
let all_arguments = unsafe { slice::from_raw_parts(argv, argc as usize) };
Arguments {
function_ptr: all_arguments[0],
full_arguments: &all_arguments[1..],
}
}
pub fn reference_to_struct<'a>(ruby_object: Value) -> &'a mut Receiver {
let ptr = ruby_object.call_no_args("object_pointer").to_u64() as usize;
let receiver: &mut Receiver = unsafe { mem::transmute(ptr) };
receiver
}
fn method(function_pointer: Value) -> Method {
unsafe { mem::transmute(self::function(function_pointer)) }
}
fn function(function_pointer: Value) -> Function {
let ptr = function_pointer.to_u64() as usize;
unsafe { mem::transmute(ptr) }
}
}