rice 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -0
  3. data/CONTRIBUTORS.md +19 -0
  4. data/Gemfile +3 -0
  5. data/README.md +44 -1025
  6. data/Rakefile +95 -12
  7. data/include/rice/rice.hpp +7766 -0
  8. data/lib/mkmf-rice.rb +127 -0
  9. data/lib/version.rb +3 -0
  10. data/rice/Address_Registration_Guard.ipp +75 -32
  11. data/rice/Address_Registration_Guard_defn.hpp +60 -56
  12. data/rice/Arg.hpp +80 -4
  13. data/rice/Arg.ipp +51 -0
  14. data/rice/Constructor.hpp +12 -14
  15. data/rice/Data_Object.ipp +234 -107
  16. data/rice/Data_Object_defn.hpp +77 -117
  17. data/rice/Data_Type.hpp +1 -2
  18. data/rice/Data_Type.ipp +251 -295
  19. data/rice/Data_Type_defn.hpp +175 -243
  20. data/rice/Director.hpp +11 -6
  21. data/rice/Enum.hpp +54 -104
  22. data/rice/Enum.ipp +104 -230
  23. data/rice/Exception.hpp +2 -8
  24. data/rice/Exception.ipp +65 -0
  25. data/rice/Exception_defn.hpp +46 -47
  26. data/rice/Identifier.hpp +28 -28
  27. data/rice/Identifier.ipp +23 -27
  28. data/rice/Return.hpp +39 -0
  29. data/rice/Return.ipp +33 -0
  30. data/rice/detail/Exception_Handler.ipp +22 -62
  31. data/rice/detail/Exception_Handler_defn.hpp +76 -91
  32. data/rice/detail/Iterator.hpp +18 -88
  33. data/rice/detail/Iterator.ipp +47 -0
  34. data/rice/detail/Jump_Tag.hpp +21 -0
  35. data/rice/detail/MethodInfo.hpp +44 -0
  36. data/rice/detail/MethodInfo.ipp +78 -0
  37. data/rice/detail/NativeAttribute.hpp +53 -0
  38. data/rice/detail/NativeAttribute.ipp +83 -0
  39. data/rice/detail/NativeFunction.hpp +69 -0
  40. data/rice/detail/NativeFunction.ipp +248 -0
  41. data/rice/detail/RubyFunction.hpp +39 -0
  42. data/rice/detail/RubyFunction.ipp +92 -0
  43. data/rice/detail/Type.hpp +29 -0
  44. data/rice/detail/Type.ipp +138 -0
  45. data/rice/detail/TypeRegistry.hpp +50 -0
  46. data/rice/detail/TypeRegistry.ipp +106 -0
  47. data/rice/detail/Wrapper.hpp +51 -0
  48. data/rice/detail/Wrapper.ipp +151 -0
  49. data/rice/detail/default_allocation_func.hpp +8 -19
  50. data/rice/detail/default_allocation_func.ipp +9 -8
  51. data/rice/detail/from_ruby.hpp +2 -37
  52. data/rice/detail/from_ruby.ipp +1020 -46
  53. data/rice/detail/from_ruby_defn.hpp +38 -0
  54. data/rice/detail/function_traits.hpp +124 -0
  55. data/rice/detail/method_data.hpp +23 -15
  56. data/rice/detail/method_data.ipp +53 -0
  57. data/rice/detail/rice_traits.hpp +116 -0
  58. data/rice/detail/ruby.hpp +9 -46
  59. data/rice/detail/to_ruby.hpp +3 -17
  60. data/rice/detail/to_ruby.ipp +409 -31
  61. data/rice/detail/to_ruby_defn.hpp +48 -0
  62. data/rice/forward_declares.ipp +82 -0
  63. data/rice/global_function.hpp +16 -20
  64. data/rice/global_function.ipp +8 -17
  65. data/rice/rice.hpp +59 -0
  66. data/rice/ruby_mark.hpp +5 -3
  67. data/rice/ruby_try_catch.hpp +4 -4
  68. data/rice/stl.hpp +11 -0
  69. data/sample/callbacks/extconf.rb +3 -0
  70. data/sample/callbacks/sample_callbacks.cpp +10 -13
  71. data/sample/enum/extconf.rb +3 -0
  72. data/sample/enum/sample_enum.cpp +3 -17
  73. data/sample/enum/test.rb +2 -2
  74. data/sample/inheritance/animals.cpp +8 -24
  75. data/sample/inheritance/extconf.rb +3 -0
  76. data/sample/inheritance/test.rb +1 -1
  77. data/sample/map/extconf.rb +3 -0
  78. data/sample/map/map.cpp +10 -18
  79. data/sample/map/test.rb +1 -1
  80. data/test/embed_ruby.cpp +18 -5
  81. data/test/ext/t1/extconf.rb +3 -0
  82. data/test/ext/t1/t1.cpp +1 -3
  83. data/test/ext/t2/extconf.rb +3 -0
  84. data/test/ext/t2/t2.cpp +1 -1
  85. data/test/extconf.rb +23 -0
  86. data/test/ruby/test_callbacks_sample.rb +28 -0
  87. data/test/ruby/test_multiple_extensions.rb +18 -0
  88. data/test/ruby/test_multiple_extensions_same_class.rb +14 -0
  89. data/test/ruby/test_multiple_extensions_with_inheritance.rb +20 -0
  90. data/test/test_Address_Registration_Guard.cpp +23 -10
  91. data/test/test_Array.cpp +129 -73
  92. data/test/test_Attribute.cpp +147 -0
  93. data/test/test_Builtin_Object.cpp +34 -14
  94. data/test/test_Class.cpp +149 -275
  95. data/test/test_Constructor.cpp +10 -9
  96. data/test/test_Data_Object.cpp +133 -192
  97. data/test/test_Data_Type.cpp +322 -252
  98. data/test/test_Director.cpp +54 -41
  99. data/test/test_Enum.cpp +228 -103
  100. data/test/test_Exception.cpp +5 -6
  101. data/test/test_Hash.cpp +31 -30
  102. data/test/test_Identifier.cpp +4 -5
  103. data/test/test_Inheritance.cpp +221 -0
  104. data/test/test_Iterator.cpp +161 -0
  105. data/test/test_Jump_Tag.cpp +1 -1
  106. data/test/test_Keep_Alive.cpp +161 -0
  107. data/test/test_Memory_Management.cpp +2 -4
  108. data/test/test_Module.cpp +167 -110
  109. data/test/test_Object.cpp +41 -21
  110. data/test/test_Ownership.cpp +275 -0
  111. data/test/test_Self.cpp +205 -0
  112. data/test/test_Stl_Optional.cpp +90 -0
  113. data/test/test_Stl_Pair.cpp +144 -0
  114. data/test/test_Stl_SmartPointer.cpp +200 -0
  115. data/test/test_Stl_String.cpp +74 -0
  116. data/test/test_Stl_Vector.cpp +652 -0
  117. data/test/test_String.cpp +1 -2
  118. data/test/test_Struct.cpp +29 -39
  119. data/test/test_Symbol.cpp +1 -2
  120. data/test/test_To_From_Ruby.cpp +249 -285
  121. data/test/test_global_functions.cpp +39 -19
  122. data/test/unittest.hpp +0 -4
  123. metadata +63 -139
  124. data/Doxyfile +0 -2268
  125. data/Makefile.am +0 -26
  126. data/Makefile.in +0 -931
  127. data/README.mingw +0 -8
  128. data/aclocal.m4 +0 -1085
  129. data/ax_cxx_compile_stdcxx.m4 +0 -951
  130. data/bootstrap +0 -8
  131. data/config.guess +0 -1421
  132. data/config.sub +0 -1807
  133. data/configure +0 -7792
  134. data/configure.ac +0 -55
  135. data/depcomp +0 -791
  136. data/doxygen.ac +0 -314
  137. data/doxygen.am +0 -186
  138. data/extconf.rb +0 -70
  139. data/install-sh +0 -501
  140. data/missing +0 -215
  141. data/post-autoconf.rb +0 -22
  142. data/post-automake.rb +0 -28
  143. data/rice/Address_Registration_Guard.cpp +0 -22
  144. data/rice/Arg_impl.hpp +0 -129
  145. data/rice/Arg_operators.cpp +0 -21
  146. data/rice/Arg_operators.hpp +0 -19
  147. data/rice/Array.hpp +0 -214
  148. data/rice/Array.ipp +0 -256
  149. data/rice/Builtin_Object.hpp +0 -8
  150. data/rice/Builtin_Object.ipp +0 -50
  151. data/rice/Builtin_Object_defn.hpp +0 -50
  152. data/rice/Class.cpp +0 -57
  153. data/rice/Class.hpp +0 -8
  154. data/rice/Class.ipp +0 -6
  155. data/rice/Class_defn.hpp +0 -84
  156. data/rice/Data_Type.cpp +0 -54
  157. data/rice/Data_Type_fwd.hpp +0 -12
  158. data/rice/Director.cpp +0 -13
  159. data/rice/Exception.cpp +0 -54
  160. data/rice/Exception_Base.hpp +0 -8
  161. data/rice/Exception_Base.ipp +0 -13
  162. data/rice/Exception_Base_defn.hpp +0 -27
  163. data/rice/Hash.hpp +0 -230
  164. data/rice/Hash.ipp +0 -329
  165. data/rice/Identifier.cpp +0 -8
  166. data/rice/Jump_Tag.hpp +0 -24
  167. data/rice/Makefile.am +0 -121
  168. data/rice/Makefile.in +0 -884
  169. data/rice/Module.cpp +0 -84
  170. data/rice/Module.hpp +0 -8
  171. data/rice/Module.ipp +0 -6
  172. data/rice/Module_defn.hpp +0 -88
  173. data/rice/Module_impl.hpp +0 -281
  174. data/rice/Module_impl.ipp +0 -345
  175. data/rice/Object.cpp +0 -169
  176. data/rice/Object.hpp +0 -8
  177. data/rice/Object.ipp +0 -33
  178. data/rice/Object_defn.hpp +0 -214
  179. data/rice/Require_Guard.hpp +0 -21
  180. data/rice/String.cpp +0 -89
  181. data/rice/String.hpp +0 -91
  182. data/rice/Struct.cpp +0 -117
  183. data/rice/Struct.hpp +0 -162
  184. data/rice/Struct.ipp +0 -26
  185. data/rice/Symbol.cpp +0 -25
  186. data/rice/Symbol.hpp +0 -66
  187. data/rice/Symbol.ipp +0 -44
  188. data/rice/config.hpp +0 -47
  189. data/rice/config.hpp.in +0 -46
  190. data/rice/detail/Arguments.hpp +0 -118
  191. data/rice/detail/Auto_Function_Wrapper.hpp +0 -898
  192. data/rice/detail/Auto_Function_Wrapper.ipp +0 -3181
  193. data/rice/detail/Auto_Member_Function_Wrapper.hpp +0 -897
  194. data/rice/detail/Auto_Member_Function_Wrapper.ipp +0 -2501
  195. data/rice/detail/Caster.hpp +0 -103
  196. data/rice/detail/Not_Copyable.hpp +0 -25
  197. data/rice/detail/Wrapped_Function.hpp +0 -33
  198. data/rice/detail/cfp.hpp +0 -24
  199. data/rice/detail/cfp.ipp +0 -51
  200. data/rice/detail/check_ruby_type.cpp +0 -27
  201. data/rice/detail/check_ruby_type.hpp +0 -23
  202. data/rice/detail/creation_funcs.hpp +0 -37
  203. data/rice/detail/creation_funcs.ipp +0 -36
  204. data/rice/detail/define_method_and_auto_wrap.hpp +0 -31
  205. data/rice/detail/define_method_and_auto_wrap.ipp +0 -30
  206. data/rice/detail/demangle.cpp +0 -56
  207. data/rice/detail/demangle.hpp +0 -19
  208. data/rice/detail/env.hpp +0 -11
  209. data/rice/detail/method_data.cpp +0 -92
  210. data/rice/detail/node.hpp +0 -13
  211. data/rice/detail/protect.cpp +0 -29
  212. data/rice/detail/protect.hpp +0 -34
  213. data/rice/detail/ruby_version_code.hpp +0 -6
  214. data/rice/detail/ruby_version_code.hpp.in +0 -6
  215. data/rice/detail/st.hpp +0 -22
  216. data/rice/detail/win32.hpp +0 -16
  217. data/rice/detail/wrap_function.hpp +0 -66
  218. data/rice/protect.hpp +0 -38
  219. data/rice/protect.ipp +0 -1134
  220. data/rice/rubypp.rb +0 -97
  221. data/rice/to_from_ruby.hpp +0 -8
  222. data/rice/to_from_ruby.ipp +0 -418
  223. data/rice/to_from_ruby_defn.hpp +0 -70
  224. data/ruby.ac +0 -135
  225. data/ruby/Makefile.am +0 -1
  226. data/ruby/Makefile.in +0 -628
  227. data/ruby/lib/Makefile.am +0 -3
  228. data/ruby/lib/Makefile.in +0 -506
  229. data/ruby/lib/mkmf-rice.rb.in +0 -217
  230. data/ruby/lib/version.rb +0 -3
  231. data/sample/Makefile.am +0 -53
  232. data/sample/Makefile.in +0 -495
  233. data/test/Makefile.am +0 -73
  234. data/test/Makefile.in +0 -1219
  235. data/test/ext/Makefile.am +0 -41
  236. data/test/ext/Makefile.in +0 -483
  237. data/test/test_rice.rb +0 -45
@@ -0,0 +1,53 @@
1
+ #ifndef Rice__detail__Native_Attribute__hpp_
2
+ #define Rice__detail__Native_Attribute__hpp_
3
+
4
+ #include "ruby.hpp"
5
+ #include "Exception_Handler_defn.hpp"
6
+ #include "MethodInfo.hpp"
7
+
8
+ namespace Rice
9
+ {
10
+ enum class AttrAccess
11
+ {
12
+ ReadWrite,
13
+ Read,
14
+ Write
15
+ };
16
+
17
+ namespace detail
18
+ {
19
+ template<typename Return_T, typename Attr_T, typename Self_T = void>
20
+ class NativeAttribute
21
+ {
22
+ public:
23
+ using Native_Return_T = Return_T;
24
+
25
+ // Static member functions that Ruby calls
26
+ static VALUE get(VALUE self);
27
+ static VALUE set(VALUE self, VALUE value);
28
+
29
+ public:
30
+ NativeAttribute(Attr_T attr, AttrAccess access = AttrAccess::ReadWrite);
31
+
32
+ // Invokes the wrapped function
33
+ VALUE read(VALUE self);
34
+ VALUE write(VALUE self, VALUE value);
35
+
36
+ private:
37
+ Attr_T attr_;
38
+ AttrAccess access_;
39
+ };
40
+
41
+ // A plain function or static member call
42
+ template<typename T>
43
+ auto* Make_Native_Attribute(T* attr, AttrAccess access);
44
+
45
+ // Lambda function that does not take Self as first parameter
46
+ template<typename Class_T, typename T>
47
+ auto* Make_Native_Attribute(T Class_T::* attr, AttrAccess access);
48
+ } // detail
49
+ } // Rice
50
+
51
+ #include "NativeAttribute.ipp"
52
+
53
+ #endif // Rice__detail__Native_Attribute__hpp_
@@ -0,0 +1,83 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+
4
+ #include "rice_traits.hpp"
5
+ #include "method_data.hpp"
6
+ #include "to_ruby_defn.hpp"
7
+ #include "../ruby_try_catch.hpp"
8
+
9
+ namespace Rice::detail
10
+ {
11
+ template<typename Return_T, typename Attr_T, typename Self_T>
12
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::get(VALUE self)
13
+ {
14
+ RUBY_TRY
15
+ {
16
+ using Native_Attr_T = NativeAttribute<Return_T, Attr_T, Self_T>;
17
+ Native_Attr_T* attr = detail::MethodData::data<Native_Attr_T*>();
18
+ return attr->read(self);
19
+ }
20
+ RUBY_CATCH
21
+ }
22
+
23
+ template<typename Return_T, typename Attr_T, typename Self_T>
24
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::set(VALUE self, VALUE value)
25
+ {
26
+ RUBY_TRY
27
+ {
28
+ using Native_Attr_T = NativeAttribute<Return_T, Attr_T, Self_T>;
29
+ Native_Attr_T* attr = detail::MethodData::data<Native_Attr_T*>();
30
+ return attr->write(self, value);
31
+ }
32
+ RUBY_CATCH
33
+ }
34
+
35
+ template<typename Return_T, typename Attr_T, typename Self_T>
36
+ NativeAttribute<Return_T, Attr_T, Self_T>::NativeAttribute(Attr_T attr, AttrAccess access)
37
+ : attr_(attr), access_(access)
38
+ {
39
+ }
40
+
41
+ template<typename Return_T, typename Attr_T, typename Self_T>
42
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::read(VALUE self)
43
+ {
44
+ using Unqualified_T = remove_cv_recursive_t<Return_T>;
45
+ if constexpr (std::is_member_object_pointer_v<Attr_T>)
46
+ {
47
+ Self_T* nativeSelf = From_Ruby<Self_T*>().convert(self);
48
+ return To_Ruby<Unqualified_T>().convert(nativeSelf->*attr_);
49
+ }
50
+ else
51
+ {
52
+ return To_Ruby<Unqualified_T>().convert(*attr_);
53
+ }
54
+ }
55
+
56
+ template<typename Return_T, typename Attr_T, typename Self_T>
57
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::write(VALUE self, VALUE value)
58
+ {
59
+ if constexpr (!std::is_const_v<std::remove_pointer_t<Attr_T>> && std::is_member_object_pointer_v<Attr_T>)
60
+ {
61
+ Self_T* nativeSelf = From_Ruby<Self_T*>().convert(self);
62
+ nativeSelf->*attr_ = From_Ruby<Return_T>().convert(value);
63
+ }
64
+ else if constexpr (!std::is_const_v<std::remove_pointer_t<Attr_T>>)
65
+ {
66
+ *attr_ = From_Ruby<Return_T>().convert(value);
67
+ }
68
+ return value;
69
+ }
70
+
71
+ template<typename T>
72
+ auto* Make_Native_Attribute(T* attr, AttrAccess access)
73
+ {
74
+ return new NativeAttribute<T, T*>(attr, access);
75
+ }
76
+
77
+ template<typename Class_T, typename T>
78
+ auto* Make_Native_Attribute(T Class_T::* attr, AttrAccess access)
79
+ {
80
+ using Attr_T = T Class_T::*;
81
+ return new NativeAttribute<T, Attr_T, Class_T>(attr, access);
82
+ }
83
+ } // Rice
@@ -0,0 +1,69 @@
1
+ #ifndef Rice__detail__Native_Function__hpp_
2
+ #define Rice__detail__Native_Function__hpp_
3
+
4
+ #include "ruby.hpp"
5
+ #include "Exception_Handler_defn.hpp"
6
+ #include "MethodInfo.hpp"
7
+ #include "function_traits.hpp"
8
+ #include "from_ruby.hpp"
9
+
10
+ namespace Rice::detail
11
+ {
12
+ template<typename Function_T, bool IsMethod>
13
+ class NativeFunction
14
+ {
15
+ public:
16
+ // We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
17
+ // have the concept of constants anyways
18
+ using Return_T = remove_cv_recursive_t<typename function_traits<Function_T>::return_type>;
19
+ using Self_T = typename method_traits<Function_T, IsMethod>::Self_T;
20
+ using Arg_Ts = typename method_traits<Function_T, IsMethod>::Arg_Ts;
21
+ using From_Ruby_Ts = typename tuple_map<From_Ruby, Arg_Ts>::type;
22
+
23
+ // Static member function that Ruby calls
24
+ static VALUE call(int argc, VALUE* argv, VALUE self);
25
+
26
+ public:
27
+ NativeFunction(Function_T func, std::shared_ptr<Exception_Handler> handler, MethodInfo* methodInfo);
28
+
29
+ // Invokes the wrapped function
30
+ VALUE operator()(int argc, VALUE* argv, VALUE self);
31
+
32
+ private:
33
+ template<typename T, std::size_t I>
34
+ From_Ruby<T> createFromRuby();
35
+
36
+ // Create NativeArgs which are used to convert values from Ruby to C++
37
+ template<std::size_t...I>
38
+ From_Ruby_Ts createFromRuby(std::index_sequence<I...>& indices);
39
+
40
+ To_Ruby<Return_T> createToRuby();
41
+
42
+ // Convert Ruby argv pointer to Ruby values
43
+ std::vector<VALUE> getRubyValues(int argc, VALUE* argv);
44
+
45
+ // Convert Ruby values to C++ values
46
+ template<typename std::size_t...I>
47
+ Arg_Ts getNativeValues(std::vector<VALUE>& values, std::index_sequence<I...>& indices);
48
+
49
+ // Figure out what self is
50
+ Self_T getSelf(VALUE self);
51
+
52
+ // Do we need to keep alive any arguments?
53
+ void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues);
54
+
55
+ // Call the underlying C++ function
56
+ VALUE invokeNativeFunction(Arg_Ts& nativeArgs);
57
+ VALUE invokeNativeMethod(VALUE self, Arg_Ts& nativeArgs);
58
+
59
+ private:
60
+ Function_T func_;
61
+ From_Ruby_Ts fromRubys_;
62
+ To_Ruby<Return_T> toRuby_;
63
+ std::shared_ptr<Exception_Handler> handler_;
64
+ std::unique_ptr<MethodInfo> methodInfo_;
65
+ };
66
+ }
67
+ #include "NativeFunction.ipp"
68
+
69
+ #endif // Rice__detail__Native_Function__hpp_
@@ -0,0 +1,248 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+ #include <stdexcept>
4
+
5
+ #include "method_data.hpp"
6
+ #include "to_ruby_defn.hpp"
7
+ #include "../ruby_try_catch.hpp"
8
+
9
+ namespace Rice::detail
10
+ {
11
+ template<typename Function_T, bool IsMethod>
12
+ VALUE NativeFunction<Function_T, IsMethod>::call(int argc, VALUE* argv, VALUE self)
13
+ {
14
+ using Wrapper_T = NativeFunction<Function_T, IsMethod>;
15
+ Wrapper_T* wrapper = detail::MethodData::data<Wrapper_T*>();
16
+ return wrapper->operator()(argc, argv, self);
17
+ }
18
+
19
+ template<typename Function_T, bool IsMethod>
20
+ NativeFunction<Function_T, IsMethod>::NativeFunction(Function_T func, std::shared_ptr<Exception_Handler> handler, MethodInfo* methodInfo)
21
+ : func_(func), handler_(handler), methodInfo_(methodInfo)
22
+ {
23
+ // Create a tuple of NativeArgs that will convert the Ruby values to native values. For
24
+ // builtin types NativeArgs will keep a copy of the native value so that it
25
+ // can be passed by reference or pointer to the native function. For non-builtin types
26
+ // it will just pass the value through.
27
+ auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
28
+ this->fromRubys_ = this->createFromRuby(indices);
29
+
30
+ this->toRuby_ = this->createToRuby();
31
+ }
32
+
33
+ template<typename Function_T, bool IsMethod>
34
+ template<typename T, std::size_t I>
35
+ From_Ruby<T> NativeFunction<Function_T, IsMethod>::createFromRuby()
36
+ {
37
+ // Does the From_Ruby instantiation work with Arg?
38
+ if constexpr (std::is_constructible_v<From_Ruby<T>, Arg*>)
39
+ {
40
+ return From_Ruby<T>(&this->methodInfo_->arg(I));
41
+ }
42
+ else
43
+ {
44
+ return From_Ruby<T>();
45
+ }
46
+ }
47
+
48
+ template<typename Function_T, bool IsMethod>
49
+ To_Ruby<typename NativeFunction<Function_T, IsMethod>::Return_T> NativeFunction<Function_T, IsMethod>::createToRuby()
50
+ {
51
+ // Does the From_Ruby instantiation work with ReturnInfo?
52
+ if constexpr (std::is_constructible_v<To_Ruby<Return_T>, Return*>)
53
+ {
54
+ return To_Ruby<Return_T>(&this->methodInfo_->returnInfo);
55
+ }
56
+ else
57
+ {
58
+ return To_Ruby<Return_T>();
59
+ }
60
+ }
61
+
62
+ template<typename Function_T, bool IsMethod>
63
+ template<std::size_t... I>
64
+ typename NativeFunction<Function_T, IsMethod>::From_Ruby_Ts NativeFunction<Function_T, IsMethod>::createFromRuby(std::index_sequence<I...>& indices)
65
+ {
66
+ return std::make_tuple(createFromRuby<remove_cv_recursive_t<typename std::tuple_element<I, Arg_Ts>::type>, I>()...);
67
+ }
68
+
69
+ template<typename Function_T, bool IsMethod>
70
+ std::vector<VALUE> NativeFunction<Function_T, IsMethod>::getRubyValues(int argc, VALUE* argv)
71
+ {
72
+ // Setup a tuple to contain required methodInfo to rb_scan_args
73
+ std::string scanFormat = this->methodInfo_->formatString();
74
+ std::tuple<int, VALUE*, const char*> rbScanMandatory = std::forward_as_tuple(argc, argv, scanFormat.c_str());
75
+
76
+ // Create a vector to store the variable number of Ruby Values
77
+ std::vector<VALUE> rbScanArgsOptional(std::tuple_size_v<Arg_Ts>, Qnil);
78
+
79
+ // Convert the vector to an array so it can then be concatenated to a tuple
80
+ std::array<VALUE*, std::tuple_size_v<Arg_Ts>> rbScanArgsOptionalPointers;
81
+ std::transform(rbScanArgsOptional.begin(), rbScanArgsOptional.end(), rbScanArgsOptionalPointers.begin(),
82
+ [](VALUE& value)
83
+ {
84
+ return &value;
85
+ });
86
+
87
+ // Combine the tuples and call rb_scan_args
88
+ auto rbScanArgs = std::tuple_cat(rbScanMandatory, rbScanArgsOptionalPointers);
89
+ std::apply(rb_scan_args, rbScanArgs);
90
+
91
+ return rbScanArgsOptional;
92
+ }
93
+
94
+ template<typename Function_T, bool IsMethod>
95
+ template<std::size_t... I>
96
+ typename NativeFunction<Function_T, IsMethod>::Arg_Ts NativeFunction<Function_T, IsMethod>::getNativeValues(std::vector<VALUE>& values,
97
+ std::index_sequence<I...>& indices)
98
+ {
99
+ // Convert each Ruby value to its native value by calling the appropriate fromRuby instance.
100
+ // Note that for fundamental types From_Ruby<Arg_Ts> will keep a copy of the native value
101
+ // so it can be passed by reference or pointer to a native function.
102
+ return std::forward_as_tuple(std::get<I>(this->fromRubys_).convert(values[I])...);
103
+ }
104
+
105
+ template<typename Function_T, bool IsMethod>
106
+ typename NativeFunction<Function_T, IsMethod>::Self_T NativeFunction<Function_T, IsMethod>::getSelf(VALUE self)
107
+ {
108
+ // There is no self parameter
109
+ if constexpr (std::is_same_v<Self_T, std::nullptr_t>)
110
+ {
111
+ return nullptr;
112
+ }
113
+ // Self parameter is a Ruby VALUE so no conversion is needed
114
+ else if constexpr (std::is_same_v<Self_T, VALUE>)
115
+ {
116
+ return self;
117
+ }
118
+ // Self parameter could be derived from Object or it is an C++ instdance and
119
+ // needs to be unwrapped from Ruby
120
+ else
121
+ {
122
+ return From_Ruby<Self_T>().convert(self);
123
+ }
124
+ }
125
+
126
+ template<typename Function_T, bool IsMethod>
127
+ VALUE NativeFunction<Function_T, IsMethod>::invokeNativeFunction(Arg_Ts& nativeArgs)
128
+ {
129
+ if constexpr (std::is_void_v<Return_T>)
130
+ {
131
+ std::apply(this->func_, nativeArgs);
132
+ return Qnil;
133
+ }
134
+ else
135
+ {
136
+ // Call the native method and get the result
137
+ Return_T nativeResult = std::apply(this->func_, nativeArgs);
138
+
139
+ // Return the result
140
+ return this->toRuby_.convert(nativeResult);
141
+ }
142
+ }
143
+
144
+ template<typename Function_T, bool IsMethod>
145
+ VALUE NativeFunction<Function_T, IsMethod>::invokeNativeMethod(VALUE self, Arg_Ts& nativeArgs)
146
+ {
147
+ Self_T receiver = this->getSelf(self);
148
+ auto selfAndNativeArgs = std::tuple_cat(std::forward_as_tuple(receiver), nativeArgs);
149
+
150
+ if constexpr (std::is_void_v<Return_T>)
151
+ {
152
+ std::apply(this->func_, selfAndNativeArgs);
153
+ return Qnil;
154
+ }
155
+ else
156
+ {
157
+ Return_T nativeResult = (Return_T)std::apply(this->func_, selfAndNativeArgs);
158
+
159
+ // Special handling if the method returns self. If so we do not want
160
+ // to create a new Ruby wrapper object and instead return self.
161
+ if constexpr (std::is_same_v<intrinsic_type<Return_T>, intrinsic_type<Self_T>>)
162
+ {
163
+ if constexpr (std::is_pointer_v<Return_T> && std::is_pointer_v<Self_T>)
164
+ {
165
+ if (nativeResult == receiver)
166
+ return self;
167
+ }
168
+ else if constexpr (std::is_pointer_v<Return_T> && std::is_reference_v<Self_T>)
169
+ {
170
+ if (nativeResult == &receiver)
171
+ return self;
172
+ }
173
+ else if constexpr (std::is_reference_v<Return_T> && std::is_pointer_v<Self_T>)
174
+ {
175
+ if (&nativeResult == receiver)
176
+ return self;
177
+ }
178
+ else if constexpr (std::is_reference_v<Return_T> && std::is_reference_v<Self_T>)
179
+ {
180
+ if (&nativeResult == &receiver)
181
+ return self;
182
+ }
183
+ }
184
+
185
+ return this->toRuby_.convert(nativeResult);
186
+ }
187
+ }
188
+
189
+ template<typename Function_T, bool IsMethod>
190
+ void NativeFunction<Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues)
191
+ {
192
+ // Check function arguments
193
+ Wrapper* selfWrapper = getWrapper(self);
194
+ for (const Arg& arg : (*this->methodInfo_))
195
+ {
196
+ if (arg.isKeepAlive)
197
+ {
198
+ selfWrapper->addKeepAlive(rubyValues[arg.position]);
199
+ }
200
+ }
201
+
202
+ // Check return value
203
+ if (this->methodInfo_->returnInfo.isKeepAlive)
204
+ {
205
+ Wrapper* returnWrapper = getWrapper(returnValue);
206
+ returnWrapper->addKeepAlive(self);
207
+ }
208
+ }
209
+
210
+ template<typename Function_T, bool IsMethod>
211
+ VALUE NativeFunction<Function_T, IsMethod>::operator()(int argc, VALUE* argv, VALUE self)
212
+ {
213
+ try
214
+ {
215
+ // Get the ruby values
216
+ std::vector<VALUE> rubyValues = this->getRubyValues(argc, argv);
217
+
218
+ auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
219
+
220
+ // Convert the Ruby values to native values
221
+ Arg_Ts nativeValues = this->getNativeValues(rubyValues, indices);
222
+
223
+ // Now call the native method
224
+ VALUE result = Qnil;
225
+ if constexpr (std::is_same_v<Self_T, std::nullptr_t>)
226
+ {
227
+ result = this->invokeNativeFunction(nativeValues);
228
+ }
229
+ else
230
+ {
231
+ result = this->invokeNativeMethod(self, nativeValues);
232
+ }
233
+
234
+ // Check if any function arguments or return values need to have their lifetimes tied to the receiver
235
+ this->checkKeepAlive(self, result, rubyValues);
236
+
237
+ return result;
238
+ }
239
+ catch (...)
240
+ {
241
+ RUBY_TRY
242
+ {
243
+ return this->handler_->handle_exception();
244
+ }
245
+ RUBY_CATCH
246
+ }
247
+ }
248
+ }