rice 4.6.0 → 4.7.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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/CMakeLists.txt +0 -4
  4. data/Rakefile +2 -8
  5. data/bin/rice-doc.rb +212 -0
  6. data/bin/rice-rbs.rb +93 -0
  7. data/include/rice/rice.hpp +5221 -4009
  8. data/include/rice/stl.hpp +822 -295
  9. data/lib/rice/doc/cpp_reference.rb +166 -0
  10. data/lib/rice/doc/doxygen.rb +294 -0
  11. data/lib/rice/doc/mkdocs.rb +298 -0
  12. data/lib/rice/doc/rice.rb +29 -0
  13. data/lib/rice/doc/ruby.rb +37 -0
  14. data/lib/rice/doc.rb +5 -0
  15. data/lib/{make_rice_headers.rb → rice/make_rice_headers.rb} +3 -0
  16. data/lib/rice/native.rb +18 -0
  17. data/lib/rice/native_registry.rb +21 -0
  18. data/lib/rice/parameter.rb +7 -0
  19. data/lib/rice/rbs.rb +104 -0
  20. data/lib/rice/version.rb +1 -1
  21. data/lib/rice.rb +4 -0
  22. data/lib/rubygems/cmake_builder.rb +24 -27
  23. data/rice/Arg.hpp +4 -4
  24. data/rice/Arg.ipp +4 -4
  25. data/rice/Buffer.hpp +77 -28
  26. data/rice/Buffer.ipp +500 -183
  27. data/rice/Data_Object.ipp +101 -82
  28. data/rice/Data_Type.hpp +7 -6
  29. data/rice/Data_Type.ipp +77 -47
  30. data/rice/Enum.ipp +15 -21
  31. data/rice/Function.hpp +17 -0
  32. data/rice/Function.ipp +13 -0
  33. data/rice/Pointer.hpp +15 -0
  34. data/rice/Pointer.ipp +49 -0
  35. data/rice/Return.hpp +1 -1
  36. data/rice/Return.ipp +2 -2
  37. data/rice/api.hpp +30 -0
  38. data/rice/cpp_api/Array.hpp +2 -2
  39. data/rice/cpp_api/Array.ipp +50 -5
  40. data/rice/cpp_api/Class.hpp +0 -5
  41. data/rice/cpp_api/Class.ipp +19 -0
  42. data/rice/cpp_api/Hash.ipp +20 -0
  43. data/rice/cpp_api/Module.hpp +6 -3
  44. data/rice/cpp_api/Module.ipp +49 -11
  45. data/rice/cpp_api/Object.ipp +31 -2
  46. data/rice/cpp_api/String.hpp +1 -2
  47. data/rice/cpp_api/String.ipp +21 -1
  48. data/rice/cpp_api/Struct.ipp +5 -0
  49. data/rice/cpp_api/Symbol.ipp +34 -0
  50. data/rice/cpp_api/shared_methods.hpp +12 -12
  51. data/rice/detail/MethodInfo.hpp +4 -2
  52. data/rice/detail/MethodInfo.ipp +19 -3
  53. data/rice/detail/ModuleRegistry.hpp +18 -0
  54. data/rice/detail/ModuleRegistry.ipp +25 -0
  55. data/rice/detail/Native.hpp +45 -2
  56. data/rice/detail/Native.ipp +196 -2
  57. data/rice/detail/NativeAttributeGet.hpp +9 -4
  58. data/rice/detail/NativeAttributeGet.ipp +73 -8
  59. data/rice/detail/NativeAttributeSet.hpp +4 -0
  60. data/rice/detail/NativeAttributeSet.ipp +33 -23
  61. data/rice/detail/NativeCallbackFFI.ipp +3 -2
  62. data/rice/detail/NativeCallbackSimple.ipp +1 -1
  63. data/rice/detail/NativeFunction.hpp +11 -49
  64. data/rice/detail/NativeFunction.ipp +83 -379
  65. data/rice/detail/NativeInvoker.hpp +74 -0
  66. data/rice/detail/NativeInvoker.ipp +197 -0
  67. data/rice/detail/NativeIterator.hpp +4 -0
  68. data/rice/detail/NativeIterator.ipp +19 -0
  69. data/rice/detail/NativeMethod.hpp +97 -0
  70. data/rice/detail/NativeMethod.ipp +332 -0
  71. data/rice/detail/NativeProc.hpp +51 -0
  72. data/rice/detail/NativeProc.ipp +133 -0
  73. data/rice/detail/NativeRegistry.hpp +8 -0
  74. data/rice/detail/NativeRegistry.ipp +27 -0
  75. data/rice/detail/Parameter.hpp +47 -0
  76. data/rice/detail/Parameter.ipp +105 -0
  77. data/rice/detail/Proc.ipp +14 -13
  78. data/rice/detail/Registries.hpp +1 -0
  79. data/rice/detail/RubyType.hpp +0 -2
  80. data/rice/detail/RubyType.ipp +15 -33
  81. data/rice/detail/Type.hpp +44 -8
  82. data/rice/detail/Type.ipp +150 -49
  83. data/rice/detail/TypeRegistry.hpp +3 -0
  84. data/rice/detail/TypeRegistry.ipp +17 -27
  85. data/rice/detail/Types.ipp +430 -0
  86. data/rice/detail/Wrapper.hpp +12 -0
  87. data/rice/detail/Wrapper.ipp +45 -2
  88. data/rice/detail/from_ruby.ipp +567 -1073
  89. data/rice/detail/ruby.hpp +1 -0
  90. data/rice/detail/to_ruby.ipp +4 -635
  91. data/rice/libc/file.ipp +3 -6
  92. data/rice/rice.hpp +22 -12
  93. data/rice/rice_api/Arg.hpp +7 -0
  94. data/rice/rice_api/Arg.ipp +9 -0
  95. data/rice/rice_api/ModuleRegistry.hpp +7 -0
  96. data/rice/rice_api/ModuleRegistry.ipp +10 -0
  97. data/rice/rice_api/Native.hpp +7 -0
  98. data/rice/rice_api/Native.ipp +52 -0
  99. data/rice/rice_api/NativeRegistry.hpp +7 -0
  100. data/rice/rice_api/NativeRegistry.ipp +21 -0
  101. data/rice/rice_api/Parameter.hpp +7 -0
  102. data/rice/rice_api/Parameter.ipp +11 -0
  103. data/rice/rice_api/Registries.hpp +6 -0
  104. data/rice/rice_api/Registries.ipp +12 -0
  105. data/rice/rice_api/TypeRegistry.hpp +7 -0
  106. data/rice/rice_api/TypeRegistry.ipp +10 -0
  107. data/rice/stl/complex.ipp +35 -0
  108. data/rice/stl/exception.ipp +20 -7
  109. data/rice/stl/filesystem.hpp +6 -0
  110. data/rice/stl/filesystem.ipp +34 -0
  111. data/rice/stl/map.ipp +13 -21
  112. data/rice/stl/monostate.ipp +37 -1
  113. data/rice/stl/multimap.ipp +17 -24
  114. data/rice/stl/optional.ipp +47 -2
  115. data/rice/stl/pair.ipp +23 -58
  116. data/rice/stl/reference_wrapper.ipp +22 -1
  117. data/rice/stl/set.ipp +17 -9
  118. data/rice/stl/shared_ptr.ipp +44 -17
  119. data/rice/stl/string.ipp +175 -7
  120. data/rice/stl/string_view.ipp +5 -0
  121. data/rice/stl/tuple.ipp +38 -9
  122. data/rice/stl/unique_ptr.ipp +46 -2
  123. data/rice/stl/unordered_map.ipp +13 -21
  124. data/rice/stl/variant.ipp +47 -11
  125. data/rice/stl/vector.ipp +182 -104
  126. data/rice/stl.hpp +1 -0
  127. data/rice/traits/attribute_traits.hpp +6 -6
  128. data/rice/traits/function_traits.hpp +2 -2
  129. data/rice/traits/method_traits.hpp +5 -16
  130. data/rice/traits/rice_traits.hpp +36 -4
  131. data/rice.gemspec +11 -22
  132. data/test/embed_ruby.cpp +0 -3
  133. data/test/test_Array.cpp +38 -38
  134. data/test/test_Attribute.cpp +244 -10
  135. data/test/test_Buffer.cpp +344 -13
  136. data/test/test_Callback.cpp +2 -3
  137. data/test/test_Class.cpp +5 -5
  138. data/test/test_Data_Object.cpp +0 -55
  139. data/test/test_Data_Type.cpp +19 -30
  140. data/test/test_Enum.cpp +4 -46
  141. data/test/test_From_Ruby.cpp +89 -82
  142. data/test/test_GVL.cpp +109 -0
  143. data/test/test_Iterator.cpp +1 -1
  144. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -3
  145. data/test/test_Module.cpp +8 -9
  146. data/test/test_Object.cpp +1 -1
  147. data/test/test_Overloads.cpp +3 -3
  148. data/test/test_Stl_Map.cpp +8 -8
  149. data/test/test_Stl_Multimap.cpp +4 -4
  150. data/test/test_Stl_Pair.cpp +5 -3
  151. data/test/test_Stl_SharedPtr.cpp +24 -12
  152. data/test/test_Stl_Tuple.cpp +1 -1
  153. data/test/test_Stl_UniquePtr.cpp +8 -0
  154. data/test/test_Stl_Unordered_Map.cpp +9 -9
  155. data/test/test_Stl_Variant.cpp +9 -3
  156. data/test/test_Stl_Vector.cpp +118 -13
  157. data/test/test_To_Ruby.cpp +35 -28
  158. data/test/test_Type.cpp +256 -53
  159. data/test/unittest.hpp +35 -0
  160. metadata +66 -34
  161. data/rice/Init.hpp +0 -8
  162. data/rice/Init.ipp +0 -8
  163. data/rice/detail/RubyFunction.hpp +0 -31
  164. data/rice/detail/RubyFunction.ipp +0 -76
  165. data/sample/callbacks/extconf.rb +0 -5
  166. data/sample/callbacks/sample_callbacks.cpp +0 -35
  167. data/sample/callbacks/test.rb +0 -28
  168. data/sample/enum/extconf.rb +0 -5
  169. data/sample/enum/sample_enum.cpp +0 -40
  170. data/sample/enum/test.rb +0 -8
  171. data/sample/inheritance/animals.cpp +0 -82
  172. data/sample/inheritance/extconf.rb +0 -5
  173. data/sample/inheritance/test.rb +0 -7
  174. data/sample/map/extconf.rb +0 -5
  175. data/sample/map/map.cpp +0 -73
  176. data/sample/map/test.rb +0 -7
  177. data/test/ext/t1/Foo.hpp +0 -10
  178. data/test/ext/t1/extconf.rb +0 -4
  179. data/test/ext/t1/t1.cpp +0 -13
  180. data/test/ext/t2/extconf.rb +0 -4
  181. data/test/ext/t2/t2.cpp +0 -11
  182. data/test/ruby/test_callbacks_sample.rb +0 -28
  183. data/test/ruby/test_multiple_extensions.rb +0 -18
  184. data/test/ruby/test_multiple_extensions_same_class.rb +0 -14
  185. data/test/ruby/test_multiple_extensions_with_inheritance.rb +0 -20
  186. /data/test/{test_Stl_Type.cpp → test_Stl_Type_Info.cpp} +0 -0
@@ -30,11 +30,11 @@ inline auto& include_module(Module const& inc)
30
30
  * \param args a list of Arg instance used to define default parameters.
31
31
  * \return *this
32
32
  */
33
- template<typename Function_T, typename...Arg_Ts>
34
- inline auto& define_method(std::string name, Function_T&& func, const Arg_Ts&...args)
33
+ template<typename Method_T, typename...Arg_Ts>
34
+ inline auto& define_method(std::string name, Method_T&& method, const Arg_Ts&...args)
35
35
  {
36
- MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, true>::arity, args...);
37
- this->wrap_native_call<true>(this->value(), name, std::forward<Function_T>(func), methodInfo);
36
+ MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Method_T>::arity, args...);
37
+ this->wrap_native_method(this->value(), name, std::forward<Method_T>(method), methodInfo);
38
38
  return *this;
39
39
  }
40
40
 
@@ -52,8 +52,8 @@ inline auto& define_method(std::string name, Function_T&& func, const Arg_Ts&...
52
52
  template<typename Function_T, typename...Arg_Ts>
53
53
  inline auto& define_function(std::string name, Function_T&& func, const Arg_Ts&...args)
54
54
  {
55
- MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, false>::arity, args...);
56
- this->wrap_native_call<false>(this->value(), name, std::forward<Function_T>(func), methodInfo);
55
+ MethodInfo* methodInfo = new MethodInfo(detail::function_traits<Function_T>::arity, args...);
56
+ this->wrap_native_function(this->value(), name, std::forward<Function_T>(func), methodInfo);
57
57
  return *this;
58
58
  }
59
59
 
@@ -72,11 +72,11 @@ inline auto& define_function(std::string name, Function_T&& func, const Arg_Ts&.
72
72
  * \param args a list of Arg instance used to define default parameters (optional)
73
73
  * \return *this
74
74
  */
75
- template<typename Function_T, typename...Arg_Ts>
76
- inline auto& define_singleton_method(std::string name, Function_T&& func, const Arg_Ts&...args)
75
+ template<typename Method_T, typename...Arg_Ts>
76
+ inline auto& define_singleton_method(std::string name, Method_T&& method, const Arg_Ts&...args)
77
77
  {
78
- MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, true>::arity, args...);
79
- this->wrap_native_call<true>(rb_singleton_class(*this), name, std::forward<Function_T>(func), methodInfo);
78
+ MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Method_T>::arity, args...);
79
+ this->wrap_native_method(rb_singleton_class(*this), name, std::forward<Method_T>(method), methodInfo);
80
80
  return *this;
81
81
  }
82
82
 
@@ -94,8 +94,8 @@ inline auto& define_singleton_method(std::string name, Function_T&& func, const
94
94
  template<typename Function_T, typename...Arg_Ts>
95
95
  inline auto& define_singleton_function(std::string name, Function_T&& func, const Arg_Ts& ...args)
96
96
  {
97
- MethodInfo* methodInfo = new MethodInfo(detail::method_traits<Function_T, false>::arity, args...);
98
- this->wrap_native_call<false>(rb_singleton_class(*this), name, std::forward<Function_T>(func), methodInfo);
97
+ MethodInfo* methodInfo = new MethodInfo(detail::function_traits<Function_T>::arity, args...);
98
+ this->wrap_native_function(rb_singleton_class(*this), name, std::forward<Function_T>(func), methodInfo);
99
99
  return *this;
100
100
  }
101
101
 
@@ -29,18 +29,20 @@ namespace Rice
29
29
  Arg* arg(std::string name);
30
30
 
31
31
  int argCount();
32
+ Return* returnInfo();
33
+ Function* function();
32
34
 
33
35
  // Iterator support
34
36
  std::vector<Arg>::iterator begin();
35
37
  std::vector<Arg>::iterator end();
36
38
 
37
- Return returnInfo;
38
-
39
39
  private:
40
40
  template <typename Arg_T>
41
41
  void processArg(const Arg_T& arg);
42
42
 
43
43
  std::vector<Arg> args_;
44
+ Return returnInfo_;
45
+ Function function_;
44
46
  };
45
47
  }
46
48
  #endif // Rice__MethodInfo__hpp_
@@ -25,16 +25,22 @@ namespace Rice
25
25
  template <typename Arg_T>
26
26
  inline void MethodInfo::processArg(const Arg_T& arg)
27
27
  {
28
- static_assert(std::is_same_v<Arg_T, Return> || std::is_same_v<Arg_T, Arg>, "Unknown argument type");
29
-
30
28
  if constexpr (std::is_same_v<Arg_T, Return>)
31
29
  {
32
- this->returnInfo = arg;
30
+ this->returnInfo_ = arg;
31
+ }
32
+ else if constexpr (std::is_same_v<Arg_T, Function>)
33
+ {
34
+ this->function_ = arg;
33
35
  }
34
36
  else if constexpr (std::is_same_v<Arg_T, Arg>)
35
37
  {
36
38
  this->addArg(arg);
37
39
  }
40
+ else
41
+ {
42
+ static_assert(true, "Unknown argument type");
43
+ }
38
44
  }
39
45
 
40
46
  inline void MethodInfo::addArg(const Arg& arg)
@@ -71,6 +77,16 @@ namespace Rice
71
77
  return nullptr;
72
78
  }
73
79
 
80
+ inline Return* MethodInfo::returnInfo()
81
+ {
82
+ return &this->returnInfo_;
83
+ }
84
+
85
+ inline Function* MethodInfo::function()
86
+ {
87
+ return &this->function_;
88
+ }
89
+
74
90
  inline std::vector<Arg>::iterator MethodInfo::begin()
75
91
  {
76
92
  return this->args_.begin();
@@ -0,0 +1,18 @@
1
+ #ifndef Rice__ModuleRegistry__hpp_
2
+ #define Rice__ModuleRegistry__hpp_
3
+
4
+ namespace Rice::detail
5
+ {
6
+ class ModuleRegistry
7
+ {
8
+ public:
9
+ void add(VALUE module);
10
+ // API for access from Ruby
11
+ VALUE modules();
12
+
13
+ private:
14
+ std::set<VALUE> modules_{};
15
+ };
16
+ }
17
+
18
+ #endif // Rice__ModuleRegistry__hpp_
@@ -0,0 +1,25 @@
1
+ #include <iostream>
2
+ #include <stdexcept>
3
+ #include <sstream>
4
+ #include <typeindex>
5
+
6
+
7
+ namespace Rice::detail
8
+ {
9
+ inline void ModuleRegistry::add(VALUE module)
10
+ {
11
+ this->modules_.insert(module);
12
+ }
13
+
14
+ inline VALUE ModuleRegistry::modules()
15
+ {
16
+ Array result;
17
+
18
+ for (const VALUE& value : this->modules_)
19
+ {
20
+ Module module(value);
21
+ result.push(module, false);
22
+ }
23
+ return result;
24
+ }
25
+ }
@@ -16,17 +16,60 @@ namespace Rice::detail
16
16
  Native* native;
17
17
  };
18
18
 
19
+ enum class NativeKind
20
+ {
21
+ Function,
22
+ Method,
23
+ Iterator,
24
+ AttributeReader,
25
+ AttributeWriter,
26
+ Proc
27
+ };
28
+
19
29
  class Native
20
30
  {
21
31
  public:
22
32
  static VALUE resolve(int argc, VALUE* argv, VALUE self);
23
33
  public:
34
+ Native() = default;
35
+ Native(std::vector<std::unique_ptr<ParameterAbstract>>&& parameters);
24
36
  virtual ~Native() = default;
25
- VALUE call(int argc, VALUE* argv, VALUE self);
26
37
 
27
- virtual Resolved matches(size_t argc, const VALUE* argv, VALUE self) = 0;
38
+ Native(const Native&) = delete;
39
+ Native(Native&&) = delete;
40
+ void operator=(const Native&) = delete;
41
+ void operator=(Native&&) = delete;
42
+
43
+ virtual Resolved matches(size_t argc, const VALUE* argv, VALUE self);
28
44
  virtual VALUE operator()(size_t argc, const VALUE* argv, VALUE self) = 0;
29
45
  virtual std::string toString() = 0;
46
+
47
+ // Ruby API access
48
+ virtual std::string name() = 0;
49
+ virtual NativeKind kind() = 0;
50
+ virtual VALUE returnKlass() = 0;
51
+ std::vector<const ParameterAbstract*> parameters();
52
+
53
+ protected:
54
+ template<typename T>
55
+ static void verify_type(bool isBuffer);
56
+
57
+ template<typename Tuple_T, std::size_t ...Indices>
58
+ static void verify_args(MethodInfo* methodInfo, std::index_sequence<Indices...> indices);
59
+
60
+ std::vector<std::optional<VALUE>> getRubyValues(size_t argc, const VALUE* argv, bool validate);
61
+ ParameterAbstract* getParameterByName(std::string name);
62
+ Convertible matchParameters(std::vector<std::optional<VALUE>>& values);
63
+
64
+ template<typename Tuple_T>
65
+ static std::vector<std::unique_ptr<ParameterAbstract>> create_parameters(MethodInfo* methodInfo);
66
+
67
+ template<typename Tuple_T, std::size_t ...Indices>
68
+ static inline void create_parameters_impl(std::vector<std::unique_ptr<ParameterAbstract>>& parameters, MethodInfo* methodInfo, std::index_sequence<Indices...> indices);
69
+
70
+ protected:
71
+ std::vector<std::unique_ptr<ParameterAbstract>> parameters_;
72
+
30
73
  };
31
74
  }
32
75
 
@@ -79,7 +79,7 @@ namespace Rice::detail
79
79
  else if (natives.size() == 0)
80
80
  {
81
81
  Identifier identifier(methodId);
82
- rb_raise(rb_eArgError, "Could not find method call for %s#%s", rb_class2name(klass), identifier.c_str());
82
+ rb_enc_raise(rb_utf8_encoding(), rb_eArgError, "Could not find method call for %s#%s", rb_class2name(klass), identifier.c_str());
83
83
  }
84
84
  else
85
85
  {
@@ -145,7 +145,7 @@ namespace Rice::detail
145
145
  message << "\n " << resolve.native->toString();
146
146
  }
147
147
 
148
- rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), natives.size());
148
+ rb_enc_raise(rb_utf8_encoding(), rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), natives.size());
149
149
  }
150
150
  }
151
151
  }
@@ -154,4 +154,198 @@ namespace Rice::detail
154
154
  return (*native)(argc, argv, self);
155
155
  });
156
156
  }
157
+
158
+ inline Native::Native(std::vector<std::unique_ptr<ParameterAbstract>>&& parameters) : parameters_(std::move(parameters))
159
+ {
160
+ }
161
+
162
+ inline ParameterAbstract* Native::getParameterByName(std::string name)
163
+ {
164
+ for (std::unique_ptr<ParameterAbstract>& parameter : this->parameters_)
165
+ {
166
+ if (parameter->arg->name == name)
167
+ {
168
+ return parameter.get();
169
+ }
170
+ }
171
+
172
+ return nullptr;
173
+ }
174
+
175
+ // ----------- Helpers ----------------
176
+ template<typename T>
177
+ inline void Native::verify_type(bool isBuffer)
178
+ {
179
+ using Base_T = std::remove_pointer_t<remove_cv_recursive_t<T>>;
180
+
181
+ detail::verifyType<T>();
182
+
183
+ if constexpr (std::is_pointer_v<T> && std::is_fundamental_v<std::remove_pointer_t<T>>)
184
+ {
185
+ Type<Pointer<std::remove_pointer_t<T>>>::verify();
186
+ Type<Buffer<std::remove_pointer_t<T>>>::verify();
187
+ }
188
+ if constexpr (std::is_array_v<T>)
189
+ {
190
+ Type<Pointer<std::remove_extent_t<remove_cv_recursive_t<T>>>>::verify();
191
+ Type<Buffer<std::remove_extent_t<remove_cv_recursive_t<T>>>>::verify();
192
+ }
193
+ else if (isBuffer)
194
+ {
195
+ if constexpr (std::is_pointer_v<T> && !std::is_function_v<Base_T> && !std::is_abstract_v<Base_T>)
196
+ {
197
+ Type<Pointer<Base_T>>::verify();
198
+ Type<Buffer<Base_T>>::verify();
199
+ }
200
+ else
201
+ {
202
+ static_assert(true, "Only pointer types can be marked as buffers");
203
+ }
204
+ }
205
+ }
206
+
207
+ template<typename Tuple_T, std::size_t ...Indices>
208
+ inline void Native::verify_args(MethodInfo* methodInfo, std::index_sequence<Indices...> indices)
209
+ {
210
+ (Native::verify_type<std::tuple_element_t<Indices, Tuple_T>>(methodInfo->arg(Indices)->isBuffer()), ...);
211
+ }
212
+
213
+ template<typename Tuple_T, std::size_t ...Indices>
214
+ inline void Native::create_parameters_impl(std::vector<std::unique_ptr<ParameterAbstract>>& parameters, MethodInfo* methodInfo, std::index_sequence<Indices...> indices)
215
+ {
216
+ (parameters.push_back(std::move(std::make_unique<Parameter<std::tuple_element_t<Indices, Tuple_T>>>(methodInfo->arg(Indices)))), ...);
217
+ }
218
+
219
+ template<typename Tuple_T>
220
+ inline std::vector<std::unique_ptr<ParameterAbstract>> Native::create_parameters(MethodInfo* methodInfo)
221
+ {
222
+ std::vector<std::unique_ptr<ParameterAbstract>> result;
223
+ auto indices = std::make_index_sequence<std::tuple_size_v<Tuple_T>>{};
224
+ Native::create_parameters_impl<Tuple_T>(result, methodInfo, indices);
225
+ return result;
226
+ }
227
+
228
+ inline std::vector<std::optional<VALUE>> Native::getRubyValues(size_t argc, const VALUE* argv, bool validate)
229
+ {
230
+ #undef max
231
+ int size = std::max(this->parameters_.size(), argc);
232
+ std::vector<std::optional<VALUE>> result(size);
233
+
234
+ // Keyword handling
235
+ if (rb_keyword_given_p())
236
+ {
237
+ // Keywords are stored in the last element in a hash
238
+ int actualArgc = argc - 1;
239
+
240
+ VALUE value = argv[actualArgc];
241
+ Hash keywords(value);
242
+
243
+ // Copy over leading non-keyword arguments
244
+ for (int i = 0; i < actualArgc; i++)
245
+ {
246
+ result[i] = argv[i];
247
+ }
248
+
249
+ // Copy over keyword arguments
250
+ for (auto pair : keywords)
251
+ {
252
+ Symbol key(pair.first);
253
+ ParameterAbstract* parameter = this->getParameterByName(key.str());
254
+ if (!parameter)
255
+ {
256
+ throw std::invalid_argument("Unknown keyword: " + key.str());
257
+ }
258
+
259
+ const Arg* arg = parameter->arg;
260
+
261
+ result[arg->position] = pair.second.value();
262
+ }
263
+ }
264
+ else
265
+ {
266
+ std::copy(argv, argv + argc, result.begin());
267
+ }
268
+
269
+ // Block handling. If we find a block and the last parameter is missing then
270
+ // set it to the block
271
+ if (rb_block_given_p() && result.size() > 0 && !result.back().has_value())
272
+ {
273
+ VALUE proc = rb_block_proc();
274
+ result.back() = proc;
275
+ }
276
+
277
+ if (validate)
278
+ {
279
+ // Protect against user sending too many arguments
280
+ if (argc > this->parameters_.size())
281
+ {
282
+ std::string message = "wrong number of arguments (given " +
283
+ std::to_string(argc) + ", expected " + std::to_string(this->parameters_.size()) + ")";
284
+ throw std::invalid_argument(message);
285
+ }
286
+
287
+ for (size_t i = 0; i < result.size(); i++)
288
+ {
289
+ std::optional<VALUE> value = result[i];
290
+ ParameterAbstract* parameter = this->parameters_[i].get();
291
+
292
+ if (!parameter->arg->hasDefaultValue() && !value.has_value())
293
+ {
294
+ std::string message;
295
+ message = "Missing argument. Name: " + parameter->arg->name + ". Index: " + std::to_string(parameter->arg->position) + ".";
296
+ throw std::invalid_argument(message);
297
+ }
298
+ }
299
+ }
300
+
301
+ return result;
302
+ }
303
+
304
+ inline Convertible Native::matchParameters(std::vector<std::optional<VALUE>>& values)
305
+ {
306
+ Convertible result = Convertible::Exact;
307
+ for (size_t i = 0; i < this->parameters_.size(); i++)
308
+ {
309
+ ParameterAbstract* parameter = this->parameters_[i].get();
310
+ std::optional<VALUE>& value = values[i];
311
+ result = result & parameter->matches(value);
312
+ }
313
+ return result;
314
+ }
315
+
316
+ inline Resolved Native::matches(size_t argc, const VALUE* argv, VALUE self)
317
+ {
318
+ // Return false if Ruby provided more arguments than the C++ method takes
319
+ if (argc > this->parameters_.size())
320
+ return Resolved{ Convertible::None, 0, this };
321
+
322
+ Resolved result{ Convertible::Exact, 1, this };
323
+
324
+ std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, false);
325
+ result.convertible = this->matchParameters(rubyValues);
326
+
327
+ if (this->parameters_.size() > 0)
328
+ {
329
+ int providedValues = std::count_if(rubyValues.begin(), rubyValues.end(), [](std::optional<VALUE>& value)
330
+ {
331
+ return value.has_value();
332
+ });
333
+
334
+ result.parameterMatch = providedValues / (double)this->parameters_.size();
335
+ }
336
+ return result;
337
+ }
338
+
339
+ inline std::vector<const ParameterAbstract*> Native::parameters()
340
+ {
341
+ std::vector<const ParameterAbstract*> result;
342
+
343
+ std::transform(this->parameters_.begin(), this->parameters_.end(), std::back_inserter(result),
344
+ [](std::unique_ptr<ParameterAbstract>& parameter) -> ParameterAbstract*
345
+ {
346
+ return parameter.get();
347
+ });
348
+
349
+ return result;
350
+ }
157
351
  }
@@ -18,13 +18,13 @@ namespace Rice
18
18
  public:
19
19
  using NativeAttribute_T = NativeAttributeGet<Attribute_T>;
20
20
 
21
- using T = typename attribute_traits<Attribute_T>::attr_type;
21
+ using Attr_T = typename attribute_traits<Attribute_T>::attr_type;
22
22
  using Receiver_T = typename attribute_traits<Attribute_T>::class_type;
23
- using To_Ruby_T = remove_cv_recursive_t<T>;
23
+ using To_Ruby_T = remove_cv_recursive_t<Attr_T>;
24
24
 
25
25
  public:
26
26
  // Register attribute getter with Ruby
27
- static void define(VALUE klass, std::string name, Attribute_T attribute);
27
+ static void define(VALUE klass, std::string name, Attribute_T attribute, Return returnInfo);
28
28
 
29
29
  public:
30
30
  // Disallow creating/copying/moving
@@ -38,13 +38,18 @@ namespace Rice
38
38
  VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
39
39
  std::string toString() override;
40
40
 
41
+ std::string name() override;
42
+ NativeKind kind() override;
43
+ VALUE returnKlass() override;
44
+
41
45
  protected:
42
- NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr);
46
+ NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr, Return returnInfo);
43
47
 
44
48
  private:
45
49
  VALUE klass_;
46
50
  std::string name_;
47
51
  Attribute_T attribute_;
52
+ Return return_;
48
53
  };
49
54
  } // detail
50
55
  } // Rice
@@ -1,14 +1,16 @@
1
1
  #include <array>
2
2
  #include <algorithm>
3
3
 
4
-
5
4
  namespace Rice::detail
6
5
  {
7
6
  template<typename Attribute_T>
8
- void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute)
7
+ void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute, Return returnInfo)
9
8
  {
9
+ // Verify attribute type
10
+ Native::verify_type<Attr_T>(returnInfo.isBuffer());
11
+
10
12
  // Create a NativeAttributeGet that Ruby will call to read/write C++ variables
11
- NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute));
13
+ NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute), returnInfo);
12
14
  std::unique_ptr<Native> native(nativeAttribute);
13
15
 
14
16
  detail::protect(rb_define_method, klass, name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
@@ -30,8 +32,8 @@ namespace Rice::detail
30
32
  }
31
33
 
32
34
  template<typename Attribute_T>
33
- NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute)
34
- : klass_(klass), name_(name), attribute_(attribute)
35
+ NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute, Return returnInfo)
36
+ : klass_(klass), name_(name), attribute_(attribute), return_(returnInfo)
35
37
  {
36
38
  }
37
39
 
@@ -41,11 +43,46 @@ namespace Rice::detail
41
43
  if constexpr (std::is_member_object_pointer_v<Attribute_T>)
42
44
  {
43
45
  Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
44
- return To_Ruby<To_Ruby_T>().convert(nativeSelf->*attribute_);
46
+
47
+ if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>>)
48
+ {
49
+ return To_Ruby<To_Ruby_T>(&this->return_).convert(nativeSelf->*attribute_);
50
+ }
51
+ else if constexpr (std::is_array_v<To_Ruby_T>)
52
+ {
53
+ return To_Ruby<To_Ruby_T>(&this->return_).convert(nativeSelf->*attribute_);
54
+ }
55
+ else if constexpr (std::is_pointer_v<To_Ruby_T>)
56
+ {
57
+ return To_Ruby<To_Ruby_T>(&this->return_).convert(nativeSelf->*attribute_);
58
+ }
59
+ else
60
+ {
61
+ // If the attribute is an object return a reference to avoid a copy (and avoid issues with
62
+ // attributes that are not assignable, copy constructible or move constructible)
63
+ return To_Ruby<To_Ruby_T&>(&this->return_).convert(nativeSelf->*attribute_);
64
+ }
45
65
  }
46
66
  else
47
67
  {
48
- return To_Ruby<To_Ruby_T>().convert(*attribute_);
68
+ if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>>)
69
+ {
70
+ return To_Ruby<To_Ruby_T>(&this->return_).convert(*attribute_);
71
+ }
72
+ else if constexpr (std::is_array_v<To_Ruby_T>)
73
+ {
74
+ return To_Ruby<To_Ruby_T>(&this->return_).convert(*attribute_);
75
+ }
76
+ else if constexpr (std::is_pointer_v<To_Ruby_T>)
77
+ {
78
+ return To_Ruby<To_Ruby_T>(&this->return_).convert(*attribute_);
79
+ }
80
+ else
81
+ {
82
+ // If the attribute is an object return a reference to avoid a copy (and avoid issues with
83
+ // attributes that are not assignable, copy constructible or move constructible)
84
+ return To_Ruby<To_Ruby_T&>(&this->return_).convert(*attribute_);
85
+ }
49
86
  }
50
87
  }
51
88
 
@@ -54,4 +91,32 @@ namespace Rice::detail
54
91
  {
55
92
  return "";
56
93
  }
57
- } // Rice
94
+
95
+ template<typename Attribute_T>
96
+ inline std::string NativeAttributeGet<Attribute_T>::name()
97
+ {
98
+ return this->name_;
99
+ }
100
+
101
+ template<typename Attribute_T>
102
+ inline NativeKind NativeAttributeGet<Attribute_T>::kind()
103
+ {
104
+ return NativeKind::AttributeReader;
105
+ }
106
+
107
+ template<typename Attribute_T>
108
+ inline VALUE NativeAttributeGet<Attribute_T>::returnKlass()
109
+ {
110
+ // Check if an array is being returned
111
+ if (this->return_.isBuffer())
112
+ {
113
+ TypeMapper<Pointer<Attr_T>> typeMapper;
114
+ return typeMapper.rubyKlass();
115
+ }
116
+ else
117
+ {
118
+ TypeMapper<Attr_T> typeMapper;
119
+ return typeMapper.rubyKlass();
120
+ }
121
+ }
122
+ }
@@ -30,6 +30,10 @@ namespace Rice
30
30
  VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
31
31
  std::string toString() override;
32
32
 
33
+ std::string name() override;
34
+ NativeKind kind() override;
35
+ VALUE returnKlass() override;
36
+
33
37
  protected:
34
38
  NativeAttributeSet(VALUE klass, std::string name, Attribute_T attr);
35
39
 
@@ -42,39 +42,30 @@ namespace Rice::detail
42
42
  template<typename Attribute_T>
43
43
  inline VALUE NativeAttributeSet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
44
44
  {
45
- if constexpr (std::is_fundamental_v<intrinsic_type<Attr_T>> && std::is_pointer_v<Attr_T>)
46
- {
47
- static_assert(true, "An fundamental value, such as an integer, cannot be assigned to an attribute that is a pointer.");
48
- }
49
- else if constexpr (std::is_same_v<intrinsic_type<Attr_T>, std::string> && std::is_pointer_v<Attr_T>)
50
- {
51
- static_assert(true, "An string cannot be assigned to an attribute that is a pointer.");
52
- }
53
-
54
45
  if (argc != 1)
55
46
  {
56
47
  throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
57
48
  }
58
49
 
59
50
  VALUE value = argv[0];
60
-
61
- if constexpr (!std::is_null_pointer_v<Receiver_T> &&
62
- !std::is_const_v<Attr_T> &&
63
- (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
51
+
52
+ if constexpr (!std::is_null_pointer_v<Receiver_T>)
64
53
  {
65
54
  Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
66
- nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
67
- }
68
- else if constexpr (std::is_null_pointer_v<Receiver_T> &&
69
- !std::is_const_v<Attr_T> &&
70
- (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
71
- {
72
- *attribute_ = From_Ruby<T_Unqualified>().convert(value);
55
+
56
+ // Deal with pointers to pointes, see Parameter::convertToNative commment
57
+ if constexpr (is_pointer_pointer_v<Attr_T> && !std::is_convertible_v<remove_cv_recursive_t<Attr_T>, Attr_T>)
58
+ {
59
+ nativeSelf->*attribute_ = (Attr_T)From_Ruby<T_Unqualified>().convert(value);
60
+ }
61
+ else
62
+ {
63
+ nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
64
+ }
73
65
  }
74
66
  else
75
67
  {
76
- // Should never get here because define_attr won't compile this code, but just in case!
77
- throw std::invalid_argument("Could not set attribute. Attribute: " + this->name_);
68
+ *attribute_ = From_Ruby<T_Unqualified>().convert(value);
78
69
  }
79
70
 
80
71
  return value;
@@ -85,4 +76,23 @@ namespace Rice::detail
85
76
  {
86
77
  return "";
87
78
  }
88
- } // Rice
79
+
80
+ template<typename Attribute_T>
81
+ inline std::string NativeAttributeSet<Attribute_T>::name()
82
+ {
83
+ return this->name_;
84
+ }
85
+
86
+ template<typename Attribute_T>
87
+ inline NativeKind NativeAttributeSet<Attribute_T>::kind()
88
+ {
89
+ return NativeKind::AttributeWriter;
90
+ }
91
+
92
+ template<typename Attribute_T>
93
+ inline VALUE NativeAttributeSet<Attribute_T>::returnKlass()
94
+ {
95
+ TypeMapper<Attr_T> typeMapper;
96
+ return typeMapper.rubyKlass();
97
+ }
98
+ }