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