rice 4.7.1 → 4.8.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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/CMakeLists.txt +14 -22
  4. data/CMakePresets.json +203 -75
  5. data/FindRuby.cmake +358 -123
  6. data/bin/rice-doc.rb +56 -141
  7. data/include/rice/api.hpp +248 -0
  8. data/include/rice/rice.hpp +2237 -1657
  9. data/include/rice/stl.hpp +346 -443
  10. data/lib/rice/doc/config.rb +70 -0
  11. data/lib/rice/doc/cpp_reference.rb +1 -4
  12. data/lib/rice/doc/mkdocs.rb +58 -20
  13. data/lib/rice/doc/rice.rb +20 -0
  14. data/lib/rice/doc.rb +1 -0
  15. data/lib/rice/make_rice_headers.rb +7 -0
  16. data/lib/rice/native_registry.rb +2 -2
  17. data/lib/rice/rbs.rb +2 -2
  18. data/lib/rice/version.rb +1 -1
  19. data/lib/rubygems_plugin.rb +12 -9
  20. data/rice/Arg.hpp +12 -6
  21. data/rice/Arg.ipp +14 -7
  22. data/rice/Buffer.ipp +44 -40
  23. data/rice/Callback.hpp +1 -1
  24. data/rice/Callback.ipp +2 -7
  25. data/rice/Constructor.hpp +1 -1
  26. data/rice/Constructor.ipp +11 -11
  27. data/rice/Data_Object.ipp +15 -15
  28. data/rice/Data_Type.hpp +9 -10
  29. data/rice/Data_Type.ipp +22 -25
  30. data/rice/Director.hpp +1 -0
  31. data/rice/Enum.ipp +58 -39
  32. data/rice/Exception.hpp +4 -4
  33. data/rice/Exception.ipp +7 -7
  34. data/rice/NoGVL.hpp +13 -0
  35. data/rice/Reference.hpp +56 -0
  36. data/rice/Reference.ipp +96 -0
  37. data/rice/Return.hpp +4 -1
  38. data/rice/Return.ipp +0 -6
  39. data/rice/cpp_api/Array.hpp +41 -4
  40. data/rice/cpp_api/Array.ipp +105 -9
  41. data/rice/cpp_api/Class.hpp +2 -2
  42. data/rice/cpp_api/Class.ipp +4 -4
  43. data/rice/cpp_api/Hash.ipp +7 -4
  44. data/rice/cpp_api/Module.hpp +4 -4
  45. data/rice/cpp_api/Module.ipp +12 -10
  46. data/rice/cpp_api/Object.hpp +4 -4
  47. data/rice/cpp_api/Object.ipp +15 -12
  48. data/rice/cpp_api/String.hpp +2 -2
  49. data/rice/cpp_api/String.ipp +11 -8
  50. data/rice/cpp_api/Symbol.ipp +7 -7
  51. data/rice/cpp_api/shared_methods.hpp +5 -9
  52. data/rice/detail/InstanceRegistry.hpp +0 -2
  53. data/rice/detail/Native.hpp +31 -21
  54. data/rice/detail/Native.ipp +282 -130
  55. data/rice/detail/NativeAttributeGet.hpp +5 -7
  56. data/rice/detail/NativeAttributeGet.ipp +26 -26
  57. data/rice/detail/NativeAttributeSet.hpp +2 -4
  58. data/rice/detail/NativeAttributeSet.ipp +20 -16
  59. data/rice/detail/NativeCallback.hpp +77 -0
  60. data/rice/detail/NativeCallback.ipp +280 -0
  61. data/rice/detail/NativeFunction.hpp +11 -21
  62. data/rice/detail/NativeFunction.ipp +58 -119
  63. data/rice/detail/NativeInvoker.hpp +4 -4
  64. data/rice/detail/NativeInvoker.ipp +7 -7
  65. data/rice/detail/NativeIterator.hpp +2 -4
  66. data/rice/detail/NativeIterator.ipp +18 -14
  67. data/rice/detail/NativeMethod.hpp +10 -20
  68. data/rice/detail/NativeMethod.ipp +54 -114
  69. data/rice/detail/NativeProc.hpp +5 -7
  70. data/rice/detail/NativeProc.ipp +39 -28
  71. data/rice/detail/NativeRegistry.hpp +0 -1
  72. data/rice/detail/Parameter.hpp +15 -8
  73. data/rice/detail/Parameter.ipp +102 -43
  74. data/rice/detail/Proc.ipp +14 -28
  75. data/rice/detail/RubyType.ipp +2 -53
  76. data/rice/detail/Type.hpp +23 -7
  77. data/rice/detail/Type.ipp +73 -93
  78. data/rice/detail/TypeRegistry.ipp +5 -4
  79. data/rice/detail/Wrapper.hpp +1 -1
  80. data/rice/detail/Wrapper.ipp +18 -10
  81. data/rice/detail/from_ruby.hpp +8 -6
  82. data/rice/detail/from_ruby.ipp +306 -173
  83. data/rice/detail/ruby.hpp +23 -0
  84. data/rice/libc/file.hpp +4 -4
  85. data/rice/rice.hpp +6 -8
  86. data/rice/rice_api/Native.ipp +5 -1
  87. data/rice/rice_api/Parameter.ipp +1 -1
  88. data/rice/ruby_mark.hpp +2 -1
  89. data/rice/stl/complex.ipp +12 -8
  90. data/rice/stl/map.ipp +27 -22
  91. data/rice/stl/monostate.ipp +16 -12
  92. data/rice/stl/multimap.hpp +0 -2
  93. data/rice/stl/multimap.ipp +27 -22
  94. data/rice/stl/optional.ipp +27 -11
  95. data/rice/stl/pair.ipp +5 -5
  96. data/rice/stl/reference_wrapper.ipp +5 -4
  97. data/rice/stl/set.ipp +16 -16
  98. data/rice/stl/shared_ptr.hpp +0 -16
  99. data/rice/stl/shared_ptr.ipp +34 -190
  100. data/rice/stl/string.ipp +18 -18
  101. data/rice/stl/string_view.ipp +1 -1
  102. data/rice/stl/tuple.ipp +15 -36
  103. data/rice/stl/unique_ptr.ipp +18 -8
  104. data/rice/stl/unordered_map.ipp +20 -15
  105. data/rice/stl/variant.ipp +37 -21
  106. data/rice/stl/vector.ipp +41 -36
  107. data/rice/traits/function_traits.hpp +19 -19
  108. data/rice/traits/method_traits.hpp +4 -4
  109. data/rice/traits/rice_traits.hpp +162 -39
  110. data/rice.gemspec +1 -3
  111. data/test/test_Array.cpp +261 -3
  112. data/test/test_Attribute.cpp +6 -3
  113. data/test/test_Buffer.cpp +6 -42
  114. data/test/test_Callback.cpp +77 -23
  115. data/test/test_Data_Object.cpp +1 -1
  116. data/test/test_Data_Type.cpp +21 -22
  117. data/test/test_Director.cpp +2 -4
  118. data/test/test_Enum.cpp +34 -5
  119. data/test/test_File.cpp +9 -5
  120. data/test/test_From_Ruby.cpp +4 -3
  121. data/test/test_GVL.cpp +3 -3
  122. data/test/test_Hash.cpp +1 -1
  123. data/test/test_Iterator.cpp +54 -22
  124. data/test/test_Keep_Alive.cpp +1 -1
  125. data/test/test_Keep_Alive_No_Wrapper.cpp +1 -1
  126. data/test/test_Module.cpp +5 -5
  127. data/test/test_Overloads.cpp +345 -48
  128. data/test/test_Proc.cpp +54 -0
  129. data/test/test_Reference.cpp +181 -0
  130. data/test/test_Self.cpp +2 -2
  131. data/test/test_Stl_Set.cpp +6 -6
  132. data/test/test_Stl_SharedPtr.cpp +54 -30
  133. data/test/test_Stl_String_View.cpp +4 -2
  134. data/test/test_Stl_Tuple.cpp +1 -1
  135. data/test/test_Stl_Variant.cpp +6 -14
  136. data/test/test_Stl_Vector.cpp +61 -30
  137. data/test/test_String.cpp +4 -2
  138. data/test/test_Struct.cpp +1 -1
  139. data/test/test_Symbol.cpp +1 -1
  140. data/test/test_To_Ruby.cpp +1 -0
  141. data/test/test_Type.cpp +36 -35
  142. data/test/test_global_functions.cpp +1 -1
  143. data/test/unittest.cpp +1 -1
  144. data/test/unittest.hpp +5 -5
  145. metadata +10 -10
  146. data/rice/Function.hpp +0 -17
  147. data/rice/Function.ipp +0 -13
  148. data/rice/detail/MethodInfo.hpp +0 -48
  149. data/rice/detail/MethodInfo.ipp +0 -99
  150. data/rice/detail/NativeCallbackFFI.hpp +0 -55
  151. data/rice/detail/NativeCallbackFFI.ipp +0 -152
  152. data/rice/detail/NativeCallbackSimple.hpp +0 -30
  153. data/rice/detail/NativeCallbackSimple.ipp +0 -29
@@ -6,13 +6,14 @@
6
6
 
7
7
  namespace Rice::detail
8
8
  {
9
- template<typename Class_T, typename Method_T>
10
- void NativeMethod<Class_T, Method_T>::define(VALUE klass, std::string method_name, Method_T method, MethodInfo* methodInfo)
9
+ template<typename Class_T, typename Method_T, bool NoGVL>
10
+ template<typename ...Arg_Ts>
11
+ void NativeMethod<Class_T, Method_T, NoGVL>::define(VALUE klass, std::string method_name, Method_T method, Arg_Ts&& ...args)
11
12
  {
12
- // Verify return and argument types
13
- Native::verify_type<Return_T>(methodInfo->returnInfo()->isBuffer());
14
- auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
15
- Native::verify_args<Arg_Ts>(methodInfo, indices);
13
+ // Verify return type
14
+ using Arg_Tuple = std::tuple<Arg_Ts...>;
15
+ constexpr bool isBuffer = tuple_element_index_v<Arg_Tuple, ReturnBuffer> < std::tuple_size_v<Arg_Tuple>;
16
+ Native::verify_type<Return_T, isBuffer>();
16
17
 
17
18
  // Have we defined this method yet in Ruby?
18
19
  Identifier identifier(method_name);
@@ -23,24 +24,29 @@ namespace Rice::detail
23
24
  detail::protect(rb_define_method, klass, method_name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
24
25
  }
25
26
 
26
- // Create a NativeMethod instance and save it to the NativeRegistry. There may be multiple
27
- // NativeMethod instances for a specific method because C++ supports method overloading.
28
- NativeMethod_T* NativeMethod = new NativeMethod_T(klass, method_name, std::forward<Method_T>(method), methodInfo);
29
- std::unique_ptr<Native> native(NativeMethod);
27
+ // Create method parameters - this will also validate their types
28
+ std::vector<std::unique_ptr<ParameterAbstract>> parameters = Native::create_parameters<Parameter_Ts>(args...);
29
+
30
+ // Create return info
31
+ std::unique_ptr<Return> returnInfo = Native::create_return<Arg_Ts...>(args...);
32
+
33
+ // Create native method
34
+ NativeMethod_T* nativeMethod = new NativeMethod_T(klass, method_name, std::forward<Method_T>(method), std::move(returnInfo), std::move(parameters));
35
+ std::unique_ptr<Native> native(nativeMethod);
36
+
37
+ // Register the native method
30
38
  detail::Registries::instance.natives.add(klass, identifier.id(), native);
31
39
  }
32
40
 
33
- template<typename Class_T, typename Method_T>
34
- NativeMethod<Class_T, Method_T>::NativeMethod(VALUE klass, std::string method_name, Method_T method, MethodInfo* methodInfo)
35
- : Native(Native::create_parameters<Arg_Ts>(methodInfo)),
36
- klass_(klass), method_name_(method_name), method_(method), methodInfo_(methodInfo),
37
- toRuby_(methodInfo->returnInfo())
41
+ template<typename Class_T, typename Method_T, bool NoGVL>
42
+ NativeMethod<Class_T, Method_T, NoGVL>::NativeMethod(VALUE klass, std::string method_name, Method_T method, std::unique_ptr<Return>&& returnInfo, std::vector<std::unique_ptr<ParameterAbstract>>&& parameters)
43
+ : Native(method_name, std::move(returnInfo), std::move(parameters)),
44
+ klass_(klass), method_(method), toRuby_(returnInfo_.get())
38
45
  {
39
46
  }
40
47
 
41
- template<typename Class_T, typename Method_T>
42
- template<std::size_t... I>
43
- std::vector<std::string> NativeMethod<Class_T, Method_T>::argTypeNames(std::ostringstream& stream, std::index_sequence<I...>& indices)
48
+ template<typename Class_T, typename Method_T, bool NoGVL>
49
+ std::vector<std::string> NativeMethod<Class_T, Method_T, NoGVL>::argTypeNames()
44
50
  {
45
51
  std::vector<std::string> result;
46
52
  for (std::unique_ptr<ParameterAbstract>& parameter : this->parameters_)
@@ -50,26 +56,25 @@ namespace Rice::detail
50
56
  return result;
51
57
  }
52
58
 
53
- template<typename Class_T, typename Method_T>
54
- std::string NativeMethod<Class_T, Method_T>::toString()
59
+ template<typename Class_T, typename Method_T, bool NoGVL>
60
+ std::string NativeMethod<Class_T, Method_T, NoGVL>::toString()
55
61
  {
56
62
  std::ostringstream result;
57
63
 
58
- detail::TypeMapper<Return_T> typeReturnMapper;
59
- result << typeReturnMapper.simplifiedName() << " ";
64
+ detail::TypeIndexParser typeIndexParserReturn(typeid(Return_T), std::is_fundamental_v<detail::intrinsic_type<Return_T>>);
65
+ result << typeIndexParserReturn.simplifiedName() << " ";
60
66
 
61
67
  if (!std::is_null_pointer_v<Receiver_T>)
62
68
  {
63
- detail::TypeMapper<Receiver_T> typeReceiverMapper;
64
- result << typeReceiverMapper.simplifiedName() << "::";
69
+ detail::TypeIndexParser typeIndexParserReceiver(typeid(Receiver_T), std::is_fundamental_v<detail::intrinsic_type<Receiver_T>>);
70
+ result << typeIndexParserReceiver.simplifiedName() << "::";
65
71
  }
66
72
 
67
- result << this->method_name_;
73
+ result << this->name();
68
74
 
69
75
  result << "(";
70
76
 
71
- auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
72
- std::vector<std::string> argTypeNames = this->argTypeNames(result, indices);
77
+ std::vector<std::string> argTypeNames = this->argTypeNames();
73
78
  for (size_t i = 0; i < argTypeNames.size(); i++)
74
79
  {
75
80
  result << argTypeNames[i];
@@ -80,22 +85,22 @@ namespace Rice::detail
80
85
  return result.str();
81
86
  }
82
87
 
83
- template<typename Class_T, typename Method_T>
88
+ template<typename Class_T, typename Method_T, bool NoGVL>
84
89
  template<std::size_t... I>
85
- typename NativeMethod<Class_T, Method_T>::Apply_Args_T NativeMethod<Class_T, Method_T>::getNativeValues(VALUE self, std::vector<std::optional<VALUE>>& values, std::index_sequence<I...>& indices)
90
+ typename NativeMethod<Class_T, Method_T, NoGVL>::Apply_Args_T NativeMethod<Class_T, Method_T, NoGVL>::getNativeValues(VALUE self, std::vector<std::optional<VALUE>>& values, const std::index_sequence<I...>&)
86
91
  {
87
92
  /* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
88
- on the arguments (Arg_Ts) required by the C++ method. Arg_T may have const/volatile while
93
+ on the arguments (Parameter_Ts) required by the C++ method. Arg_T may have const/volatile while
89
94
  the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
90
95
  which we let the compiler convert to const values as needed. This works except for
91
96
  T** -> const T**, see comment in convertToNative method. */
92
97
  return std::forward_as_tuple(this->getReceiver(self),
93
- (dynamic_cast<Parameter<std::tuple_element_t<I, Arg_Ts>>*>(this->parameters_[I].get()))->
98
+ (dynamic_cast<Parameter<std::tuple_element_t<I, Parameter_Ts>>*>(this->parameters_[I].get()))->
94
99
  convertToNative(values[I])...);
95
100
  }
96
101
 
97
- template<typename Class_T, typename Method_T>
98
- typename NativeMethod<Class_T, Method_T>::Receiver_T NativeMethod<Class_T, Method_T>::getReceiver(VALUE self)
102
+ template<typename Class_T, typename Method_T, bool NoGVL>
103
+ typename NativeMethod<Class_T, Method_T, NoGVL>::Receiver_T NativeMethod<Class_T, Method_T, NoGVL>::getReceiver(VALUE self)
99
104
  {
100
105
  // Self parameter is a Ruby VALUE so no conversion is needed
101
106
  if constexpr (std::is_same_v<Receiver_T, VALUE>)
@@ -129,8 +134,8 @@ namespace Rice::detail
129
134
  }
130
135
  }
131
136
 
132
- template<typename Class_T, typename Method_T>
133
- inline VALUE NativeMethod<Class_T, Method_T>::invoke(VALUE self, Apply_Args_T&& nativeArgs)
137
+ template<typename Class_T, typename Method_T, bool NoGVL>
138
+ inline VALUE NativeMethod<Class_T, Method_T, NoGVL>::invoke(VALUE self, Apply_Args_T&& nativeArgs)
134
139
  {
135
140
  if constexpr (std::is_void_v<Return_T>)
136
141
  {
@@ -173,8 +178,8 @@ namespace Rice::detail
173
178
  }
174
179
  }
175
180
 
176
- template<typename Class_T, typename Method_T>
177
- inline VALUE NativeMethod<Class_T, Method_T>::invokeNoGVL(VALUE self, Apply_Args_T&& nativeArgs)
181
+ template<typename Class_T, typename Method_T, bool NoGVL>
182
+ inline VALUE NativeMethod<Class_T, Method_T, NoGVL>::invokeNoGVL(VALUE self, Apply_Args_T&& nativeArgs)
178
183
  {
179
184
  if constexpr (std::is_void_v<Return_T>)
180
185
  {
@@ -217,77 +222,17 @@ namespace Rice::detail
217
222
  }
218
223
  }
219
224
 
220
- template<typename Class_T, typename Method_T>
221
- inline void NativeMethod<Class_T, Method_T>::noWrapper(const VALUE klass, const std::string& wrapper)
222
- {
223
- std::stringstream message;
224
-
225
- message << "When calling the method `";
226
- message << this->method_name_;
227
- message << "' we could not find the wrapper for the '";
228
- message << rb_obj_classname(klass);
229
- message << "' ";
230
- message << wrapper;
231
- message << " type. You should not use keepAlive() on a Return or Arg that is a builtin Rice type.";
232
-
233
- throw std::runtime_error(message.str());
234
- }
235
-
236
- template<typename Class_T, typename Method_T>
237
- void NativeMethod<Class_T, Method_T>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues)
238
- {
239
- // Self will be Qnil for wrapped procs
240
- if (self == Qnil)
241
- return;
242
-
243
- // selfWrapper will be nullptr if this(self) is a builtin type and not an external(wrapped) type
244
- // it is highly unlikely that keepAlive is used in this case but we check anyway
245
- WrapperBase* selfWrapper = getWrapper(self);
246
-
247
- // Check method arguments
248
- for (const Arg& arg : (*this->methodInfo_))
249
- {
250
- if (arg.isKeepAlive())
251
- {
252
- if (selfWrapper == nullptr)
253
- {
254
- noWrapper(self, "self");
255
- }
256
- selfWrapper->addKeepAlive(rubyValues[arg.position].value());
257
- }
258
- }
259
-
260
- // Check return value
261
- if (this->methodInfo_->returnInfo()->isKeepAlive())
262
- {
263
- if (selfWrapper == nullptr)
264
- {
265
- noWrapper(self, "self");
266
- }
267
-
268
- // returnWrapper will be nullptr if returnValue is a built-in type and not an external(wrapped) type
269
- WrapperBase* returnWrapper = getWrapper(returnValue);
270
- if (returnWrapper == nullptr)
271
- {
272
- noWrapper(returnValue, "return");
273
- }
274
- returnWrapper->addKeepAlive(self);
275
- }
276
- }
277
-
278
- template<typename Class_T, typename Method_T>
279
- VALUE NativeMethod<Class_T, Method_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
225
+ template<typename Class_T, typename Method_T, bool NoGVL>
226
+ VALUE NativeMethod<Class_T, Method_T, NoGVL>::operator()(std::map<std::string, VALUE>& values, VALUE self)
280
227
  {
281
228
  // Get the ruby values and make sure we have the correct number
282
- std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, true);
283
- auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
229
+ std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(values, true);
230
+ auto indices = std::make_index_sequence<std::tuple_size_v<Parameter_Ts>>{};
284
231
  Apply_Args_T nativeArgs = this->getNativeValues(self, rubyValues, indices);
285
232
 
286
- bool noGvl = this->methodInfo_->function()->isNoGvl();
287
-
288
233
  VALUE result = Qnil;
289
234
 
290
- if (noGvl)
235
+ if constexpr (NoGVL)
291
236
  {
292
237
  result = this->invokeNoGVL(self, std::forward<Apply_Args_T>(nativeArgs));
293
238
  }
@@ -302,25 +247,20 @@ namespace Rice::detail
302
247
  return result;
303
248
  }
304
249
 
305
- template<typename Class_T, typename Method_T>
306
- inline std::string NativeMethod<Class_T, Method_T>::name()
307
- {
308
- return this->method_name_;
309
- }
310
-
311
- template<typename Class_T, typename Method_T>
312
- inline NativeKind NativeMethod<Class_T, Method_T>::kind()
250
+ template<typename Class_T, typename Method_T, bool NoGVL>
251
+ inline NativeKind NativeMethod<Class_T, Method_T, NoGVL>::kind()
313
252
  {
314
253
  return NativeKind::Method;
315
254
  }
316
255
 
317
- template<typename Class_T, typename Method_T>
318
- inline VALUE NativeMethod<Class_T, Method_T>::returnKlass()
256
+ template<typename Class_T, typename Method_T, bool NoGVL>
257
+ inline VALUE NativeMethod<Class_T, Method_T, NoGVL>::returnKlass()
319
258
  {
320
259
  // Check if an array is being returned
321
- if (this->methodInfo_->returnInfo()->isBuffer())
260
+ bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
261
+ if (isBuffer)
322
262
  {
323
- TypeMapper<Pointer<Return_T>> typeMapper;
263
+ TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Return_T>>>> typeMapper;
324
264
  return typeMapper.rubyKlass();
325
265
  }
326
266
  else
@@ -12,7 +12,7 @@ namespace Rice::detail
12
12
  // We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
13
13
  // have the concept of constants anyways
14
14
  using Return_T = typename function_traits<Proc_T>::return_type;
15
- using Arg_Ts = typename function_traits<Proc_T>::arg_types;
15
+ using Parameter_Ts = typename function_traits<Proc_T>::arg_types;
16
16
  using To_Ruby_T = remove_cv_recursive_t<Return_T>;
17
17
 
18
18
  // Define a new Ruby Proc to wrap a C++ function
@@ -23,11 +23,10 @@ namespace Rice::detail
23
23
  static VALUE resolve(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
24
24
 
25
25
  public:
26
- NativeProc(Proc_T proc, MethodInfo* methodInfo);
27
- VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
26
+ NativeProc(Proc_T proc, std::unique_ptr<Return>&& returnInfo, std::vector<std::unique_ptr<ParameterAbstract>>&& parameters);
27
+ VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
28
28
  std::string toString() override;
29
29
 
30
- std::string name() override;
31
30
  NativeKind kind() override;
32
31
  VALUE returnKlass() override;
33
32
 
@@ -36,14 +35,13 @@ namespace Rice::detail
36
35
 
37
36
  // Convert Ruby values to C++ values
38
37
  template<typename std::size_t...I>
39
- Arg_Ts getNativeValues(std::vector<std::optional<VALUE>>& values, std::index_sequence<I...>& indices);
38
+ Parameter_Ts getNativeValues(std::vector<std::optional<VALUE>>& values, std::index_sequence<I...>& indices);
40
39
 
41
40
  // Call the underlying C++ function
42
- VALUE invoke(Arg_Ts&& nativeArgs);
41
+ VALUE invoke(Parameter_Ts&& nativeArgs);
43
42
 
44
43
  private:
45
44
  Proc_T proc_;
46
- std::unique_ptr<MethodInfo> methodInfo_;
47
45
  To_Ruby<To_Ruby_T> toRuby_;
48
46
  };
49
47
  }
@@ -9,8 +9,13 @@ namespace Rice::detail
9
9
  template<typename Proc_T>
10
10
  NativeProc<Proc_T>* NativeProc<Proc_T>::define(Proc_T proc)
11
11
  {
12
- MethodInfo* methodInfo = new MethodInfo(detail::function_traits<Proc_T>::arity);
13
- return new NativeProc_T(std::forward<Proc_T>(proc), methodInfo);
12
+ // Create proc parameters
13
+ std::vector<std::unique_ptr<ParameterAbstract>> parameters = Native::create_parameters<Parameter_Ts>();
14
+
15
+ // Create return info
16
+ std::unique_ptr<Return> returnInfo = std::make_unique<Return>();
17
+
18
+ return new NativeProc_T(std::forward<Proc_T>(proc), std::move(returnInfo), std::move(parameters));
14
19
  }
15
20
 
16
21
  template<typename Proc_T>
@@ -30,19 +35,20 @@ namespace Rice::detail
30
35
 
31
36
  // Ruby calls this method when invoking a proc that was defined as a C++ function
32
37
  template<typename Proc_T>
33
- VALUE NativeProc<Proc_T>::resolve(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
38
+ VALUE NativeProc<Proc_T>::resolve(VALUE, VALUE callback_arg, int argc, const VALUE* argv, VALUE)
34
39
  {
35
40
  return cpp_protect([&]
36
41
  {
42
+ std::map<std::string, VALUE> values = readRubyArgs(argc, argv);
37
43
  NativeProc_T * native = (NativeProc_T*)callback_arg;
38
- return (*native)(argc, argv, Qnil);
44
+ return (*native)(values, Qnil);
39
45
  });
40
46
  }
41
47
 
42
48
  // Ruby calls this method if an instance of a NativeProc is owned by a Ruby proc. That happens when C++
43
49
  // returns a function back to Ruby
44
50
  template<typename Proc_T>
45
- VALUE NativeProc<Proc_T>::finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
51
+ VALUE NativeProc<Proc_T>::finalizerCallback(VALUE, VALUE callback_arg, int, const VALUE*, VALUE)
46
52
  {
47
53
  NativeProc_T* native = (NativeProc_T*)callback_arg;
48
54
  delete native;
@@ -50,8 +56,9 @@ namespace Rice::detail
50
56
  }
51
57
 
52
58
  template<typename Proc_T>
53
- NativeProc<Proc_T>::NativeProc(Proc_T proc, MethodInfo* methodInfo) : Native(Native::create_parameters<Arg_Ts>(methodInfo)),
54
- proc_(proc), methodInfo_(methodInfo)
59
+ NativeProc<Proc_T>::NativeProc(Proc_T proc, std::unique_ptr<Return>&& returnInfo, std::vector<std::unique_ptr<ParameterAbstract>>&& parameters)
60
+ : Native("proc", std::move(returnInfo), std::move(parameters)),
61
+ proc_(proc), toRuby_(returnInfo_.get())
55
62
  {
56
63
  }
57
64
 
@@ -63,32 +70,32 @@ namespace Rice::detail
63
70
 
64
71
  template<typename Proc_T>
65
72
  template<std::size_t... I>
66
- typename NativeProc<Proc_T>::Arg_Ts NativeProc<Proc_T>::getNativeValues(std::vector<std::optional<VALUE>>& values,
67
- std::index_sequence<I...>& indices)
73
+ typename NativeProc<Proc_T>::Parameter_Ts NativeProc<Proc_T>::getNativeValues(std::vector<std::optional<VALUE>>& values,
74
+ std::index_sequence<I...>&)
68
75
  {
69
76
  /* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
70
- on the arguments (Arg_Ts) required by the C++ function. Arg_T may have const/volatile while
77
+ on the arguments (Parameter_Ts) required by the C++ function. Arg_T may have const/volatile while
71
78
  the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
72
79
  which we let the compiler convert to const values as needed. This works except for
73
80
  T** -> const T**, see comment in convertToNative method. */
74
- //return std::forward_as_tuple(this->getNativeValue<std::tuple_element_t<I, Arg_Ts>, I>(values)...);
81
+ //return std::forward_as_tuple(this->getNativeValue<std::tuple_element_t<I, Parameter_Ts>, I>(values)...);
75
82
  return std::forward_as_tuple(
76
- (dynamic_cast<Parameter<std::tuple_element_t<I, Arg_Ts>>*>(this->parameters_[I].get()))->
83
+ (dynamic_cast<Parameter<std::tuple_element_t<I, Parameter_Ts>>*>(this->parameters_[I].get()))->
77
84
  convertToNative(values[I])...);
78
85
  }
79
86
 
80
87
  template<typename Proc_T>
81
- VALUE NativeProc<Proc_T>::invoke(Arg_Ts&& nativeArgs)
88
+ VALUE NativeProc<Proc_T>::invoke(Parameter_Ts&& nativeArgs)
82
89
  {
83
90
  if constexpr (std::is_void_v<Return_T>)
84
91
  {
85
- std::apply(this->proc_, std::forward<Arg_Ts>(nativeArgs));
92
+ std::apply(this->proc_, std::forward<Parameter_Ts>(nativeArgs));
86
93
  return Qnil;
87
94
  }
88
95
  else
89
96
  {
90
97
  // Call the native method and get the result
91
- Return_T nativeResult = std::apply(this->proc_, std::forward<Arg_Ts>(nativeArgs));
98
+ Return_T nativeResult = std::apply(this->proc_, std::forward<Parameter_Ts>(nativeArgs));
92
99
 
93
100
  // Return the result
94
101
  return this->toRuby_.convert(std::forward<Return_T>(nativeResult));
@@ -96,28 +103,22 @@ namespace Rice::detail
96
103
  }
97
104
 
98
105
  template<typename Proc_T>
99
- VALUE NativeProc<Proc_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
106
+ VALUE NativeProc<Proc_T>::operator()(std::map<std::string, VALUE>& values, VALUE)
100
107
  {
101
108
  // Get the ruby values and make sure we have the correct number
102
- std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, true);
109
+ std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(values, true);
103
110
 
104
- auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
111
+ auto indices = std::make_index_sequence<std::tuple_size_v<Parameter_Ts>>{};
105
112
 
106
113
  // Convert the Ruby values to native values
107
- Arg_Ts nativeValues = this->getNativeValues(rubyValues, indices);
114
+ Parameter_Ts nativeValues = this->getNativeValues(rubyValues, indices);
108
115
 
109
116
  // Now call the native method
110
- VALUE result = this->invoke(std::forward<Arg_Ts>(nativeValues));
117
+ VALUE result = this->invoke(std::forward<Parameter_Ts>(nativeValues));
111
118
 
112
119
  return result;
113
120
  }
114
121
 
115
- template<typename Proc_T>
116
- inline std::string NativeProc< Proc_T>::name()
117
- {
118
- return "proc";
119
- }
120
-
121
122
  template<typename Proc_T>
122
123
  inline NativeKind NativeProc< Proc_T>::kind()
123
124
  {
@@ -127,7 +128,17 @@ namespace Rice::detail
127
128
  template<typename Proc_T>
128
129
  inline VALUE NativeProc<Proc_T>::returnKlass()
129
130
  {
130
- TypeMapper<Return_T> typeMapper;
131
- return typeMapper.rubyKlass();
131
+ // Check if an array is being returned
132
+ bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
133
+ if (isBuffer)
134
+ {
135
+ TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Return_T>>>> typeMapper;
136
+ return typeMapper.rubyKlass();
137
+ }
138
+ else
139
+ {
140
+ TypeMapper<Return_T> typeMapper;
141
+ return typeMapper.rubyKlass();
142
+ }
132
143
  }
133
144
  }
@@ -1,7 +1,6 @@
1
1
  #ifndef Rice__detail__NativeRegistry__hpp
2
2
  #define Rice__detail__NativeRegistry__hpp
3
3
 
4
- #include <map>
5
4
  #include <memory>
6
5
  #include <utility>
7
6
 
@@ -8,19 +8,22 @@ namespace Rice::detail
8
8
  class ParameterAbstract
9
9
  {
10
10
  public:
11
- ParameterAbstract() = default;
12
- ParameterAbstract(Arg* arg);
11
+ ParameterAbstract(std::unique_ptr<Arg>&& arg);
13
12
  virtual ~ParameterAbstract() = default;
14
13
 
14
+ ParameterAbstract(const ParameterAbstract& other);
15
15
  ParameterAbstract(ParameterAbstract&& other) = default;
16
16
  ParameterAbstract& operator=(ParameterAbstract&& other) = default;
17
17
 
18
- virtual Convertible matches(std::optional<VALUE>& valueOpt) = 0;
18
+ virtual VALUE defaultValueRuby() = 0;
19
+ virtual double matches(std::optional<VALUE>& valueOpt) = 0;
19
20
  virtual std::string cppTypeName() = 0;
20
21
  virtual VALUE klass() = 0;
21
22
 
22
- public:
23
- Arg* arg = nullptr;
23
+ Arg* arg();
24
+
25
+ private:
26
+ std::unique_ptr<Arg> arg_;
24
27
  };
25
28
 
26
29
  template<typename T>
@@ -29,19 +32,23 @@ namespace Rice::detail
29
32
  public:
30
33
  using Type = T;
31
34
 
32
- Parameter() = default;
33
- Parameter(Arg* arg);
35
+ Parameter(std::unique_ptr<Arg>&& arg);
36
+ Parameter(const Parameter& other) = default;
34
37
  Parameter(Parameter&& other) = default;
35
38
  Parameter& operator=(Parameter&& other) = default;
36
39
 
37
40
  T convertToNative(std::optional<VALUE>& valueOpt);
38
- Convertible matches(std::optional<VALUE>& valueOpt) override;
41
+ VALUE convertToRuby(T& object);
42
+ VALUE defaultValueRuby() override;
43
+
44
+ double matches(std::optional<VALUE>& valueOpt) override;
39
45
  std::string cppTypeName() override;
40
46
  VALUE klass() override;
41
47
 
42
48
  // std::string typeName() override;
43
49
  private:
44
50
  From_Ruby<remove_cv_recursive_t<T>> fromRuby_;
51
+ To_Ruby<remove_cv_recursive_t<T>> toRuby_;
45
52
  };
46
53
  }
47
54
  #endif // Rice__detail__Parameter__hpp_