-
Notifications
You must be signed in to change notification settings - Fork 1
/
mrubyfunction.hpp
115 lines (99 loc) · 2.54 KB
/
mrubyfunction.hpp
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
#ifndef __MRUBYFUNCTION_HPP__
#define __MRUBYFUNCTION_HPP__
class BaseFunction
{
protected:
mrb_state* mrb;
RProc* proc;
BaseFunction(mrb_state* mrb, RProc* proc) : mrb(mrb), proc(proc)
{ }
template<typename TArgHead, typename TArgHead2, typename ... TArgTail>
static void push_args(mrb_state* mrb, std::vector<mrb_value>* vector, TArgHead head, TArgHead2 head2, TArgTail ... tail)
{
vector->push_back(TypeBinder<TArgHead>::to_mrb_value(mrb, head));
push_args<TArgHead2, TArgTail...>(mrb, vector, head2, tail...);
}
template<typename TArgHead>
static void push_args(mrb_state* mrb, std::vector<mrb_value>* vector, TArgHead head)
{
vector->push_back(TypeBinder<TArgHead>::to_mrb_value(mrb, head));
}
};
template<typename TFunc>
class Function : public BaseFunction
{
Function()
{ /* private constructor */
}
};
template<typename TRet, typename ... TArgs>
class Function<TRet(TArgs...)> : public BaseFunction
{
public:
Function(mrb_state* mrb, RProc* proc) : BaseFunction(mrb, proc)
{ }
TRet invoke(TArgs... args)
{
size_t argc = sizeof...(TArgs);
std::vector<mrb_value> argvector;
push_args(mrb, &argvector, args...);
mrb_sym call = mrb_intern_cstr(mrb, "call");
return TypeBinder<TRet>::from_mrb_value(
mrb,
mrb_funcall_argv(
mrb,
TypeBinder<RProc*>::to_mrb_value(mrb, proc),
call,
argc,
&argvector[0]));
}
};
template<typename ... TArgs>
class Function<void(TArgs...)> : public BaseFunction
{
public:
Function(mrb_state* mrb, RProc* proc) : BaseFunction(mrb, proc)
{ }
void invoke(TArgs... args)
{
size_t argc = sizeof...(TArgs);
std::vector<mrb_value> argvector;
push_args(mrb, &argvector, args...);
mrb_sym call = mrb_intern_cstr(mrb, "call");
mrb_funcall_argv(
mrb,
TypeBinder<RProc*>::to_mrb_value(mrb, proc),
call,
argc,
&argvector[0]);
}
};
template<typename TRet>
class Function<TRet()> : public BaseFunction
{
public:
Function(mrb_state* mrb, RProc* proc) : BaseFunction(mrb, proc)
{ }
TRet invoke()
{
mrb_value no = mrb_nil_value();
mrb_sym call = mrb_intern_cstr(mrb, "call");
return TypeBinder<TRet>::from_mrb_value(
mrb,
mrb_funcall_argv(mrb, TypeBinder<RProc*>::to_mrb_value(mrb, proc), call, 0, &no));
}
};
template<>
class Function< void() > : public BaseFunction
{
public:
Function(mrb_state* mrb, RProc* proc) : BaseFunction(mrb, proc)
{ }
void invoke()
{
mrb_value no = mrb_nil_value();
mrb_sym call = mrb_intern_cstr(mrb, "call");
mrb_funcall_argv(mrb, TypeBinder<RProc*>::to_mrb_value(mrb, proc), call, 0, &no);
}
};
#endif // __MRUBYFUNCTION_HPP__