rice 3.0.0 → 4.0.0

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 (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
+ }