rice 4.7.1 → 4.9.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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -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 +58 -141
  7. data/include/rice/api.hpp +261 -0
  8. data/include/rice/rice.hpp +2459 -1693
  9. data/include/rice/stl.hpp +450 -546
  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 +21 -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 +5 -10
  17. data/lib/rice/rbs.rb +6 -6
  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 +33 -31
  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 +7 -2
  42. data/rice/cpp_api/Class.ipp +9 -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 +10 -4
  47. data/rice/cpp_api/Object.ipp +20 -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/Forwards.hpp +18 -0
  53. data/rice/detail/Forwards.ipp +60 -0
  54. data/rice/detail/InstanceRegistry.hpp +0 -2
  55. data/rice/detail/Native.hpp +31 -21
  56. data/rice/detail/Native.ipp +282 -130
  57. data/rice/detail/NativeAttributeGet.hpp +5 -7
  58. data/rice/detail/NativeAttributeGet.ipp +26 -26
  59. data/rice/detail/NativeAttributeSet.hpp +2 -4
  60. data/rice/detail/NativeAttributeSet.ipp +20 -16
  61. data/rice/detail/NativeCallback.hpp +77 -0
  62. data/rice/detail/NativeCallback.ipp +280 -0
  63. data/rice/detail/NativeFunction.hpp +11 -21
  64. data/rice/detail/NativeFunction.ipp +58 -119
  65. data/rice/detail/NativeInvoker.hpp +4 -4
  66. data/rice/detail/NativeInvoker.ipp +7 -7
  67. data/rice/detail/NativeIterator.hpp +2 -4
  68. data/rice/detail/NativeIterator.ipp +18 -14
  69. data/rice/detail/NativeMethod.hpp +10 -20
  70. data/rice/detail/NativeMethod.ipp +54 -114
  71. data/rice/detail/NativeProc.hpp +5 -7
  72. data/rice/detail/NativeProc.ipp +39 -28
  73. data/rice/detail/NativeRegistry.hpp +1 -1
  74. data/rice/detail/NativeRegistry.ipp +29 -0
  75. data/rice/detail/Parameter.hpp +15 -8
  76. data/rice/detail/Parameter.ipp +102 -43
  77. data/rice/detail/Proc.ipp +14 -28
  78. data/rice/detail/RubyType.ipp +2 -53
  79. data/rice/detail/Type.hpp +23 -7
  80. data/rice/detail/Type.ipp +77 -93
  81. data/rice/detail/TypeRegistry.ipp +5 -4
  82. data/rice/detail/Wrapper.hpp +13 -12
  83. data/rice/detail/Wrapper.ipp +97 -44
  84. data/rice/detail/from_ruby.hpp +8 -6
  85. data/rice/detail/from_ruby.ipp +306 -173
  86. data/rice/detail/ruby.hpp +23 -0
  87. data/rice/libc/file.hpp +4 -4
  88. data/rice/rice.hpp +9 -8
  89. data/rice/rice_api/Native.ipp +5 -1
  90. data/rice/rice_api/NativeRegistry.ipp +14 -1
  91. data/rice/rice_api/Parameter.ipp +1 -1
  92. data/rice/ruby_mark.hpp +2 -1
  93. data/rice/stl/complex.ipp +12 -8
  94. data/rice/stl/map.ipp +27 -22
  95. data/rice/stl/monostate.ipp +16 -12
  96. data/rice/stl/multimap.hpp +0 -2
  97. data/rice/stl/multimap.ipp +27 -22
  98. data/rice/stl/optional.ipp +27 -11
  99. data/rice/stl/pair.ipp +5 -5
  100. data/rice/stl/reference_wrapper.ipp +5 -4
  101. data/rice/stl/set.ipp +16 -16
  102. data/rice/stl/shared_ptr.hpp +9 -9
  103. data/rice/stl/shared_ptr.ipp +52 -185
  104. data/rice/stl/string.ipp +18 -18
  105. data/rice/stl/string_view.ipp +1 -1
  106. data/rice/stl/tuple.ipp +15 -36
  107. data/rice/stl/unique_ptr.hpp +9 -3
  108. data/rice/stl/unique_ptr.ipp +86 -120
  109. data/rice/stl/unordered_map.ipp +20 -15
  110. data/rice/stl/variant.ipp +37 -21
  111. data/rice/stl/vector.ipp +41 -36
  112. data/rice/traits/function_traits.hpp +19 -19
  113. data/rice/traits/method_traits.hpp +4 -4
  114. data/rice/traits/rice_traits.hpp +162 -39
  115. data/rice.gemspec +1 -3
  116. data/test/test_Array.cpp +261 -3
  117. data/test/test_Attribute.cpp +6 -3
  118. data/test/test_Buffer.cpp +6 -42
  119. data/test/test_Callback.cpp +77 -23
  120. data/test/test_Data_Object.cpp +1 -1
  121. data/test/test_Data_Type.cpp +21 -22
  122. data/test/test_Director.cpp +2 -4
  123. data/test/test_Enum.cpp +34 -5
  124. data/test/test_File.cpp +9 -5
  125. data/test/test_From_Ruby.cpp +4 -3
  126. data/test/test_GVL.cpp +3 -3
  127. data/test/test_Hash.cpp +1 -1
  128. data/test/test_Inheritance.cpp +14 -14
  129. data/test/test_Iterator.cpp +54 -22
  130. data/test/test_Keep_Alive.cpp +1 -1
  131. data/test/test_Keep_Alive_No_Wrapper.cpp +7 -3
  132. data/test/test_Module.cpp +5 -5
  133. data/test/test_Overloads.cpp +345 -48
  134. data/test/test_Proc.cpp +54 -0
  135. data/test/test_Reference.cpp +181 -0
  136. data/test/test_Self.cpp +2 -2
  137. data/test/test_Stl_Set.cpp +6 -6
  138. data/test/test_Stl_SharedPtr.cpp +172 -33
  139. data/test/test_Stl_String_View.cpp +4 -2
  140. data/test/test_Stl_Tuple.cpp +1 -1
  141. data/test/test_Stl_UniquePtr.cpp +48 -3
  142. data/test/test_Stl_Variant.cpp +6 -14
  143. data/test/test_Stl_Vector.cpp +61 -30
  144. data/test/test_String.cpp +4 -2
  145. data/test/test_Struct.cpp +1 -1
  146. data/test/test_Symbol.cpp +1 -1
  147. data/test/test_To_Ruby.cpp +1 -0
  148. data/test/test_Type.cpp +36 -35
  149. data/test/test_global_functions.cpp +1 -1
  150. data/test/unittest.cpp +1 -1
  151. data/test/unittest.hpp +5 -5
  152. metadata +12 -10
  153. data/rice/Function.hpp +0 -17
  154. data/rice/Function.ipp +0 -13
  155. data/rice/detail/MethodInfo.hpp +0 -48
  156. data/rice/detail/MethodInfo.ipp +0 -99
  157. data/rice/detail/NativeCallbackFFI.hpp +0 -55
  158. data/rice/detail/NativeCallbackFFI.ipp +0 -152
  159. data/rice/detail/NativeCallbackSimple.hpp +0 -30
  160. data/rice/detail/NativeCallbackSimple.ipp +0 -29
data/rice/detail/Type.ipp CHANGED
@@ -71,37 +71,20 @@ namespace Rice::detail
71
71
  {
72
72
  };
73
73
 
74
- // ---------- TypeMapper ------------
75
- template<typename T>
76
- inline std::string TypeMapper<T>::demangle(char const* mangled_name)
74
+ // ---------- TypeIndexParser ------------
75
+ inline TypeIndexParser::TypeIndexParser(const std::type_index& typeIndex, bool isFundamental) :
76
+ typeIndex_(typeIndex), isFundamental_(isFundamental)
77
77
  {
78
- #ifdef __GNUC__
79
- struct Helper
80
- {
81
- Helper(
82
- char const* mangled_name)
83
- : name_(0)
84
- {
85
- int status = 0;
86
- name_ = abi::__cxa_demangle(mangled_name, 0, 0, &status);
87
- }
88
-
89
- ~Helper()
90
- {
91
- std::free(name_);
92
- }
93
-
94
- char* name_;
95
-
96
- private:
97
- Helper(Helper const&);
98
- void operator=(Helper const&);
99
- };
78
+ }
100
79
 
101
- Helper helper(mangled_name);
102
- if (helper.name_)
80
+ inline std::string TypeIndexParser::demangle(char const* mangled_name)
81
+ {
82
+ #ifdef __GNUC__
83
+ int status = 0;
84
+ char* name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
85
+ if (name)
103
86
  {
104
- return helper.name_;
87
+ return name;
105
88
  }
106
89
  else
107
90
  {
@@ -112,17 +95,9 @@ namespace Rice::detail
112
95
  #endif
113
96
  }
114
97
 
115
- template<typename T>
116
- inline std::string TypeMapper<T>::name()
98
+ inline std::string TypeIndexParser::name()
117
99
  {
118
- const std::type_index& typeIndex = typeid(T);
119
- return demangle(typeIndex.name());
120
- }
121
-
122
- template<typename T>
123
- inline std::string TypeMapper<T>::name(const std::type_index& typeIndex)
124
- {
125
- return demangle(typeIndex.name());
100
+ return this->demangle(this->typeIndex_.name());
126
101
  }
127
102
 
128
103
  // Find text inside of < > taking into account nested groups.
@@ -130,8 +105,7 @@ namespace Rice::detail
130
105
  // Example:
131
106
  //
132
107
  // std::vector<std::vector<int>, std::allocator<std::vector, std::allocator<int>>>
133
- template<typename T>
134
- inline std::string TypeMapper<T>::findGroup(std::string& string, size_t offset)
108
+ inline std::string TypeIndexParser::findGroup(std::string& string, size_t offset)
135
109
  {
136
110
  int depth = 0;
137
111
 
@@ -164,8 +138,7 @@ namespace Rice::detail
164
138
  throw std::runtime_error("Unbalanced Group");
165
139
  }
166
140
 
167
- template<typename T>
168
- inline void TypeMapper<T>::replaceAll(std::string& string, std::regex regex, std::string replacement)
141
+ inline void TypeIndexParser::replaceAll(std::string& string, std::regex regex, std::string replacement)
169
142
  {
170
143
  std::smatch match;
171
144
  while (std::regex_search(string, match, regex))
@@ -174,8 +147,7 @@ namespace Rice::detail
174
147
  }
175
148
  }
176
149
 
177
- template<typename T>
178
- inline void TypeMapper<T>::removeGroup(std::string& string, std::regex regex)
150
+ inline void TypeIndexParser::removeGroup(std::string& string, std::regex regex)
179
151
  {
180
152
  std::smatch match;
181
153
  while (std::regex_search(string, match, regex))
@@ -186,8 +158,7 @@ namespace Rice::detail
186
158
  }
187
159
  }
188
160
 
189
- template<typename T>
190
- inline void TypeMapper<T>::replaceGroup(std::string& string, std::regex regex, std::string replacement)
161
+ inline void TypeIndexParser::replaceGroup(std::string& string, std::regex regex, std::string replacement)
191
162
  {
192
163
  std::smatch match;
193
164
  while (std::regex_search(string, match, regex))
@@ -198,8 +169,7 @@ namespace Rice::detail
198
169
  }
199
170
  }
200
171
 
201
- template<typename T>
202
- inline std::string TypeMapper<T>::simplifiedName()
172
+ inline std::string TypeIndexParser::simplifiedName()
203
173
  {
204
174
  std::string base = this->name();
205
175
 
@@ -239,6 +209,10 @@ namespace Rice::detail
239
209
  std::regex equalRegex(R"(,\s*std::equal_to)");
240
210
  removeGroup(base, equalRegex);
241
211
 
212
+ // Remove default_delete (std::unique_ptr)
213
+ std::regex defaultDeleteRegex(R"(,\s*std::default_delete)");
214
+ removeGroup(base, defaultDeleteRegex);
215
+
242
216
  // Remove spaces before pointers
243
217
  std::regex ptrRegex = std::regex(R"(\s+\*)");
244
218
  base = std::regex_replace(base, ptrRegex, "*");
@@ -271,42 +245,9 @@ namespace Rice::detail
271
245
  return base;
272
246
  }
273
247
 
274
- template<typename T>
275
- inline void TypeMapper<T>::capitalizeHelper(std::string& content, std::regex& regex)
248
+ inline std::string TypeIndexParser::rubyName(std::string rubyTypeName)
276
249
  {
277
- std::smatch match;
278
- while (std::regex_search(content, match, regex))
279
- {
280
- std::string replacement = match[1];
281
- std::transform(replacement.begin(), replacement.end(), replacement.begin(), ::toupper);
282
- content.replace(match.position(), match.length(), replacement);
283
- }
284
- }
285
-
286
- template<typename T>
287
- inline std::string TypeMapper<T>::rubyTypeName()
288
- {
289
- using Intrinsic_T = detail::intrinsic_type<T>;
290
-
291
- if constexpr (std::is_fundamental_v<T>)
292
- {
293
- return RubyType<Intrinsic_T>::name;
294
- }
295
- else if constexpr (std::is_same_v<std::remove_cv_t<T>, char*>)
296
- {
297
- return "String";
298
- }
299
- else
300
- {
301
- detail::TypeMapper<Intrinsic_T> typeIntrinsicMapper;
302
- return typeIntrinsicMapper.simplifiedName();
303
- }
304
- }
305
-
306
- template<typename T>
307
- inline std::string TypeMapper<T>::rubyName()
308
- {
309
- std::string base = this->rubyTypeName();
250
+ std::string base = rubyTypeName;
310
251
 
311
252
  // Remove std:: these could be embedded in template types
312
253
  auto stdRegex = std::regex("std::");
@@ -318,50 +259,93 @@ namespace Rice::detail
318
259
  base = std::regex_replace(base, leadingNamespacesRegex, "");
319
260
 
320
261
  // Capitalize first letter
321
- base[0] = std::toupper(base[0]);
262
+ base[0] = (char)std::toupper(base[0]);
322
263
 
323
264
  // Replace :: with unicode U+u02F8 (Modified Letter raised colon)
324
265
  auto colonRegex = std::regex(R"(:)");
325
- replaceAll(base, colonRegex, "\uA789");
266
+ this->replaceAll(base, colonRegex, "\uA789");
326
267
 
327
268
  // Replace _ and capitalize the next letter
328
269
  std::regex underscoreRegex(R"(_(\w))");
329
- capitalizeHelper(base, underscoreRegex);
270
+ this->capitalizeHelper(base, underscoreRegex);
330
271
 
331
- if constexpr (std::is_fundamental_v<intrinsic_type<T>>)
272
+ if (this->isFundamental_)
332
273
  {
333
274
  // Replace space and capitalize the next letter
334
275
  std::regex spaceRegex(R"(\s+(\w))");
335
- capitalizeHelper(base, spaceRegex);
276
+ this->capitalizeHelper(base, spaceRegex);
336
277
  }
337
278
  else
338
279
  {
339
280
  // Replace spaces with unicode U+u00A0 (Non breaking Space)
340
281
  std::regex spaceRegex = std::regex(R"(\s+)");
341
- replaceAll(base, spaceRegex, "\u00A0");
282
+ this->replaceAll(base, spaceRegex, "\u00A0");
342
283
  }
343
284
 
344
285
  // Replace < with unicode U+227A (Precedes)
345
286
  auto lessThanRegex = std::regex("<");
346
287
  //replaceAll(base, lessThanRegex, "≺");
347
- replaceAll(base, lessThanRegex, "\u227A");
288
+ this->replaceAll(base, lessThanRegex, "\u227A");
348
289
 
349
290
  // Replace > with unicode U+227B (Succeeds)
350
291
  auto greaterThanRegex = std::regex(">");
351
292
  //replaceAll(base, greaterThanRegex, "≻");
352
- replaceAll(base, greaterThanRegex, "\u227B");
293
+ this->replaceAll(base, greaterThanRegex, "\u227B");
353
294
 
354
295
  // Replace , with Unicode Character (U+066C) - Arabic Thousands Separator
355
296
  auto commaRegex = std::regex(R"(,\s*)");
356
- replaceAll(base, commaRegex, "\u201A");
297
+ this->replaceAll(base, commaRegex, "\u201A");
357
298
 
358
299
  // Replace * with Unicode Character (U+2217) - Asterisk Operator
359
300
  auto asteriskRegex = std::regex(R"(\*)");
360
- replaceAll(base, asteriskRegex, "\u2217");
301
+ this->replaceAll(base, asteriskRegex, "\u2217");
361
302
 
362
303
  return base;
363
304
  }
364
305
 
306
+ inline void TypeIndexParser::capitalizeHelper(std::string& content, std::regex& regex)
307
+ {
308
+ std::smatch match;
309
+ while (std::regex_search(content, match, regex))
310
+ {
311
+ std::string replacement = match[1];
312
+ std::transform(replacement.begin(), replacement.end(), replacement.begin(),
313
+ [](unsigned char c) -> char
314
+ {
315
+ return static_cast<char>(std::toupper(c));
316
+ });
317
+ content.replace(match.position(), match.length(), replacement);
318
+ }
319
+ }
320
+
321
+ // ---------- TypeMapper ------------
322
+ template<typename T>
323
+ inline std::string TypeMapper<T>::rubyTypeName()
324
+ {
325
+ using Intrinsic_T = detail::intrinsic_type<T>;
326
+
327
+ if constexpr (std::is_fundamental_v<T>)
328
+ {
329
+ return RubyType<Intrinsic_T>::name;
330
+ }
331
+ else if constexpr (std::is_same_v<std::remove_cv_t<T>, char*>)
332
+ {
333
+ return "String";
334
+ }
335
+ else
336
+ {
337
+ detail::TypeIndexParser typeIndexParser(typeid(Intrinsic_T), std::is_fundamental_v<detail::intrinsic_type<Intrinsic_T>>);
338
+ return typeIndexParser.simplifiedName();
339
+ }
340
+ }
341
+
342
+ template<typename T>
343
+ inline std::string TypeMapper<T>::rubyName()
344
+ {
345
+ std::string base = this->rubyTypeName();
346
+ return this->typeIndexParser_.rubyName(base);
347
+ }
348
+
365
349
  template<typename T>
366
350
  inline VALUE TypeMapper<T>::rubyKlass()
367
351
  {
@@ -97,8 +97,9 @@ namespace Rice::detail
97
97
  return result.value();
98
98
  }
99
99
 
100
- detail::TypeMapper<T> typeMapper;
101
- raiseUnverifiedType(typeMapper.name());
100
+ detail::TypeIndexParser typeIndexParser(typeid(T), std::is_fundamental_v<detail::intrinsic_type<T>>);
101
+ raiseUnverifiedType(typeIndexParser.name());
102
+
102
103
  // Make the compiler happy
103
104
  return std::pair<VALUE, rb_data_type_t*>(Qnil, nullptr);
104
105
  }
@@ -131,8 +132,8 @@ namespace Rice::detail
131
132
 
132
133
  for (const std::type_index& typeIndex : this->unverified_)
133
134
  {
134
- detail::TypeMapper<int> typeMapper;
135
- stream << " " << typeMapper.name(typeIndex) << "\n";
135
+ detail::TypeIndexParser typeIndexParser(typeIndex);
136
+ stream << " " << typeIndexParser.name() << "\n";
136
137
  }
137
138
 
138
139
  throw std::invalid_argument(stream.str());
@@ -6,9 +6,9 @@ namespace Rice::detail
6
6
  class WrapperBase
7
7
  {
8
8
  public:
9
- WrapperBase() = default;
9
+ WrapperBase(rb_data_type_t* rb_data_type);
10
10
  virtual ~WrapperBase() = default;
11
- virtual void* get() = 0;
11
+ virtual void* get(rb_data_type_t* requestedType) = 0;
12
12
  bool isConst();
13
13
 
14
14
  void ruby_mark();
@@ -16,6 +16,7 @@ namespace Rice::detail
16
16
  void setOwner(bool value);
17
17
 
18
18
  protected:
19
+ rb_data_type_t* rb_data_type_;
19
20
  bool isOwner_ = false;
20
21
  bool isConst_ = false;
21
22
 
@@ -30,10 +31,10 @@ namespace Rice::detail
30
31
  class Wrapper : public WrapperBase
31
32
  {
32
33
  public:
33
- Wrapper(T& data);
34
- Wrapper(T&& data);
34
+ Wrapper(rb_data_type_t* rb_data_type, T& data);
35
+ Wrapper(rb_data_type_t* rb_data_type, T&& data);
35
36
  ~Wrapper();
36
- void* get() override;
37
+ void* get(rb_data_type_t* requestedType) override;
37
38
 
38
39
  private:
39
40
  T data_;
@@ -43,9 +44,9 @@ namespace Rice::detail
43
44
  class Wrapper<T&> : public WrapperBase
44
45
  {
45
46
  public:
46
- Wrapper(T& data);
47
+ Wrapper(rb_data_type_t* rb_data_type, T& data);
47
48
  ~Wrapper();
48
- void* get() override;
49
+ void* get(rb_data_type_t* requestedType) override;
49
50
 
50
51
  private:
51
52
  T& data_;
@@ -55,9 +56,9 @@ namespace Rice::detail
55
56
  class Wrapper<T*> : public WrapperBase
56
57
  {
57
58
  public:
58
- Wrapper(T* data, bool isOwner);
59
+ Wrapper(rb_data_type_t* rb_data_type, T* data, bool isOwner);
59
60
  ~Wrapper();
60
- void* get() override;
61
+ void* get(rb_data_type_t* requestedType) override;
61
62
 
62
63
  private:
63
64
  T* data_ = nullptr;
@@ -67,9 +68,9 @@ namespace Rice::detail
67
68
  class Wrapper<T**> : public WrapperBase
68
69
  {
69
70
  public:
70
- Wrapper(T** data, bool isOwner);
71
+ Wrapper(rb_data_type_t* rb_data_type, T** data, bool isOwner);
71
72
  ~Wrapper();
72
- void* get() override;
73
+ void* get(rb_data_type_t* requestedType) override;
73
74
 
74
75
  private:
75
76
  T** data_ = nullptr;
@@ -77,7 +78,7 @@ namespace Rice::detail
77
78
 
78
79
  // ---- Helper Functions ---------
79
80
  template <typename T>
80
- void wrapConstructed(VALUE value, rb_data_type_t* rb_data_type, T* data, bool isOwner);
81
+ void wrapConstructed(VALUE value, rb_data_type_t* rb_data_type, T* data);
81
82
 
82
83
  template <typename T>
83
84
  VALUE wrap(VALUE klass, rb_data_type_t* rb_data_type, T& data, bool isOwner);
@@ -2,6 +2,10 @@
2
2
 
3
3
  namespace Rice::detail
4
4
  {
5
+ inline WrapperBase::WrapperBase(rb_data_type_t* rb_data_type) : rb_data_type_(rb_data_type)
6
+ {
7
+ }
8
+
5
9
  inline bool WrapperBase::isConst()
6
10
  {
7
11
  return this->isConst_;
@@ -27,30 +31,40 @@ namespace Rice::detail
27
31
 
28
32
  // ---- Wrapper -----
29
33
  template <typename T>
30
- inline Wrapper<T>::Wrapper(T& data): data_(data)
34
+ inline Wrapper<T>::Wrapper(rb_data_type_t* rb_data_type, T& data) : WrapperBase(rb_data_type), data_(data)
31
35
  {
36
+ this->isConst_ = std::is_const_v<std::remove_reference_t<T>>;
32
37
  }
33
38
 
34
39
  template <typename T>
35
- inline Wrapper<T>::Wrapper(T&& data) : data_(std::move(data))
40
+ inline Wrapper<T>::Wrapper(rb_data_type_t* rb_data_type, T&& data) : WrapperBase(rb_data_type), data_(std::move(data))
36
41
  {
37
42
  }
38
43
 
39
44
  template <typename T>
40
45
  inline Wrapper<T>::~Wrapper()
41
46
  {
42
- Registries::instance.instances.remove(this->get());
47
+ Registries::instance.instances.remove(this->get(this->rb_data_type_));
43
48
  }
44
49
 
45
50
  template <typename T>
46
- inline void* Wrapper<T>::Wrapper::get()
51
+ inline void* Wrapper<T>::get(rb_data_type_t* requestedType)
47
52
  {
48
- return (void*)&this->data_;
53
+ if (rb_typeddata_inherited_p(this->rb_data_type_, requestedType))
54
+ {
55
+ return (void*)&this->data_;
56
+ }
57
+ else
58
+ {
59
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
60
+ this->rb_data_type_->wrap_struct_name,
61
+ requestedType->wrap_struct_name);
62
+ }
49
63
  }
50
64
 
51
65
  // ---- Wrapper& -----
52
66
  template <typename T>
53
- inline Wrapper<T&>::Wrapper(T& data): data_(data)
67
+ inline Wrapper<T&>::Wrapper(rb_data_type_t* rb_data_type, T& data) : WrapperBase(rb_data_type), data_(data)
54
68
  {
55
69
  this->isConst_ = std::is_const_v<std::remove_reference_t<T>>;
56
70
  }
@@ -58,18 +72,27 @@ namespace Rice::detail
58
72
  template <typename T>
59
73
  inline Wrapper<T&>::~Wrapper()
60
74
  {
61
- Registries::instance.instances.remove(this->get());
75
+ Registries::instance.instances.remove(this->get(this->rb_data_type_));
62
76
  }
63
77
 
64
78
  template <typename T>
65
- inline void* Wrapper<T&>::get()
79
+ inline void* Wrapper<T&>::get(rb_data_type_t* requestedType)
66
80
  {
67
- return (void*)&this->data_;
81
+ if (rb_typeddata_inherited_p(this->rb_data_type_, requestedType))
82
+ {
83
+ return (void*)&this->data_;
84
+ }
85
+ else
86
+ {
87
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
88
+ this->rb_data_type_->wrap_struct_name,
89
+ requestedType->wrap_struct_name);
90
+ }
68
91
  }
69
92
 
70
93
  // ---- Wrapper* -----
71
94
  template <typename T>
72
- inline Wrapper<T*>::Wrapper(T* data, bool isOwner) : data_(data)
95
+ inline Wrapper<T*>::Wrapper(rb_data_type_t* rb_data_type, T* data, bool isOwner) : WrapperBase(rb_data_type), data_(data)
73
96
  {
74
97
  this->isOwner_ = isOwner;
75
98
  this->isConst_ = std::is_const_v<std::remove_pointer_t<T>>;
@@ -78,7 +101,8 @@ namespace Rice::detail
78
101
  template <typename T>
79
102
  inline Wrapper<T*>::~Wrapper()
80
103
  {
81
- Registries::instance.instances.remove(this->get());
104
+ Registries::instance.instances.remove(this->get(this->rb_data_type_));
105
+
82
106
  if constexpr (std::is_destructible_v<T>)
83
107
  {
84
108
  if (this->isOwner_)
@@ -89,14 +113,23 @@ namespace Rice::detail
89
113
  }
90
114
 
91
115
  template <typename T>
92
- inline void* Wrapper<T*>::get()
116
+ inline void* Wrapper<T*>::get(rb_data_type_t* requestedType)
93
117
  {
94
- return (void*)this->data_;
118
+ if (rb_typeddata_inherited_p(this->rb_data_type_, requestedType))
119
+ {
120
+ return (void*)this->data_;
121
+ }
122
+ else
123
+ {
124
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
125
+ this->rb_data_type_->wrap_struct_name,
126
+ requestedType->wrap_struct_name);
127
+ }
95
128
  }
96
129
 
97
130
  // ---- Wrapper** -----
98
131
  template <typename T>
99
- inline Wrapper<T**>::Wrapper(T** data, bool isOwner) : data_(data)
132
+ inline Wrapper<T**>::Wrapper(rb_data_type_t* rb_data_type, T** data, bool isOwner) : WrapperBase(rb_data_type), data_(data)
100
133
  {
101
134
  this->isOwner_ = isOwner;
102
135
  this->isConst_ = std::is_const_v<std::remove_pointer_t<std::remove_pointer_t<T>>>;
@@ -105,7 +138,8 @@ namespace Rice::detail
105
138
  template <typename T>
106
139
  inline Wrapper<T**>::~Wrapper()
107
140
  {
108
- Registries::instance.instances.remove(this->get());
141
+ Registries::instance.instances.remove(this->get(this->rb_data_type_));
142
+
109
143
  if constexpr (std::is_destructible_v<T>)
110
144
  {
111
145
  if (this->isOwner_)
@@ -116,9 +150,18 @@ namespace Rice::detail
116
150
  }
117
151
 
118
152
  template <typename T>
119
- inline void* Wrapper<T**>::get()
153
+ inline void* Wrapper<T**>::get(rb_data_type_t* requestedType)
120
154
  {
121
- return (void*)this->data_;
155
+ if (rb_typeddata_inherited_p(this->rb_data_type_, requestedType))
156
+ {
157
+ return (void*)this->data_;
158
+ }
159
+ else
160
+ {
161
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
162
+ this->rb_data_type_->wrap_struct_name,
163
+ requestedType->wrap_struct_name);
164
+ }
122
165
  }
123
166
 
124
167
  // ---- Helper Functions -------
@@ -135,21 +178,21 @@ namespace Rice::detail
135
178
  // If Ruby is not the owner then wrap the reference
136
179
  if (!isOwner)
137
180
  {
138
- wrapper = new Wrapper<T&>(data);
181
+ wrapper = new Wrapper<T&>(rb_data_type, data);
139
182
  result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
140
183
  }
141
184
 
142
- // std::is_copy_constructible_v<std::vector<std::unique_ptr<T>>>> return true. Sigh.
185
+ // std::is_copy_constructible_v<std::vector<std::unique_ptr<T>>>> returns true. Sigh.
143
186
  else if constexpr (detail::is_std_vector_v<T>)
144
187
  {
145
188
  if constexpr (std::is_copy_constructible_v<typename T::value_type>)
146
189
  {
147
- wrapper = new Wrapper<T>(data);
190
+ wrapper = new Wrapper<T>(rb_data_type, data);
148
191
  result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
149
192
  }
150
193
  else
151
194
  {
152
- wrapper = new Wrapper<T>(std::move(data));
195
+ wrapper = new Wrapper<T>(rb_data_type, std::move(data));
153
196
  result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
154
197
  }
155
198
  }
@@ -157,26 +200,26 @@ namespace Rice::detail
157
200
  // Ruby is the owner so copy data
158
201
  else if constexpr (std::is_copy_constructible_v<T>)
159
202
  {
160
- wrapper = new Wrapper<T>(data);
203
+ wrapper = new Wrapper<T>(rb_data_type, data);
161
204
  result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
162
205
  }
163
206
 
164
207
  // Ruby is the owner so move data
165
208
  else if constexpr (std::is_move_constructible_v<T>)
166
209
  {
167
- wrapper = new Wrapper<T>(std::move(data));
210
+ wrapper = new Wrapper<T>(rb_data_type, std::move(data));
168
211
  result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
169
212
  }
170
213
 
171
214
  else
172
215
  {
173
- detail::TypeMapper<T> typeMapper;
216
+ detail::TypeIndexParser typeIndexParser(typeid(T), std::is_fundamental_v<detail::intrinsic_type<T>>);
174
217
  std::string message = "Rice was directed to take ownership of a C++ object but it does not have an accessible copy or move constructor. Type: " +
175
- typeMapper.name();
218
+ typeIndexParser.name();
176
219
  throw std::runtime_error(message);
177
220
  }
178
221
 
179
- Registries::instance.instances.add(wrapper->get(), result);
222
+ Registries::instance.instances.add(wrapper->get(rb_data_type), result);
180
223
 
181
224
  return result;
182
225
  };
@@ -189,37 +232,40 @@ namespace Rice::detail
189
232
  if (result != Qnil)
190
233
  return result;
191
234
 
192
- WrapperBase* wrapper = new Wrapper<T*>(data, isOwner);
235
+ WrapperBase* wrapper = new Wrapper<T*>(rb_data_type, data, isOwner);
193
236
  result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
194
237
 
195
- Registries::instance.instances.add(wrapper->get(), result);
238
+ Registries::instance.instances.add(wrapper->get(rb_data_type), result);
196
239
  return result;
197
240
  };
198
241
 
199
242
  template <typename T>
200
243
  inline T* unwrap(VALUE value, rb_data_type_t* rb_data_type, bool takeOwnership)
201
244
  {
202
- if (rb_type(value) != RUBY_T_DATA)
245
+ if (!RTYPEDDATA_P(value))
203
246
  {
204
- std::string message = "The provided Ruby object does not wrap a C++ object";
247
+ std::string message = "The Ruby object does not wrap a C++ object. It is actually a " +
248
+ std::string(detail::protect(rb_obj_classname, value)) + ".";
205
249
  throw std::runtime_error(message);
206
250
  }
207
251
 
208
- WrapperBase* wrapper = getWrapper(value, rb_data_type);
252
+ WrapperBase* wrapper = static_cast<WrapperBase*>(RTYPEDDATA_DATA(value));
209
253
 
210
254
  if (wrapper == nullptr)
211
255
  {
212
- std::string message = "Wrapped C++ object is nil. Did you override " +
213
- std::string(detail::protect(rb_obj_classname, value)) +
256
+ std::string message = "Wrapped C++ object is nil. Did you override " +
257
+ std::string(detail::protect(rb_obj_classname, value)) +
214
258
  "#initialize and forget to call super?";
215
259
 
216
260
  throw std::runtime_error(message);
217
261
  }
218
262
 
219
263
  if (takeOwnership)
264
+ {
220
265
  wrapper->setOwner(false);
266
+ }
221
267
 
222
- return static_cast<T*>(wrapper->get());
268
+ return static_cast<T*>(wrapper->get(rb_data_type));
223
269
  }
224
270
 
225
271
  template <typename Wrapper_T>
@@ -233,12 +279,19 @@ namespace Rice::detail
233
279
  inline WrapperBase* getWrapper(VALUE value)
234
280
  {
235
281
  // Turn off spurious warning on g++ 12
236
- #if defined(__GNUC__) || defined(__clang__)
237
- #pragma GCC diagnostic push
238
- #pragma GCC diagnostic ignored "-Warray-bounds"
239
- #endif
282
+ #if defined(__GNUC__) || defined(__clang__)
283
+ #pragma GCC diagnostic push
284
+ #pragma GCC diagnostic ignored "-Warray-bounds"
285
+ #endif
286
+
287
+ if (!RTYPEDDATA_P(value))
288
+ {
289
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
290
+ detail::protect(rb_obj_classname, value),
291
+ "wrapped C++ object");
292
+ }
240
293
 
241
- return RTYPEDDATA_P(value) ? static_cast<WrapperBase*>(RTYPEDDATA_DATA(value)) : nullptr;
294
+ return static_cast<WrapperBase*>(RTYPEDDATA_DATA(value));
242
295
 
243
296
  #if defined(__GNUC__) || defined(__clang__)
244
297
  #pragma GCC diagnostic pop
@@ -246,21 +299,21 @@ namespace Rice::detail
246
299
  }
247
300
 
248
301
  template <typename T>
249
- inline void wrapConstructed(VALUE value, rb_data_type_t* rb_data_type, T* data, bool isOwner)
302
+ inline void wrapConstructed(VALUE value, rb_data_type_t* rb_data_type, T* data)
250
303
  {
251
304
  using Wrapper_T = Wrapper<T*>;
252
-
305
+
253
306
  Wrapper_T* wrapper = nullptr;
254
307
  TypedData_Get_Struct(value, Wrapper_T, rb_data_type, wrapper);
255
308
  if (wrapper)
256
309
  {
257
- Registries::instance.instances.remove(wrapper->get());
310
+ Registries::instance.instances.remove(wrapper->get(rb_data_type));
258
311
  delete wrapper;
259
312
  }
260
313
 
261
- wrapper = new Wrapper_T(data, true);
314
+ wrapper = new Wrapper_T(rb_data_type, data, true);
262
315
  RTYPEDDATA_DATA(value) = wrapper;
263
316
 
264
317
  Registries::instance.instances.add(data, value);
265
318
  }
266
- } // namespace
319
+ }