rice 2.1.3 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -0
  3. data/CONTRIBUTORS.md +19 -0
  4. data/COPYING +2 -2
  5. data/Gemfile +3 -0
  6. data/README.md +45 -1028
  7. data/Rakefile +95 -12
  8. data/include/rice/rice.hpp +7766 -0
  9. data/include/rice/stl.hpp +1113 -0
  10. data/lib/mkmf-rice.rb +127 -0
  11. data/lib/version.rb +3 -0
  12. data/rice/Address_Registration_Guard.ipp +75 -32
  13. data/rice/Address_Registration_Guard_defn.hpp +60 -56
  14. data/rice/Arg.hpp +80 -4
  15. data/rice/Arg.ipp +51 -0
  16. data/rice/Constructor.hpp +30 -376
  17. data/rice/Data_Object.ipp +234 -107
  18. data/rice/Data_Object_defn.hpp +77 -117
  19. data/rice/Data_Type.hpp +1 -2
  20. data/rice/Data_Type.ipp +251 -295
  21. data/rice/Data_Type_defn.hpp +175 -243
  22. data/rice/Director.hpp +14 -9
  23. data/rice/Enum.hpp +54 -104
  24. data/rice/Enum.ipp +104 -230
  25. data/rice/Exception.hpp +2 -8
  26. data/rice/Exception.ipp +65 -0
  27. data/rice/Exception_defn.hpp +46 -47
  28. data/rice/Identifier.hpp +28 -28
  29. data/rice/Identifier.ipp +23 -27
  30. data/rice/Return.hpp +39 -0
  31. data/rice/Return.ipp +33 -0
  32. data/rice/detail/Exception_Handler.ipp +22 -62
  33. data/rice/detail/Exception_Handler_defn.hpp +76 -91
  34. data/rice/detail/Iterator.hpp +18 -88
  35. data/rice/detail/Iterator.ipp +47 -0
  36. data/rice/detail/Jump_Tag.hpp +21 -0
  37. data/rice/detail/MethodInfo.hpp +44 -0
  38. data/rice/detail/MethodInfo.ipp +78 -0
  39. data/rice/detail/NativeAttribute.hpp +53 -0
  40. data/rice/detail/NativeAttribute.ipp +83 -0
  41. data/rice/detail/NativeFunction.hpp +69 -0
  42. data/rice/detail/NativeFunction.ipp +248 -0
  43. data/rice/detail/RubyFunction.hpp +39 -0
  44. data/rice/detail/RubyFunction.ipp +92 -0
  45. data/rice/detail/Type.hpp +29 -0
  46. data/rice/detail/Type.ipp +138 -0
  47. data/rice/detail/TypeRegistry.hpp +50 -0
  48. data/rice/detail/TypeRegistry.ipp +106 -0
  49. data/rice/detail/Wrapper.hpp +51 -0
  50. data/rice/detail/Wrapper.ipp +151 -0
  51. data/rice/detail/default_allocation_func.hpp +8 -19
  52. data/rice/detail/default_allocation_func.ipp +9 -8
  53. data/rice/detail/from_ruby.hpp +2 -37
  54. data/rice/detail/from_ruby.ipp +1020 -46
  55. data/rice/detail/from_ruby_defn.hpp +38 -0
  56. data/rice/detail/function_traits.hpp +124 -0
  57. data/rice/detail/method_data.hpp +23 -15
  58. data/rice/detail/method_data.ipp +53 -0
  59. data/rice/detail/rice_traits.hpp +116 -0
  60. data/rice/detail/ruby.hpp +9 -50
  61. data/rice/detail/to_ruby.hpp +3 -17
  62. data/rice/detail/to_ruby.ipp +409 -31
  63. data/rice/detail/to_ruby_defn.hpp +48 -0
  64. data/rice/forward_declares.ipp +82 -0
  65. data/rice/global_function.hpp +16 -20
  66. data/rice/global_function.ipp +8 -17
  67. data/rice/rice.hpp +59 -0
  68. data/rice/ruby_mark.hpp +5 -3
  69. data/rice/ruby_try_catch.hpp +4 -4
  70. data/rice/stl.hpp +11 -0
  71. data/sample/callbacks/extconf.rb +6 -0
  72. data/sample/callbacks/sample_callbacks.cpp +35 -0
  73. data/sample/callbacks/test.rb +28 -0
  74. data/sample/enum/extconf.rb +3 -0
  75. data/sample/enum/sample_enum.cpp +3 -17
  76. data/sample/enum/test.rb +2 -2
  77. data/sample/inheritance/animals.cpp +8 -24
  78. data/sample/inheritance/extconf.rb +3 -0
  79. data/sample/inheritance/test.rb +1 -1
  80. data/sample/map/extconf.rb +3 -0
  81. data/sample/map/map.cpp +10 -18
  82. data/sample/map/test.rb +1 -1
  83. data/test/embed_ruby.cpp +34 -0
  84. data/test/embed_ruby.hpp +4 -0
  85. data/test/ext/t1/extconf.rb +3 -0
  86. data/test/ext/t1/t1.cpp +1 -3
  87. data/test/ext/t2/extconf.rb +3 -0
  88. data/test/ext/t2/t2.cpp +1 -1
  89. data/test/extconf.rb +23 -0
  90. data/test/ruby/test_callbacks_sample.rb +28 -0
  91. data/test/ruby/test_multiple_extensions.rb +18 -0
  92. data/test/ruby/test_multiple_extensions_same_class.rb +14 -0
  93. data/test/ruby/test_multiple_extensions_with_inheritance.rb +20 -0
  94. data/test/test_Address_Registration_Guard.cpp +25 -11
  95. data/test/test_Array.cpp +131 -74
  96. data/test/test_Attribute.cpp +147 -0
  97. data/test/test_Builtin_Object.cpp +36 -15
  98. data/test/test_Class.cpp +151 -276
  99. data/test/test_Constructor.cpp +10 -9
  100. data/test/test_Data_Object.cpp +135 -193
  101. data/test/test_Data_Type.cpp +323 -252
  102. data/test/test_Director.cpp +56 -42
  103. data/test/test_Enum.cpp +230 -104
  104. data/test/test_Exception.cpp +7 -7
  105. data/test/test_Hash.cpp +33 -31
  106. data/test/test_Identifier.cpp +6 -6
  107. data/test/test_Inheritance.cpp +221 -0
  108. data/test/test_Iterator.cpp +161 -0
  109. data/test/test_Jump_Tag.cpp +1 -1
  110. data/test/test_Keep_Alive.cpp +161 -0
  111. data/test/test_Memory_Management.cpp +4 -5
  112. data/test/test_Module.cpp +169 -111
  113. data/test/test_Object.cpp +51 -19
  114. data/test/test_Ownership.cpp +275 -0
  115. data/test/test_Self.cpp +205 -0
  116. data/test/test_Stl_Optional.cpp +90 -0
  117. data/test/test_Stl_Pair.cpp +144 -0
  118. data/test/test_Stl_SmartPointer.cpp +200 -0
  119. data/test/test_Stl_String.cpp +74 -0
  120. data/test/test_Stl_Vector.cpp +652 -0
  121. data/test/test_String.cpp +3 -3
  122. data/test/test_Struct.cpp +31 -40
  123. data/test/test_Symbol.cpp +3 -3
  124. data/test/test_To_From_Ruby.cpp +283 -218
  125. data/test/test_global_functions.cpp +41 -20
  126. data/test/unittest.cpp +34 -8
  127. data/test/unittest.hpp +0 -4
  128. metadata +121 -136
  129. data/Doxyfile +0 -2268
  130. data/Makefile.am +0 -26
  131. data/Makefile.in +0 -923
  132. data/README.mingw +0 -8
  133. data/aclocal.m4 +0 -1088
  134. data/bootstrap +0 -8
  135. data/check_stdcxx_11.ac +0 -103
  136. data/config.guess +0 -1421
  137. data/config.sub +0 -1807
  138. data/configure +0 -7367
  139. data/configure.ac +0 -55
  140. data/depcomp +0 -791
  141. data/doxygen.ac +0 -314
  142. data/doxygen.am +0 -186
  143. data/extconf.rb +0 -69
  144. data/install-sh +0 -501
  145. data/missing +0 -215
  146. data/post-autoconf.rb +0 -22
  147. data/post-automake.rb +0 -28
  148. data/rice/Address_Registration_Guard.cpp +0 -22
  149. data/rice/Arg_impl.hpp +0 -129
  150. data/rice/Arg_operators.cpp +0 -21
  151. data/rice/Arg_operators.hpp +0 -19
  152. data/rice/Array.hpp +0 -214
  153. data/rice/Array.ipp +0 -256
  154. data/rice/Builtin_Object.hpp +0 -8
  155. data/rice/Builtin_Object.ipp +0 -50
  156. data/rice/Builtin_Object_defn.hpp +0 -50
  157. data/rice/Class.cpp +0 -57
  158. data/rice/Class.hpp +0 -8
  159. data/rice/Class.ipp +0 -6
  160. data/rice/Class_defn.hpp +0 -83
  161. data/rice/Data_Type.cpp +0 -54
  162. data/rice/Data_Type_fwd.hpp +0 -12
  163. data/rice/Director.cpp +0 -13
  164. data/rice/Exception.cpp +0 -59
  165. data/rice/Exception_Base.hpp +0 -8
  166. data/rice/Exception_Base.ipp +0 -13
  167. data/rice/Exception_Base_defn.hpp +0 -27
  168. data/rice/Hash.hpp +0 -227
  169. data/rice/Hash.ipp +0 -329
  170. data/rice/Identifier.cpp +0 -8
  171. data/rice/Jump_Tag.hpp +0 -24
  172. data/rice/Makefile.am +0 -125
  173. data/rice/Makefile.in +0 -888
  174. data/rice/Module.cpp +0 -84
  175. data/rice/Module.hpp +0 -8
  176. data/rice/Module.ipp +0 -6
  177. data/rice/Module_defn.hpp +0 -88
  178. data/rice/Module_impl.hpp +0 -281
  179. data/rice/Module_impl.ipp +0 -345
  180. data/rice/Object.cpp +0 -169
  181. data/rice/Object.hpp +0 -8
  182. data/rice/Object.ipp +0 -19
  183. data/rice/Object_defn.hpp +0 -191
  184. data/rice/Require_Guard.hpp +0 -21
  185. data/rice/String.cpp +0 -94
  186. data/rice/String.hpp +0 -91
  187. data/rice/Struct.cpp +0 -117
  188. data/rice/Struct.hpp +0 -162
  189. data/rice/Struct.ipp +0 -26
  190. data/rice/Symbol.cpp +0 -25
  191. data/rice/Symbol.hpp +0 -66
  192. data/rice/Symbol.ipp +0 -44
  193. data/rice/config.hpp +0 -47
  194. data/rice/config.hpp.in +0 -46
  195. data/rice/detail/Arguments.hpp +0 -118
  196. data/rice/detail/Auto_Function_Wrapper.hpp +0 -898
  197. data/rice/detail/Auto_Function_Wrapper.ipp +0 -3694
  198. data/rice/detail/Auto_Member_Function_Wrapper.hpp +0 -897
  199. data/rice/detail/Auto_Member_Function_Wrapper.ipp +0 -2774
  200. data/rice/detail/Caster.hpp +0 -103
  201. data/rice/detail/Not_Copyable.hpp +0 -25
  202. data/rice/detail/Wrapped_Function.hpp +0 -33
  203. data/rice/detail/cfp.hpp +0 -24
  204. data/rice/detail/cfp.ipp +0 -51
  205. data/rice/detail/check_ruby_type.cpp +0 -27
  206. data/rice/detail/check_ruby_type.hpp +0 -23
  207. data/rice/detail/creation_funcs.hpp +0 -37
  208. data/rice/detail/creation_funcs.ipp +0 -36
  209. data/rice/detail/define_method_and_auto_wrap.hpp +0 -31
  210. data/rice/detail/define_method_and_auto_wrap.ipp +0 -30
  211. data/rice/detail/demangle.cpp +0 -56
  212. data/rice/detail/demangle.hpp +0 -19
  213. data/rice/detail/env.hpp +0 -11
  214. data/rice/detail/method_data.cpp +0 -86
  215. data/rice/detail/node.hpp +0 -13
  216. data/rice/detail/object_call.hpp +0 -69
  217. data/rice/detail/object_call.ipp +0 -131
  218. data/rice/detail/protect.cpp +0 -29
  219. data/rice/detail/protect.hpp +0 -34
  220. data/rice/detail/ruby_version_code.hpp +0 -6
  221. data/rice/detail/ruby_version_code.hpp.in +0 -6
  222. data/rice/detail/st.hpp +0 -22
  223. data/rice/detail/traits.hpp +0 -43
  224. data/rice/detail/win32.hpp +0 -16
  225. data/rice/detail/wrap_function.hpp +0 -341
  226. data/rice/detail/wrap_function.ipp +0 -514
  227. data/rice/protect.hpp +0 -92
  228. data/rice/protect.ipp +0 -1134
  229. data/rice/rubypp.rb +0 -97
  230. data/rice/to_from_ruby.hpp +0 -8
  231. data/rice/to_from_ruby.ipp +0 -294
  232. data/rice/to_from_ruby_defn.hpp +0 -70
  233. data/ruby.ac +0 -135
  234. data/ruby/Makefile.am +0 -1
  235. data/ruby/Makefile.in +0 -628
  236. data/ruby/lib/Makefile.am +0 -3
  237. data/ruby/lib/Makefile.in +0 -506
  238. data/ruby/lib/mkmf-rice.rb.in +0 -217
  239. data/ruby/lib/version.rb +0 -3
  240. data/sample/Makefile.am +0 -47
  241. data/sample/Makefile.in +0 -489
  242. data/test/Makefile.am +0 -72
  243. data/test/Makefile.in +0 -1213
  244. data/test/ext/Makefile.am +0 -41
  245. data/test/ext/Makefile.in +0 -483
  246. data/test/test_rice.rb +0 -41
@@ -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
+ }