rice 4.3.3 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -26
  3. data/README.md +7 -2
  4. data/Rakefile +7 -1
  5. data/include/rice/rice.hpp +7291 -4430
  6. data/include/rice/stl.hpp +769 -222
  7. data/lib/mkmf-rice.rb +37 -95
  8. data/rice/Address_Registration_Guard.hpp +72 -3
  9. data/rice/Arg.hpp +19 -5
  10. data/rice/Arg.ipp +24 -0
  11. data/rice/Callback.hpp +21 -0
  12. data/rice/Callback.ipp +13 -0
  13. data/rice/Constructor.hpp +4 -27
  14. data/rice/Constructor.ipp +79 -0
  15. data/rice/Data_Object.hpp +74 -3
  16. data/rice/Data_Object.ipp +324 -32
  17. data/rice/Data_Type.hpp +215 -3
  18. data/rice/Data_Type.ipp +125 -64
  19. data/rice/Director.hpp +0 -2
  20. data/rice/Enum.hpp +4 -6
  21. data/rice/Enum.ipp +101 -57
  22. data/rice/Exception.hpp +62 -2
  23. data/rice/Exception.ipp +7 -12
  24. data/rice/JumpException.hpp +44 -0
  25. data/rice/JumpException.ipp +48 -0
  26. data/rice/MemoryView.hpp +11 -0
  27. data/rice/MemoryView.ipp +43 -0
  28. data/rice/Return.hpp +6 -26
  29. data/rice/Return.ipp +10 -16
  30. data/rice/detail/DefaultHandler.hpp +12 -0
  31. data/rice/detail/DefaultHandler.ipp +8 -0
  32. data/rice/detail/HandlerRegistry.hpp +5 -35
  33. data/rice/detail/HandlerRegistry.ipp +7 -11
  34. data/rice/detail/InstanceRegistry.hpp +1 -4
  35. data/rice/detail/MethodInfo.hpp +15 -5
  36. data/rice/detail/MethodInfo.ipp +78 -6
  37. data/rice/detail/Native.hpp +32 -0
  38. data/rice/detail/Native.ipp +129 -0
  39. data/rice/detail/NativeAttributeGet.hpp +51 -0
  40. data/rice/detail/NativeAttributeGet.ipp +51 -0
  41. data/rice/detail/NativeAttributeSet.hpp +43 -0
  42. data/rice/detail/NativeAttributeSet.ipp +82 -0
  43. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  44. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  45. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  46. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  47. data/rice/detail/NativeFunction.hpp +20 -21
  48. data/rice/detail/NativeFunction.ipp +199 -64
  49. data/rice/detail/NativeIterator.hpp +8 -11
  50. data/rice/detail/NativeIterator.ipp +27 -31
  51. data/rice/detail/NativeRegistry.hpp +24 -15
  52. data/rice/detail/NativeRegistry.ipp +23 -48
  53. data/rice/detail/Proc.hpp +4 -0
  54. data/rice/detail/Proc.ipp +85 -0
  55. data/rice/detail/Registries.hpp +0 -7
  56. data/rice/detail/Registries.ipp +0 -18
  57. data/rice/detail/RubyFunction.hpp +0 -3
  58. data/rice/detail/RubyFunction.ipp +4 -8
  59. data/rice/detail/RubyType.hpp +19 -0
  60. data/rice/detail/RubyType.ipp +187 -0
  61. data/rice/detail/TupleIterator.hpp +14 -0
  62. data/rice/detail/Type.hpp +5 -6
  63. data/rice/detail/Type.ipp +150 -33
  64. data/rice/detail/TypeRegistry.hpp +15 -7
  65. data/rice/detail/TypeRegistry.ipp +105 -12
  66. data/rice/detail/Wrapper.hpp +6 -5
  67. data/rice/detail/Wrapper.ipp +45 -23
  68. data/rice/detail/cpp_protect.hpp +5 -6
  69. data/rice/detail/default_allocation_func.ipp +0 -2
  70. data/rice/detail/from_ruby.hpp +37 -3
  71. data/rice/detail/from_ruby.ipp +911 -454
  72. data/rice/detail/ruby.hpp +18 -0
  73. data/rice/detail/to_ruby.hpp +41 -3
  74. data/rice/detail/to_ruby.ipp +437 -113
  75. data/rice/global_function.hpp +0 -4
  76. data/rice/global_function.ipp +1 -2
  77. data/rice/rice.hpp +105 -22
  78. data/rice/ruby_mark.hpp +4 -3
  79. data/rice/stl.hpp +4 -0
  80. data/test/embed_ruby.cpp +4 -1
  81. data/test/extconf.rb +2 -0
  82. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  83. data/test/test_Address_Registration_Guard.cpp +5 -0
  84. data/test/test_Array.cpp +12 -1
  85. data/test/test_Attribute.cpp +103 -21
  86. data/test/test_Builtin_Object.cpp +5 -0
  87. data/test/test_Callback.cpp +231 -0
  88. data/test/test_Class.cpp +5 -31
  89. data/test/test_Constructor.cpp +69 -6
  90. data/test/test_Data_Object.cpp +9 -4
  91. data/test/test_Data_Type.cpp +428 -64
  92. data/test/test_Director.cpp +10 -5
  93. data/test/test_Enum.cpp +152 -40
  94. data/test/test_Exception.cpp +235 -0
  95. data/test/test_File.cpp +70 -0
  96. data/test/test_From_Ruby.cpp +542 -0
  97. data/test/test_Hash.cpp +5 -0
  98. data/test/test_Identifier.cpp +5 -0
  99. data/test/test_Inheritance.cpp +6 -1
  100. data/test/test_Iterator.cpp +5 -0
  101. data/test/test_JumpException.cpp +22 -0
  102. data/test/test_Keep_Alive.cpp +6 -1
  103. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
  104. data/test/test_Memory_Management.cpp +5 -0
  105. data/test/test_Module.cpp +118 -64
  106. data/test/test_Native_Registry.cpp +2 -33
  107. data/test/test_Object.cpp +5 -0
  108. data/test/test_Overloads.cpp +631 -0
  109. data/test/test_Ownership.cpp +67 -4
  110. data/test/test_Proc.cpp +45 -0
  111. data/test/test_Self.cpp +5 -0
  112. data/test/test_Stl_Exception.cpp +109 -0
  113. data/test/test_Stl_Map.cpp +22 -8
  114. data/test/test_Stl_Optional.cpp +5 -0
  115. data/test/test_Stl_Pair.cpp +7 -2
  116. data/test/test_Stl_Reference_Wrapper.cpp +5 -0
  117. data/test/test_Stl_SmartPointer.cpp +210 -5
  118. data/test/test_Stl_String.cpp +5 -0
  119. data/test/test_Stl_String_View.cpp +5 -0
  120. data/test/test_Stl_Type.cpp +147 -0
  121. data/test/test_Stl_Unordered_Map.cpp +18 -7
  122. data/test/test_Stl_Variant.cpp +5 -0
  123. data/test/test_Stl_Vector.cpp +130 -8
  124. data/test/test_String.cpp +5 -0
  125. data/test/test_Struct.cpp +5 -0
  126. data/test/test_Symbol.cpp +5 -0
  127. data/test/test_Template.cpp +192 -0
  128. data/test/test_To_Ruby.cpp +152 -0
  129. data/test/test_Tracking.cpp +1 -0
  130. data/test/test_Type.cpp +100 -0
  131. data/test/test_global_functions.cpp +53 -6
  132. data/test/unittest.cpp +8 -0
  133. metadata +37 -20
  134. data/lib/version.rb +0 -3
  135. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  136. data/rice/Data_Object_defn.hpp +0 -84
  137. data/rice/Data_Type_defn.hpp +0 -190
  138. data/rice/Exception_defn.hpp +0 -68
  139. data/rice/HandlerRegistration.hpp +0 -15
  140. data/rice/Identifier.hpp +0 -50
  141. data/rice/Identifier.ipp +0 -29
  142. data/rice/detail/ExceptionHandler.hpp +0 -8
  143. data/rice/detail/ExceptionHandler.ipp +0 -28
  144. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  145. data/rice/detail/Jump_Tag.hpp +0 -21
  146. data/rice/detail/NativeAttribute.hpp +0 -64
  147. data/rice/detail/NativeAttribute.ipp +0 -112
  148. data/rice/detail/from_ruby_defn.hpp +0 -38
  149. data/rice/detail/to_ruby_defn.hpp +0 -48
  150. data/test/test_Jump_Tag.cpp +0 -17
  151. data/test/test_To_From_Ruby.cpp +0 -399
data/include/rice/stl.hpp CHANGED
@@ -2,12 +2,86 @@
2
2
  #define Rice__stl__hpp_
3
3
 
4
4
 
5
+ // ========= exception.hpp =========
6
+
7
+ namespace Rice::stl
8
+ {
9
+ extern Class rb_cStlException;
10
+ }
11
+
12
+
13
+ // --------- exception.ipp ---------
14
+ #include <exception>
15
+
16
+ // Libraries sometime inherit custom exception objects from std::exception,
17
+ // so define it for Ruby if necessary
18
+ namespace Rice::stl
19
+ {
20
+ inline Class rb_cStlException;
21
+
22
+ inline void define_stl_exception()
23
+ {
24
+ Module rb_mRice = define_module("Rice");
25
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
26
+ rb_cStlException = define_class_under<std::exception>(rb_mStd, "Exception", rb_eStandardError).
27
+ define_constructor(Constructor<std::exception>()).
28
+ define_method("message", &std::exception::what);
29
+ }
30
+ }
31
+
32
+ namespace Rice::detail
33
+ {
34
+ template<>
35
+ struct Type<std::exception>
36
+ {
37
+ static bool verify()
38
+ {
39
+ Rice::stl::define_stl_exception();
40
+ return true;
41
+ }
42
+ };
43
+ }
44
+
45
+
46
+ // ========= exception_ptr.hpp =========
47
+
48
+
49
+ // --------- exception_ptr.ipp ---------
50
+ #include <functional>
51
+
52
+ namespace Rice::stl
53
+ {
54
+ inline Data_Type<std::exception_ptr> define_exception_ptr()
55
+ {
56
+ Module rb_mRice = define_module("Rice");
57
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
58
+
59
+ return define_class_under<std::exception_ptr>(rb_mStd, "ExceptionPtr");
60
+ }
61
+ }
62
+
63
+ namespace Rice::detail
64
+ {
65
+ template<>
66
+ struct Type<std::exception_ptr>
67
+ {
68
+ static bool verify()
69
+ {
70
+ if (!detail::Registries::instance.types.isDefined<std::exception_ptr>())
71
+ {
72
+ stl::define_exception_ptr();
73
+ }
74
+
75
+ return true;
76
+ }
77
+ };
78
+ }
79
+
80
+
5
81
  // ========= string.hpp =========
6
82
 
7
83
 
8
84
  // --------- string.ipp ---------
9
- #include <string>
10
-
11
85
  namespace Rice::detail
12
86
  {
13
87
  template<>
@@ -49,9 +123,16 @@ namespace Rice::detail
49
123
  {
50
124
  }
51
125
 
52
- bool is_convertible(VALUE value)
126
+ Convertible is_convertible(VALUE value)
53
127
  {
54
- return rb_type(value) == RUBY_T_STRING;
128
+ switch (rb_type(value))
129
+ {
130
+ case RUBY_T_STRING:
131
+ return Convertible::Exact;
132
+ break;
133
+ default:
134
+ return Convertible::None;
135
+ }
55
136
  }
56
137
 
57
138
  std::string convert(VALUE value)
@@ -81,9 +162,16 @@ namespace Rice::detail
81
162
  {
82
163
  }
83
164
 
84
- bool is_convertible(VALUE value)
165
+ Convertible is_convertible(VALUE value)
85
166
  {
86
- return rb_type(value) == RUBY_T_STRING;
167
+ switch (rb_type(value))
168
+ {
169
+ case RUBY_T_STRING:
170
+ return Convertible::Exact;
171
+ break;
172
+ default:
173
+ return Convertible::None;
174
+ }
87
175
  }
88
176
 
89
177
  std::string& convert(VALUE value)
@@ -109,9 +197,16 @@ namespace Rice::detail
109
197
  class From_Ruby<std::string*>
110
198
  {
111
199
  public:
112
- bool is_convertible(VALUE value)
200
+ Convertible is_convertible(VALUE value)
113
201
  {
114
- return rb_type(value) == RUBY_T_STRING;
202
+ switch (rb_type(value))
203
+ {
204
+ case RUBY_T_STRING:
205
+ return Convertible::Exact;
206
+ break;
207
+ default:
208
+ return Convertible::None;
209
+ }
115
210
  }
116
211
 
117
212
  std::string* convert(VALUE value)
@@ -129,9 +224,16 @@ namespace Rice::detail
129
224
  class From_Ruby<std::string*&>
130
225
  {
131
226
  public:
132
- bool is_convertible(VALUE value)
227
+ Convertible is_convertible(VALUE value)
133
228
  {
134
- return rb_type(value) == RUBY_T_STRING;
229
+ switch (rb_type(value))
230
+ {
231
+ case RUBY_T_STRING:
232
+ return Convertible::Exact;
233
+ break;
234
+ default:
235
+ return Convertible::None;
236
+ }
135
237
  }
136
238
 
137
239
  std::string* convert(VALUE value)
@@ -193,9 +295,16 @@ namespace Rice::detail
193
295
  {
194
296
  }
195
297
 
196
- bool is_convertible(VALUE value)
298
+ Convertible is_convertible(VALUE value)
197
299
  {
198
- return rb_type(value) == RUBY_T_STRING;
300
+ switch (rb_type(value))
301
+ {
302
+ case RUBY_T_STRING:
303
+ return Convertible::Exact;
304
+ break;
305
+ default:
306
+ return Convertible::None;
307
+ }
199
308
  }
200
309
 
201
310
  std::string_view convert(VALUE value)
@@ -251,6 +360,18 @@ namespace Rice::detail
251
360
  class From_Ruby<std::complex<T>>
252
361
  {
253
362
  public:
363
+ Convertible is_convertible(VALUE value)
364
+ {
365
+ switch (rb_type(value))
366
+ {
367
+ case RUBY_T_COMPLEX:
368
+ return Convertible::Exact;
369
+ break;
370
+ default:
371
+ return Convertible::None;
372
+ }
373
+ }
374
+
254
375
  std::complex<T> convert(VALUE value)
255
376
  {
256
377
  VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
@@ -258,17 +379,24 @@ namespace Rice::detail
258
379
 
259
380
  return std::complex<T>(From_Ruby<T>().convert(real), From_Ruby<T>().convert(imaginary));
260
381
  }
261
-
262
- bool is_convertible(VALUE value)
263
- {
264
- return rb_type(value) == RUBY_T_COMPLEX;
265
- }
266
382
  };
267
383
 
268
384
  template<typename T>
269
385
  class From_Ruby<std::complex<T>&>
270
386
  {
271
387
  public:
388
+ Convertible is_convertible(VALUE value)
389
+ {
390
+ switch (rb_type(value))
391
+ {
392
+ case RUBY_T_COMPLEX:
393
+ return Convertible::Exact;
394
+ break;
395
+ default:
396
+ return Convertible::None;
397
+ }
398
+ }
399
+
272
400
  std::complex<T>& convert(VALUE value)
273
401
  {
274
402
  VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
@@ -278,11 +406,6 @@ namespace Rice::detail
278
406
  return this->converted_;
279
407
  }
280
408
 
281
- bool is_convertible(VALUE value)
282
- {
283
- return rb_type(value) == RUBY_T_COMPLEX;
284
- }
285
-
286
409
  private:
287
410
  std::complex<T> converted_;
288
411
  };
@@ -354,6 +477,18 @@ namespace Rice::detail
354
477
  class From_Ruby<std::optional<T>>
355
478
  {
356
479
  public:
480
+ Convertible is_convertible(VALUE value)
481
+ {
482
+ switch (rb_type(value))
483
+ {
484
+ case RUBY_T_NIL:
485
+ return Convertible::Exact;
486
+ break;
487
+ default:
488
+ return From_Ruby<T>().is_convertible(value);
489
+ }
490
+ }
491
+
357
492
  std::optional<T> convert(VALUE value)
358
493
  {
359
494
  if (value == Qnil)
@@ -371,6 +506,18 @@ namespace Rice::detail
371
506
  class From_Ruby<std::optional<T>&>
372
507
  {
373
508
  public:
509
+ Convertible is_convertible(VALUE value)
510
+ {
511
+ switch (rb_type(value))
512
+ {
513
+ case RUBY_T_NIL:
514
+ return Convertible::Exact;
515
+ break;
516
+ default:
517
+ return From_Ruby<T>().is_convertible(value);
518
+ }
519
+ }
520
+
374
521
  std::optional<T>& convert(VALUE value)
375
522
  {
376
523
  if (value == Qnil)
@@ -383,7 +530,6 @@ namespace Rice::detail
383
530
  }
384
531
  return this->converted_;
385
532
  }
386
-
387
533
  private:
388
534
  std::optional<T> converted_;
389
535
  };
@@ -421,9 +567,9 @@ namespace Rice::detail
421
567
  class From_Ruby<std::reference_wrapper<T>>
422
568
  {
423
569
  public:
424
- bool is_convertible(VALUE value)
570
+ Convertible is_convertible(VALUE value)
425
571
  {
426
- return true;
572
+ return this->converter_.is_convertible(value);
427
573
  }
428
574
 
429
575
  std::reference_wrapper<T> convert(VALUE value)
@@ -494,12 +640,11 @@ namespace Rice::detail
494
640
  class To_Ruby<std::unique_ptr<T>>
495
641
  {
496
642
  public:
643
+ using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
644
+
497
645
  VALUE convert(std::unique_ptr<T>& data)
498
646
  {
499
647
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
500
-
501
- // Use custom wrapper type
502
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
503
648
  return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
504
649
  }
505
650
  };
@@ -508,26 +653,84 @@ namespace Rice::detail
508
653
  class To_Ruby<std::unique_ptr<T>&>
509
654
  {
510
655
  public:
656
+ using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
657
+
511
658
  VALUE convert(std::unique_ptr<T>& data)
512
659
  {
513
660
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
514
-
515
- // Use custom wrapper type
516
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
517
661
  return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
518
662
  }
519
663
  };
520
664
 
665
+ template <typename T>
666
+ class From_Ruby<std::unique_ptr<T>>
667
+ {
668
+ public:
669
+ using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
670
+
671
+ Wrapper_T* is_same_smart_ptr(VALUE value)
672
+ {
673
+ Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
674
+ return dynamic_cast<Wrapper_T*>(wrapper);
675
+ }
676
+
677
+ Convertible is_convertible(VALUE value)
678
+ {
679
+ if (!is_same_smart_ptr(value))
680
+ return Convertible::None;
681
+
682
+ switch (rb_type(value))
683
+ {
684
+ case RUBY_T_DATA:
685
+ return Convertible::Exact;
686
+ break;
687
+ default:
688
+ return Convertible::None;
689
+ }
690
+ }
691
+
692
+ std::unique_ptr<T> convert(VALUE value)
693
+ {
694
+ Wrapper_T* smartWrapper = is_same_smart_ptr(value);
695
+ if (!smartWrapper)
696
+ {
697
+ std::string message = "Invalid smart pointer wrapper";
698
+ throw std::runtime_error(message.c_str());
699
+ }
700
+ return std::move(smartWrapper->data());
701
+ }
702
+ };
703
+
521
704
  template <typename T>
522
705
  class From_Ruby<std::unique_ptr<T>&>
523
706
  {
524
707
  public:
525
- std::unique_ptr<T>& convert(VALUE value)
708
+ using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
709
+
710
+ Wrapper_T* is_same_smart_ptr(VALUE value)
526
711
  {
527
712
  Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
713
+ return dynamic_cast<Wrapper_T*>(wrapper);
714
+ }
715
+
716
+ Convertible is_convertible(VALUE value)
717
+ {
718
+ if (!is_same_smart_ptr(value))
719
+ return Convertible::None;
720
+
721
+ switch (rb_type(value))
722
+ {
723
+ case RUBY_T_DATA:
724
+ return Convertible::Exact;
725
+ break;
726
+ default:
727
+ return Convertible::None;
728
+ }
729
+ }
528
730
 
529
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
530
- Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
731
+ std::unique_ptr<T>& convert(VALUE value)
732
+ {
733
+ Wrapper_T* smartWrapper = is_same_smart_ptr(value);
531
734
  if (!smartWrapper)
532
735
  {
533
736
  std::string message = "Invalid smart pointer wrapper";
@@ -551,36 +754,68 @@ namespace Rice::detail
551
754
  class To_Ruby<std::shared_ptr<T>>
552
755
  {
553
756
  public:
757
+ using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
758
+
554
759
  VALUE convert(std::shared_ptr<T>& data)
555
760
  {
556
761
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
557
-
558
- // Use custom wrapper type
559
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
560
762
  return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
561
763
  }
562
764
  };
563
765
 
766
+ template <>
767
+ class To_Ruby<std::shared_ptr<void>>
768
+ {
769
+ public:
770
+ using Wrapper_T = WrapperSmartPointer<std::shared_ptr, void>;
771
+
772
+ VALUE convert(std::shared_ptr<void>& data)
773
+ {
774
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(data.get());
775
+ return detail::wrap<std::shared_ptr<void>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
776
+ }
777
+ };
778
+
564
779
  template <typename T>
565
780
  class From_Ruby<std::shared_ptr<T>>
566
781
  {
567
782
  public:
783
+ using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
784
+
568
785
  From_Ruby() = default;
569
786
 
570
787
  explicit From_Ruby(Arg * arg) : arg_(arg)
571
788
  {
572
789
  }
573
790
 
791
+ Wrapper_T* is_same_smart_ptr(VALUE value)
792
+ {
793
+ Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
794
+ return dynamic_cast<Wrapper_T*>(wrapper);
795
+ }
796
+
797
+ Convertible is_convertible(VALUE value)
798
+ {
799
+ if (!is_same_smart_ptr(value))
800
+ return Convertible::None;
801
+
802
+ switch (rb_type(value))
803
+ {
804
+ case RUBY_T_DATA:
805
+ return Convertible::Exact;
806
+ break;
807
+ default:
808
+ return Convertible::None;
809
+ }
810
+ }
811
+
574
812
  std::shared_ptr<T> convert(VALUE value)
575
813
  {
576
814
  if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
577
815
  return this->arg_->template defaultValue<std::shared_ptr<T>>();
578
816
  }
579
817
 
580
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
581
-
582
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
583
- Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
818
+ Wrapper_T* smartWrapper = is_same_smart_ptr(value);
584
819
  if (!smartWrapper)
585
820
  {
586
821
  std::string message = "Invalid smart pointer wrapper";
@@ -588,7 +823,6 @@ namespace Rice::detail
588
823
  }
589
824
  return smartWrapper->data();
590
825
  }
591
-
592
826
  private:
593
827
  Arg* arg_ = nullptr;
594
828
  };
@@ -597,12 +831,11 @@ namespace Rice::detail
597
831
  class To_Ruby<std::shared_ptr<T>&>
598
832
  {
599
833
  public:
834
+ using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
835
+
600
836
  VALUE convert(std::shared_ptr<T>& data)
601
837
  {
602
838
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
603
-
604
- // Use custom wrapper type
605
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
606
839
  return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
607
840
  }
608
841
  };
@@ -611,22 +844,42 @@ namespace Rice::detail
611
844
  class From_Ruby<std::shared_ptr<T>&>
612
845
  {
613
846
  public:
847
+ using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
848
+
614
849
  From_Ruby() = default;
615
850
 
616
851
  explicit From_Ruby(Arg * arg) : arg_(arg)
617
852
  {
618
853
  }
619
854
 
855
+ Wrapper_T* is_same_smart_ptr(VALUE value)
856
+ {
857
+ Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
858
+ return dynamic_cast<Wrapper_T*>(wrapper);
859
+ }
860
+
861
+ Convertible is_convertible(VALUE value)
862
+ {
863
+ if (!is_same_smart_ptr(value))
864
+ return Convertible::None;
865
+
866
+ switch (rb_type(value))
867
+ {
868
+ case RUBY_T_DATA:
869
+ return Convertible::Exact;
870
+ break;
871
+ default:
872
+ return Convertible::None;
873
+ }
874
+ }
875
+
620
876
  std::shared_ptr<T>& convert(VALUE value)
621
877
  {
622
878
  if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
623
879
  return this->arg_->template defaultValue<std::shared_ptr<T>>();
624
880
  }
625
881
 
626
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
627
-
628
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
629
- Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
882
+ Wrapper_T* smartWrapper = is_same_smart_ptr(value);
630
883
  if (!smartWrapper)
631
884
  {
632
885
  std::string message = "Invalid smart pointer wrapper";
@@ -691,9 +944,9 @@ namespace Rice::detail
691
944
  class From_Ruby<std::monostate>
692
945
  {
693
946
  public:
694
- bool is_convertible(VALUE value)
947
+ Convertible is_convertible(VALUE value)
695
948
  {
696
- return false;
949
+ return Convertible::None;
697
950
  }
698
951
 
699
952
  std::monostate convert(VALUE value)
@@ -706,9 +959,9 @@ namespace Rice::detail
706
959
  class From_Ruby<std::monostate&>
707
960
  {
708
961
  public:
709
- bool is_convertible(VALUE value)
962
+ Convertible is_convertible(VALUE value)
710
963
  {
711
- return false;
964
+ return Convertible::None;
712
965
  }
713
966
 
714
967
  std::monostate& convert(VALUE value)
@@ -722,6 +975,81 @@ namespace Rice::detail
722
975
  }
723
976
 
724
977
 
978
+ // ========= type_index.hpp =========
979
+
980
+
981
+ // --------- type_index.ipp ---------
982
+ #include <typeindex>
983
+
984
+ namespace Rice::stl
985
+ {
986
+ inline Data_Type<std::type_index> define_type_index()
987
+ {
988
+ Module rb_mRice = define_module("Rice");
989
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
990
+
991
+ return define_class_under<std::type_index>(rb_mStd, "TypeIndex").
992
+ define_constructor(Constructor<std::type_index, const std::type_info&>()).
993
+ define_method("hash_code", &std::type_index::hash_code).
994
+ define_method("name", &std::type_index::name);
995
+ }
996
+ }
997
+
998
+ namespace Rice::detail
999
+ {
1000
+ template<>
1001
+ struct Type<std::type_index>
1002
+ {
1003
+ static bool verify()
1004
+ {
1005
+ if (!detail::Registries::instance.types.isDefined<std::type_index>())
1006
+ {
1007
+ stl::define_type_index();
1008
+ }
1009
+
1010
+ return true;
1011
+ }
1012
+ };
1013
+ }
1014
+
1015
+
1016
+ // ========= type_info.hpp =========
1017
+
1018
+
1019
+ // --------- type_info.ipp ---------
1020
+ #include <typeinfo>
1021
+
1022
+ namespace Rice::stl
1023
+ {
1024
+ inline Data_Type<std::type_info> define_type_info()
1025
+ {
1026
+ Module rb_mRice = define_module("Rice");
1027
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
1028
+
1029
+ return define_class_under<std::type_info>(rb_mStd, "TypeInfo").
1030
+ define_method("hash_code", &std::type_info::hash_code).
1031
+ define_method("name", &std::type_info::name);
1032
+ }
1033
+ }
1034
+
1035
+ namespace Rice::detail
1036
+ {
1037
+ template<>
1038
+ struct Type<std::type_info>
1039
+ {
1040
+ static inline bool verify()
1041
+ {
1042
+ if (!detail::Registries::instance.types.isDefined<std::type_info>())
1043
+ {
1044
+ stl::define_type_info();
1045
+ }
1046
+
1047
+ return true;
1048
+ }
1049
+ };
1050
+ }
1051
+
1052
+
725
1053
  // ========= variant.hpp =========
726
1054
 
727
1055
 
@@ -781,14 +1109,24 @@ namespace Rice::detail
781
1109
  comma operator to return true to the fold expression. If the variant does not have
782
1110
  a value for the type then return false.
783
1111
 
784
- The fold operator is or (||). If an index returns false, then the next index is evaulated
1112
+ The fold operator is or (||). If an index returns false, then the next index is evaluated
785
1113
  up until I.
786
1114
 
787
1115
  Code inspired by https://www.foonathan.net/2020/05/fold-tricks/ */
788
1116
 
789
1117
  VALUE result = Qnil;
1118
+
1119
+ #if defined(__GNUC__) || defined(__clang__)
1120
+ #pragma GCC diagnostic push
1121
+ #pragma GCC diagnostic ignored "-Wunused-value"
1122
+ #endif
1123
+
790
1124
  ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
791
1125
  (result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
1126
+
1127
+ #if defined(__GNUC__) || defined(__clang__)
1128
+ #pragma GCC diagnostic pop
1129
+ #endif
792
1130
 
793
1131
  return result;
794
1132
  }
@@ -818,9 +1156,19 @@ namespace Rice::detail
818
1156
 
819
1157
  // See comments above for explanation of this code
820
1158
  VALUE result = Qnil;
1159
+
1160
+ #if defined(__GNUC__) || defined(__clang__)
1161
+ #pragma GCC diagnostic push
1162
+ #pragma GCC diagnostic ignored "-Wunused-value"
1163
+ #endif
1164
+
821
1165
  ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
822
1166
  (result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
823
1167
 
1168
+ #if defined(__GNUC__) || defined(__clang__)
1169
+ #pragma GCC diagnostic pop
1170
+ #endif
1171
+
824
1172
  return result;
825
1173
  }
826
1174
 
@@ -834,83 +1182,102 @@ namespace Rice::detail
834
1182
  template<typename...Types>
835
1183
  class From_Ruby<std::variant<Types...>>
836
1184
  {
837
- private:
838
- // Possible converters we could use for this variant
839
- using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
840
-
841
1185
  public:
1186
+ Convertible is_convertible(VALUE value)
1187
+ {
1188
+ Convertible result = Convertible::None;
1189
+
1190
+ for_each_tuple(this->fromRubys_,
1191
+ [&](auto& fromRuby)
1192
+ {
1193
+ result = result | fromRuby.is_convertible(value);
1194
+ });
1195
+
1196
+ return result;
1197
+ }
1198
+
1199
+ // This method search through a variant's types to figure out which one the
1200
+ // currently Ruby value best matches. It then returns the index of the type.
1201
+ int figureIndex(VALUE value)
1202
+ {
1203
+ int i = 0;
1204
+ int index = -1;
1205
+ Convertible foundConversion = Convertible::None;
1206
+
1207
+ for_each_tuple(this->fromRubys_,
1208
+ [&](auto& fromRuby)
1209
+ {
1210
+ Convertible isConvertible = fromRuby.is_convertible(value);
1211
+
1212
+ if (isConvertible > foundConversion)
1213
+ {
1214
+ index = i;
1215
+ foundConversion = isConvertible;
1216
+ }
1217
+ i++;
1218
+ });
1219
+
1220
+ if (index == -1)
1221
+ {
1222
+ rb_raise(rb_eArgError, "Could not find converter for variant");
1223
+ }
1224
+
1225
+ return index;
1226
+ }
1227
+
842
1228
  /* This method loops over each type in the variant, creates a From_Ruby converter,
843
1229
  and then check if the converter can work with the provided Rby value (it checks
844
- the type of the Ruby object to see if it matches the variant type).
1230
+ the type of the Ruby object to see if it matches the variant type).
845
1231
  If yes, then the converter runs. If no, then the method recursively calls itself
846
- increasing the index.
847
-
1232
+ increasing the index.
1233
+
848
1234
  We use recursion, with a constexpr, to avoid having to instantiate an instance
849
1235
  of the variant to store results from a fold expression like the To_Ruby code
850
1236
  does above. That allows us to process variants with non default constructible
851
1237
  arguments like std::reference_wrapper. */
852
1238
  template <std::size_t I = 0>
853
- std::variant<Types...> convertInternal(VALUE value)
1239
+ std::variant<Types...> convertInternal(VALUE value, int index)
854
1240
  {
855
- // Loop over each possible type in the variant.
856
1241
  if constexpr (I < std::variant_size_v<std::variant<Types...>>)
857
1242
  {
858
- // Get the converter for the current index
859
- typename std::tuple_element_t<I, From_Ruby_Ts> converter;
860
-
861
- // See if it will work
862
- if (converter.is_convertible(value))
1243
+ if (I == index)
863
1244
  {
864
- return converter.convert(value);
1245
+ auto fromRuby = std::get<I>(this->fromRubys_);
1246
+ return fromRuby.convert(value);
865
1247
  }
866
1248
  else
867
1249
  {
868
- return convertInternal<I + 1>(value);
1250
+ return convertInternal<I + 1>(value, index);
869
1251
  }
870
1252
  }
871
- throw std::runtime_error("Could not find converter for variant");
1253
+ rb_raise(rb_eArgError, "Could not find converter for variant");
872
1254
  }
873
1255
 
874
1256
  std::variant<Types...> convert(VALUE value)
875
1257
  {
876
- return convertInternal(value);
1258
+ int index = this->figureIndex(value);
1259
+ return this->convertInternal(value, index);
877
1260
  }
878
- };
879
1261
 
880
- template<typename...Types>
881
- class From_Ruby<std::variant<Types...>&>
882
- {
883
1262
  private:
884
1263
  // Possible converters we could use for this variant
885
1264
  using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
1265
+ From_Ruby_Ts fromRubys_;
1266
+ };
886
1267
 
1268
+ template<typename...Types>
1269
+ class From_Ruby<std::variant<Types...>&> : public From_Ruby<std::variant<Types...>>
1270
+ {
887
1271
  public:
888
- template <std::size_t I = 0>
889
- std::variant<Types...> convertInternal(VALUE value)
1272
+ std::variant<Types...>& convert(VALUE value)
890
1273
  {
891
- // Loop over each possible type in the variant
892
- if constexpr (I < std::variant_size_v<std::variant<Types...>>)
893
- {
894
- // Get the converter for the current index
895
- typename std::tuple_element_t<I, From_Ruby_Ts> converter;
896
-
897
- // See if it will work
898
- if (converter.is_convertible(value))
899
- {
900
- return converter.convert(value);
901
- }
902
- else
903
- {
904
- return convertInternal<I + 1>(value);
905
- }
906
- }
907
- throw std::runtime_error("Could not find converter for variant");
1274
+ int index = this->figureIndex(value);
1275
+ this->converted_ = this->convertInternal(value, index);
1276
+ return this->converted_;
908
1277
  }
909
1278
 
910
- std::variant<Types...> convert(VALUE value)
911
- {
912
- return convertInternal(value);
913
- }
1279
+ private:
1280
+ std::variant<Types...> converted_;
914
1281
  };
915
1282
  }
916
1283
 
@@ -924,7 +1291,7 @@ namespace Rice
924
1291
  Data_Type<T> define_pair(std::string name);
925
1292
 
926
1293
  template<typename T>
927
- Data_Type<T> define_pair_under(Object module, std::string name);
1294
+ Data_Type<T> define_pair_under(Object parent, std::string name);
928
1295
  }
929
1296
 
930
1297
 
@@ -1044,17 +1411,17 @@ namespace Rice
1044
1411
  } // namespace
1045
1412
 
1046
1413
  template<typename T>
1047
- Data_Type<T> define_pair_under(Object module, std::string name)
1414
+ Data_Type<T> define_pair_under(Object parent, std::string name)
1048
1415
  {
1049
1416
  if (detail::Registries::instance.types.isDefined<T>())
1050
1417
  {
1051
1418
  // If the pair has been previously seen it will be registered but may
1052
1419
  // not be associated with the constant Module::<name>
1053
- module.const_set_maybe(name, Data_Type<T>().klass());
1420
+ parent.const_set_maybe(name, Data_Type<T>().klass());
1054
1421
  return Data_Type<T>();
1055
1422
  }
1056
1423
 
1057
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
1424
+ Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, name.c_str());
1058
1425
  stl::PairHelper helper(result);
1059
1426
  return result;
1060
1427
  }
@@ -1078,10 +1445,11 @@ namespace Rice
1078
1445
  template<typename T>
1079
1446
  Data_Type<T> define_pair_auto()
1080
1447
  {
1081
- std::string klassName = detail::makeClassName(typeid(T));
1448
+ std::string name = detail::typeName(typeid(T));
1449
+ std::string klassName = detail::makeClassName(name);
1082
1450
  Module rb_mRice = define_module("Rice");
1083
- Module rb_mpair = define_module_under(rb_mRice, "Std");
1084
- return define_pair_under<T>(rb_mpair, klassName);
1451
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
1452
+ return define_pair_under<T>(rb_mStd, klassName);
1085
1453
  }
1086
1454
 
1087
1455
  namespace detail
@@ -1138,8 +1506,10 @@ namespace Rice
1138
1506
  using Key_T = typename T::key_type;
1139
1507
  using Mapped_T = typename T::mapped_type;
1140
1508
  using Value_T = typename T::value_type;
1509
+ using Reference_T = typename T::reference;
1141
1510
  using Size_T = typename T::size_type;
1142
1511
  using Difference_T = typename T::difference_type;
1512
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1143
1513
 
1144
1514
  public:
1145
1515
  MapHelper(Data_Type<T> klass) : klass_(klass)
@@ -1288,7 +1658,7 @@ namespace Rice
1288
1658
  return std::nullopt;
1289
1659
  }
1290
1660
  })
1291
- .define_method("[]=", [](T& map, Key_T key, Mapped_T value) -> Mapped_T
1661
+ .define_method("[]=", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1292
1662
  {
1293
1663
  map[key] = value;
1294
1664
  return value;
@@ -1309,10 +1679,10 @@ namespace Rice
1309
1679
  klass_.define_method("to_h", [](T& map)
1310
1680
  {
1311
1681
  VALUE result = rb_hash_new();
1312
- std::for_each(map.begin(), map.end(), [&result](const typename T::reference pair)
1682
+ std::for_each(map.begin(), map.end(), [&result](const Reference_T pair)
1313
1683
  {
1314
1684
  VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
1315
- VALUE value = detail::To_Ruby<Mapped_T&>().convert(pair.second);
1685
+ VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
1316
1686
  rb_hash_aset(result, key, value);
1317
1687
  });
1318
1688
 
@@ -1359,17 +1729,17 @@ namespace Rice
1359
1729
  } // namespace
1360
1730
 
1361
1731
  template<typename T>
1362
- Data_Type<T> define_map_under(Object module, std::string name)
1732
+ Data_Type<T> define_map_under(Object parent, std::string name)
1363
1733
  {
1364
1734
  if (detail::Registries::instance.types.isDefined<T>())
1365
1735
  {
1366
1736
  // If the map has been previously seen it will be registered but may
1367
1737
  // not be associated with the constant Module::<name>
1368
- module.const_set_maybe(name, Data_Type<T>().klass());
1738
+ parent.const_set_maybe(name, Data_Type<T>().klass());
1369
1739
  return Data_Type<T>();
1370
1740
  }
1371
1741
 
1372
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
1742
+ Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, name.c_str());
1373
1743
  stl::MapHelper helper(result);
1374
1744
  return result;
1375
1745
  }
@@ -1393,10 +1763,11 @@ namespace Rice
1393
1763
  template<typename T>
1394
1764
  Data_Type<T> define_map_auto()
1395
1765
  {
1396
- std::string klassName = detail::makeClassName(typeid(T));
1766
+ std::string name = detail::typeName(typeid(T));
1767
+ std::string klassName = detail::makeClassName(name);
1397
1768
  Module rb_mRice = define_module("Rice");
1398
- Module rb_mmap = define_module_under(rb_mRice, "Std");
1399
- return define_map_under<T>(rb_mmap, klassName);
1769
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
1770
+ return define_map_under<T>(rb_mStd, klassName);
1400
1771
  }
1401
1772
 
1402
1773
  namespace detail
@@ -1457,16 +1828,31 @@ namespace Rice
1457
1828
  {
1458
1829
  }
1459
1830
 
1831
+ Convertible is_convertible(VALUE value)
1832
+ {
1833
+ switch (rb_type(value))
1834
+ {
1835
+ case RUBY_T_DATA:
1836
+ return Convertible::Exact;
1837
+ break;
1838
+ case RUBY_T_HASH:
1839
+ return Convertible::Cast;
1840
+ break;
1841
+ default:
1842
+ return Convertible::None;
1843
+ }
1844
+ }
1845
+
1460
1846
  std::map<T, U> convert(VALUE value)
1461
1847
  {
1462
1848
  switch (rb_type(value))
1463
1849
  {
1464
- case T_DATA:
1850
+ case RUBY_T_DATA:
1465
1851
  {
1466
1852
  // This is a wrapped map (hopefully!)
1467
1853
  return *Data_Object<std::map<T, U>>::from_ruby(value);
1468
1854
  }
1469
- case T_HASH:
1855
+ case RUBY_T_HASH:
1470
1856
  {
1471
1857
  // If this an Ruby hash and the mapped type is copyable
1472
1858
  if constexpr (std::is_default_constructible_v<U>)
@@ -1474,7 +1860,7 @@ namespace Rice
1474
1860
  return MapFromHash<T, U>::convert(value);
1475
1861
  }
1476
1862
  }
1477
- case T_NIL:
1863
+ case RUBY_T_NIL:
1478
1864
  {
1479
1865
  if (this->arg_ && this->arg_->hasDefaultValue())
1480
1866
  {
@@ -1503,16 +1889,31 @@ namespace Rice
1503
1889
  {
1504
1890
  }
1505
1891
 
1892
+ Convertible is_convertible(VALUE value)
1893
+ {
1894
+ switch (rb_type(value))
1895
+ {
1896
+ case RUBY_T_DATA:
1897
+ return Convertible::Exact;
1898
+ break;
1899
+ case RUBY_T_HASH:
1900
+ return Convertible::Cast;
1901
+ break;
1902
+ default:
1903
+ return Convertible::None;
1904
+ }
1905
+ }
1906
+
1506
1907
  std::map<T, U>& convert(VALUE value)
1507
1908
  {
1508
1909
  switch (rb_type(value))
1509
1910
  {
1510
- case T_DATA:
1911
+ case RUBY_T_DATA:
1511
1912
  {
1512
1913
  // This is a wrapped map (hopefully!)
1513
1914
  return *Data_Object<std::map<T, U>>::from_ruby(value);
1514
1915
  }
1515
- case T_HASH:
1916
+ case RUBY_T_HASH:
1516
1917
  {
1517
1918
  // If this an Ruby array and the map type is copyable
1518
1919
  if constexpr (std::is_default_constructible_v<std::map<T, U>>)
@@ -1521,7 +1922,7 @@ namespace Rice
1521
1922
  return this->converted_;
1522
1923
  }
1523
1924
  }
1524
- case T_NIL:
1925
+ case RUBY_T_NIL:
1525
1926
  {
1526
1927
  if (this->arg_ && this->arg_->hasDefaultValue())
1527
1928
  {
@@ -1545,16 +1946,34 @@ namespace Rice
1545
1946
  class From_Ruby<std::map<T, U>*>
1546
1947
  {
1547
1948
  public:
1949
+ Convertible is_convertible(VALUE value)
1950
+ {
1951
+ switch (rb_type(value))
1952
+ {
1953
+ case RUBY_T_DATA:
1954
+ return Convertible::Exact;
1955
+ break;
1956
+ case RUBY_T_NIL:
1957
+ return Convertible::Exact;
1958
+ break;
1959
+ case RUBY_T_HASH:
1960
+ return Convertible::Cast;
1961
+ break;
1962
+ default:
1963
+ return Convertible::None;
1964
+ }
1965
+ }
1966
+
1548
1967
  std::map<T, U>* convert(VALUE value)
1549
1968
  {
1550
1969
  switch (rb_type(value))
1551
1970
  {
1552
- case T_DATA:
1971
+ case RUBY_T_DATA:
1553
1972
  {
1554
1973
  // This is a wrapped map (hopefully!)
1555
1974
  return Data_Object<std::map<T, U>>::from_ruby(value);
1556
1975
  }
1557
- case T_HASH:
1976
+ case RUBY_T_HASH:
1558
1977
  {
1559
1978
  // If this an Ruby array and the map type is copyable
1560
1979
  if constexpr (std::is_default_constructible_v<U>)
@@ -1586,7 +2005,7 @@ namespace Rice
1586
2005
  Data_Type<U> define_unordered_map(std::string name);
1587
2006
 
1588
2007
  template<typename U>
1589
- Data_Type<U> define_unordered_map_under(Object module, std::string name);
2008
+ Data_Type<U> define_unordered_map_under(Object parent, std::string name);
1590
2009
  }
1591
2010
 
1592
2011
 
@@ -1608,8 +2027,10 @@ namespace Rice
1608
2027
  using Key_T = typename T::key_type;
1609
2028
  using Mapped_T = typename T::mapped_type;
1610
2029
  using Value_T = typename T::value_type;
2030
+ using Reference_T = typename T::reference;
1611
2031
  using Size_T = typename T::size_type;
1612
2032
  using Difference_T = typename T::difference_type;
2033
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1613
2034
 
1614
2035
  public:
1615
2036
  UnorderedMapHelper(Data_Type<T> klass) : klass_(klass)
@@ -1758,7 +2179,7 @@ namespace Rice
1758
2179
  return std::nullopt;
1759
2180
  }
1760
2181
  })
1761
- .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T value) -> Mapped_T
2182
+ .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T& value) -> Mapped_T
1762
2183
  {
1763
2184
  unordered_map[key] = value;
1764
2185
  return value;
@@ -1779,10 +2200,10 @@ namespace Rice
1779
2200
  klass_.define_method("to_h", [](T& unordered_map)
1780
2201
  {
1781
2202
  VALUE result = rb_hash_new();
1782
- std::for_each(unordered_map.begin(), unordered_map.end(), [&result](const auto& pair)
2203
+ std::for_each(unordered_map.begin(), unordered_map.end(), [&result](const Reference_T& pair)
1783
2204
  {
1784
- VALUE key = detail::To_Ruby<Key_T>().convert(pair.first);
1785
- VALUE value = detail::To_Ruby<Mapped_T>().convert(pair.second);
2205
+ VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
2206
+ VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
1786
2207
  rb_hash_aset(result, key, value);
1787
2208
  });
1788
2209
 
@@ -1829,17 +2250,17 @@ namespace Rice
1829
2250
  } // namespace
1830
2251
 
1831
2252
  template<typename T>
1832
- Data_Type<T> define_unordered_map_under(Object module, std::string name)
2253
+ Data_Type<T> define_unordered_map_under(Object parent, std::string name)
1833
2254
  {
1834
2255
  if (detail::Registries::instance.types.isDefined<T>())
1835
2256
  {
1836
2257
  // If the unordered_map has been previously seen it will be registered but may
1837
2258
  // not be associated with the constant Module::<name>
1838
- module.const_set_maybe(name, Data_Type<T>().klass());
2259
+ parent.const_set_maybe(name, Data_Type<T>().klass());
1839
2260
  return Data_Type<T>();
1840
2261
  }
1841
2262
 
1842
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
2263
+ Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, name.c_str());
1843
2264
  stl::UnorderedMapHelper helper(result);
1844
2265
  return result;
1845
2266
  }
@@ -1863,10 +2284,11 @@ namespace Rice
1863
2284
  template<typename T>
1864
2285
  Data_Type<T> define_unordered_map_auto()
1865
2286
  {
1866
- std::string klassName = detail::makeClassName(typeid(T));
2287
+ std::string name = detail::typeName(typeid(T));
2288
+ std::string klassName = detail::makeClassName(name);
1867
2289
  Module rb_mRice = define_module("Rice");
1868
- Module rb_munordered_map = define_module_under(rb_mRice, "Std");
1869
- return define_unordered_map_under<T>(rb_munordered_map, klassName);
2290
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
2291
+ return define_unordered_map_under<T>(rb_mStd, klassName);
1870
2292
  }
1871
2293
 
1872
2294
  namespace detail
@@ -1927,16 +2349,31 @@ namespace Rice
1927
2349
  {
1928
2350
  }
1929
2351
 
2352
+ Convertible is_convertible(VALUE value)
2353
+ {
2354
+ switch (rb_type(value))
2355
+ {
2356
+ case RUBY_T_DATA:
2357
+ return Convertible::Exact;
2358
+ break;
2359
+ case RUBY_T_HASH:
2360
+ return Convertible::Cast;
2361
+ break;
2362
+ default:
2363
+ return Convertible::None;
2364
+ }
2365
+ }
2366
+
1930
2367
  std::unordered_map<T, U> convert(VALUE value)
1931
2368
  {
1932
2369
  switch (rb_type(value))
1933
2370
  {
1934
- case T_DATA:
2371
+ case RUBY_T_DATA:
1935
2372
  {
1936
2373
  // This is a wrapped unordered_map (hopefully!)
1937
2374
  return *Data_Object<std::unordered_map<T, U>>::from_ruby(value);
1938
2375
  }
1939
- case T_HASH:
2376
+ case RUBY_T_HASH:
1940
2377
  {
1941
2378
  // If this an Ruby hash and the unordered_mapped type is copyable
1942
2379
  if constexpr (std::is_default_constructible_v<U>)
@@ -1944,7 +2381,7 @@ namespace Rice
1944
2381
  return UnorderedMapFromHash<T, U>::convert(value);
1945
2382
  }
1946
2383
  }
1947
- case T_NIL:
2384
+ case RUBY_T_NIL:
1948
2385
  {
1949
2386
  if (this->arg_ && this->arg_->hasDefaultValue())
1950
2387
  {
@@ -1973,16 +2410,31 @@ namespace Rice
1973
2410
  {
1974
2411
  }
1975
2412
 
2413
+ Convertible is_convertible(VALUE value)
2414
+ {
2415
+ switch (rb_type(value))
2416
+ {
2417
+ case RUBY_T_DATA:
2418
+ return Convertible::Exact;
2419
+ break;
2420
+ case RUBY_T_HASH:
2421
+ return Convertible::Cast;
2422
+ break;
2423
+ default:
2424
+ return Convertible::None;
2425
+ }
2426
+ }
2427
+
1976
2428
  std::unordered_map<T, U>& convert(VALUE value)
1977
2429
  {
1978
2430
  switch (rb_type(value))
1979
2431
  {
1980
- case T_DATA:
2432
+ case RUBY_T_DATA:
1981
2433
  {
1982
2434
  // This is a wrapped unordered_map (hopefully!)
1983
2435
  return *Data_Object<std::unordered_map<T, U>>::from_ruby(value);
1984
2436
  }
1985
- case T_HASH:
2437
+ case RUBY_T_HASH:
1986
2438
  {
1987
2439
  // If this an Ruby array and the unordered_map type is copyable
1988
2440
  if constexpr (std::is_default_constructible_v<std::unordered_map<T, U>>)
@@ -1991,7 +2443,7 @@ namespace Rice
1991
2443
  return this->converted_;
1992
2444
  }
1993
2445
  }
1994
- case T_NIL:
2446
+ case RUBY_T_NIL:
1995
2447
  {
1996
2448
  if (this->arg_ && this->arg_->hasDefaultValue())
1997
2449
  {
@@ -2015,16 +2467,34 @@ namespace Rice
2015
2467
  class From_Ruby<std::unordered_map<T, U>*>
2016
2468
  {
2017
2469
  public:
2470
+ Convertible is_convertible(VALUE value)
2471
+ {
2472
+ switch (rb_type(value))
2473
+ {
2474
+ case RUBY_T_DATA:
2475
+ return Convertible::Exact;
2476
+ break;
2477
+ case RUBY_T_NIL:
2478
+ return Convertible::Exact;
2479
+ break;
2480
+ case RUBY_T_HASH:
2481
+ return Convertible::Cast;
2482
+ break;
2483
+ default:
2484
+ return Convertible::None;
2485
+ }
2486
+ }
2487
+
2018
2488
  std::unordered_map<T, U>* convert(VALUE value)
2019
2489
  {
2020
2490
  switch (rb_type(value))
2021
2491
  {
2022
- case T_DATA:
2492
+ case RUBY_T_DATA:
2023
2493
  {
2024
2494
  // This is a wrapped unordered_map (hopefully!)
2025
2495
  return Data_Object<std::unordered_map<T, U>>::from_ruby(value);
2026
2496
  }
2027
- case T_HASH:
2497
+ case RUBY_T_HASH:
2028
2498
  {
2029
2499
  // If this an Ruby array and the unordered_map type is copyable
2030
2500
  if constexpr (std::is_default_constructible_v<U>)
@@ -2056,7 +2526,7 @@ namespace Rice
2056
2526
  Data_Type<T> define_vector(std::string name);
2057
2527
 
2058
2528
  template<typename T>
2059
- Data_Type<T> define_vector_under(Object module, std::string name);
2529
+ Data_Type<T> define_vector_under(Object parent, std::string name);
2060
2530
  }
2061
2531
 
2062
2532
 
@@ -2075,9 +2545,17 @@ namespace Rice
2075
2545
  template<typename T>
2076
2546
  class VectorHelper
2077
2547
  {
2548
+ // We do NOT use Reference_T and instead use Parameter_T to avoid the weirdness
2549
+ // of std::vector<bool>. Reference_T is actually a proxy class that we do not
2550
+ // want to have to register with Rice nor do we want to pass it around.
2078
2551
  using Value_T = typename T::value_type;
2079
2552
  using Size_T = typename T::size_type;
2080
2553
  using Difference_T = typename T::difference_type;
2554
+ // For To_Ruby_T however we do need to use reference type because this is what
2555
+ // will be passed by an interator to To_Ruby#convert
2556
+ using Reference_T = typename T::reference;
2557
+ using Parameter_T = std::conditional_t<std::is_pointer_v<Value_T>, Value_T, Value_T&>;
2558
+ using To_Ruby_T = detail::remove_cv_recursive_t<typename T::reference>;
2081
2559
 
2082
2560
  public:
2083
2561
  VectorHelper(Data_Type<T> klass) : klass_(klass)
@@ -2141,7 +2619,11 @@ namespace Rice
2141
2619
 
2142
2620
  void define_constructable_methods()
2143
2621
  {
2144
- if constexpr (std::is_default_constructible_v<Value_T>)
2622
+ if constexpr (std::is_default_constructible_v<Value_T> && std::is_same_v<Value_T, bool>)
2623
+ {
2624
+ klass_.define_method("resize", static_cast<void (T::*)(const size_t, bool)>(&T::resize));
2625
+ }
2626
+ else if constexpr (std::is_default_constructible_v<Value_T>)
2145
2627
  {
2146
2628
  klass_.define_method("resize", static_cast<void (T::*)(const size_t)>(&T::resize));
2147
2629
  }
@@ -2172,41 +2654,71 @@ namespace Rice
2172
2654
  {
2173
2655
  // Access methods
2174
2656
  klass_.define_method("first", [](const T& vector) -> std::optional<Value_T>
2657
+ {
2658
+ if (vector.size() > 0)
2659
+ {
2660
+ return vector.front();
2661
+ }
2662
+ else
2663
+ {
2664
+ return std::nullopt;
2665
+ }
2666
+ })
2667
+ .define_method("last", [](const T& vector) -> std::optional<Value_T>
2175
2668
  {
2176
2669
  if (vector.size() > 0)
2177
2670
  {
2178
- return vector.front();
2671
+ return vector.back();
2179
2672
  }
2180
2673
  else
2181
2674
  {
2182
2675
  return std::nullopt;
2183
2676
  }
2184
2677
  })
2185
- .define_method("last", [](const T& vector) -> std::optional<Value_T>
2678
+ .define_method("[]", [this](const T& vector, Difference_T index) -> std::optional<Value_T>
2679
+ {
2680
+ index = normalizeIndex(vector.size(), index);
2681
+ if (index < 0 || index >= (Difference_T)vector.size())
2186
2682
  {
2187
- if (vector.size() > 0)
2188
- {
2189
- return vector.back();
2190
- }
2191
- else
2683
+ return std::nullopt;
2684
+ }
2685
+ else
2686
+ {
2687
+ return vector[index];
2688
+ }
2689
+ })
2690
+ .define_method("[]", [this](const T& vector, Difference_T start, Difference_T length) -> VALUE
2691
+ {
2692
+ start = normalizeIndex(vector.size(), start);
2693
+ if (start < 0 || start >= (Difference_T)vector.size())
2694
+ {
2695
+ return rb_ary_new();
2696
+ }
2697
+ else
2698
+ {
2699
+ auto begin = vector.begin() + start;
2700
+
2701
+ // Ruby does not throw an exception when the length is too long
2702
+ if (start + length > vector.size())
2192
2703
  {
2193
- return std::nullopt;
2704
+ length = vector.size() - start;
2194
2705
  }
2195
- })
2196
- .define_method("[]", [this](const T& vector, Difference_T index) -> std::optional<Value_T>
2706
+
2707
+ auto finish = vector.begin() + start + length;
2708
+ T slice(begin, finish);
2709
+
2710
+ VALUE result = rb_ary_new();
2711
+ std::for_each(slice.begin(), slice.end(), [&result](const Reference_T element)
2197
2712
  {
2198
- index = normalizeIndex(vector.size(), index);
2199
- if (index < 0 || index >= (Difference_T)vector.size())
2200
- {
2201
- return std::nullopt;
2202
- }
2203
- else
2204
- {
2205
- return vector[index];
2206
- }
2713
+ VALUE value = detail::To_Ruby<Parameter_T>().convert(element);
2714
+ rb_ary_push(result, value);
2207
2715
  });
2208
2716
 
2209
- rb_define_alias(klass_, "at", "[]");
2717
+ return result;
2718
+ }
2719
+ }, Return().setValue());
2720
+
2721
+ rb_define_alias(klass_, "at", "[]");
2210
2722
  }
2211
2723
 
2212
2724
  // Methods that require Value_T to support operator==
@@ -2214,7 +2726,7 @@ namespace Rice
2214
2726
  {
2215
2727
  if constexpr (detail::is_comparable_v<Value_T>)
2216
2728
  {
2217
- klass_.define_method("delete", [](T& vector, Value_T& element) -> std::optional<Value_T>
2729
+ klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
2218
2730
  {
2219
2731
  auto iter = std::find(vector.begin(), vector.end(), element);
2220
2732
  if (iter == vector.end())
@@ -2228,11 +2740,11 @@ namespace Rice
2228
2740
  return result;
2229
2741
  }
2230
2742
  })
2231
- .define_method("include?", [](T& vector, Value_T& element)
2743
+ .define_method("include?", [](T& vector, Parameter_T element)
2232
2744
  {
2233
2745
  return std::find(vector.begin(), vector.end(), element) != vector.end();
2234
2746
  })
2235
- .define_method("index", [](T& vector, Value_T& element) -> std::optional<Difference_T>
2747
+ .define_method("index", [](T& vector, Parameter_T element) -> std::optional<Difference_T>
2236
2748
  {
2237
2749
  auto iter = std::find(vector.begin(), vector.end(), element);
2238
2750
  if (iter == vector.end())
@@ -2247,15 +2759,15 @@ namespace Rice
2247
2759
  }
2248
2760
  else
2249
2761
  {
2250
- klass_.define_method("delete", [](T& vector, Value_T& element) -> std::optional<Value_T>
2762
+ klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
2251
2763
  {
2252
2764
  return std::nullopt;
2253
2765
  })
2254
- .define_method("include?", [](const T& vector, Value_T& element)
2766
+ .define_method("include?", [](const T& vector, Parameter_T element)
2255
2767
  {
2256
2768
  return false;
2257
2769
  })
2258
- .define_method("index", [](const T& vector, Value_T& element) -> std::optional<Difference_T>
2770
+ .define_method("index", [](const T& vector, Parameter_T element) -> std::optional<Difference_T>
2259
2771
  {
2260
2772
  return std::nullopt;
2261
2773
  });
@@ -2272,7 +2784,7 @@ namespace Rice
2272
2784
  vector.erase(iter);
2273
2785
  return result;
2274
2786
  })
2275
- .define_method("insert", [this](T& vector, Difference_T index, Value_T& element) -> T&
2787
+ .define_method("insert", [this](T& vector, Difference_T index, Parameter_T element) -> T&
2276
2788
  {
2277
2789
  index = normalizeIndex(vector.size(), index, true);
2278
2790
  auto iter = vector.begin() + index;
@@ -2292,13 +2804,13 @@ namespace Rice
2292
2804
  return std::nullopt;
2293
2805
  }
2294
2806
  })
2295
- .define_method("push", [](T& vector, Value_T& element) -> T&
2807
+ .define_method("push", [](T& vector, Parameter_T element) -> T&
2296
2808
  {
2297
2809
  vector.push_back(element);
2298
2810
  return vector;
2299
2811
  })
2300
2812
  .define_method("shrink_to_fit", &T::shrink_to_fit)
2301
- .define_method("[]=", [this](T& vector, Difference_T index, Value_T& element) -> Value_T&
2813
+ .define_method("[]=", [this](T& vector, Difference_T index, Parameter_T element) -> Parameter_T
2302
2814
  {
2303
2815
  index = normalizeIndex(vector.size(), index, true);
2304
2816
  vector[index] = element;
@@ -2321,9 +2833,9 @@ namespace Rice
2321
2833
  klass_.define_method("to_a", [](T& vector)
2322
2834
  {
2323
2835
  VALUE result = rb_ary_new();
2324
- std::for_each(vector.begin(), vector.end(), [&result](const Value_T& element)
2836
+ std::for_each(vector.begin(), vector.end(), [&result](const Reference_T element)
2325
2837
  {
2326
- VALUE value = detail::To_Ruby<Value_T&>().convert(element);
2838
+ VALUE value = detail::To_Ruby<Parameter_T>().convert(element);
2327
2839
  rb_ary_push(result, value);
2328
2840
  });
2329
2841
 
@@ -2374,18 +2886,19 @@ namespace Rice
2374
2886
  } // namespace
2375
2887
 
2376
2888
  template<typename T>
2377
- Data_Type<T> define_vector_under(Object module, std::string name)
2889
+ Data_Type<T> define_vector_under(Object parent, std::string name)
2378
2890
  {
2379
2891
  if (detail::Registries::instance.types.isDefined<T>())
2380
2892
  {
2381
2893
  // If the vector has been previously seen it will be registered but may
2382
2894
  // not be associated with the constant Module::<name>
2383
- module.const_set_maybe(name, Data_Type<T>().klass());
2895
+ parent.const_set_maybe(name, Data_Type<T>().klass());
2384
2896
 
2385
2897
  return Data_Type<T>();
2386
2898
  }
2387
2899
 
2388
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
2900
+ Identifier id(name);
2901
+ Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, id, rb_cObject);
2389
2902
  stl::VectorHelper helper(result);
2390
2903
  return result;
2391
2904
  }
@@ -2410,10 +2923,11 @@ namespace Rice
2410
2923
  template<typename T>
2411
2924
  Data_Type<T> define_vector_auto()
2412
2925
  {
2413
- std::string klassName = detail::makeClassName(typeid(T));
2926
+ std::string name = detail::typeName(typeid(T));
2927
+ std::string klassName = detail::makeClassName(name);
2414
2928
  Module rb_mRice = define_module("Rice");
2415
- Module rb_mVector = define_module_under(rb_mRice, "Std");
2416
- return define_vector_under<T>(rb_mVector, klassName);
2929
+ Module rb_mStd = define_module_under(rb_mRice, "Std");
2930
+ return define_vector_under<T>(rb_mStd, klassName);
2417
2931
  }
2418
2932
 
2419
2933
  namespace detail
@@ -2434,20 +2948,6 @@ namespace Rice
2434
2948
  }
2435
2949
  };
2436
2950
 
2437
- template<typename T>
2438
- std::vector<T> vectorFromArray(VALUE value)
2439
- {
2440
- long length = protect(rb_array_len, value);
2441
- std::vector<T> result(length);
2442
-
2443
- for (long i = 0; i < length; i++)
2444
- {
2445
- VALUE element = protect(rb_ary_entry, value, i);
2446
- result[i] = From_Ruby<T>().convert(element);
2447
- }
2448
-
2449
- return result;
2450
- }
2451
2951
 
2452
2952
  template<typename T>
2453
2953
  class From_Ruby<std::vector<T>>
@@ -2459,24 +2959,39 @@ namespace Rice
2459
2959
  {
2460
2960
  }
2461
2961
 
2962
+ Convertible is_convertible(VALUE value)
2963
+ {
2964
+ switch (rb_type(value))
2965
+ {
2966
+ case RUBY_T_DATA:
2967
+ return Convertible::Exact;
2968
+ break;
2969
+ case RUBY_T_ARRAY:
2970
+ return Convertible::Cast;
2971
+ break;
2972
+ default:
2973
+ return Convertible::None;
2974
+ }
2975
+ }
2976
+
2462
2977
  std::vector<T> convert(VALUE value)
2463
2978
  {
2464
2979
  switch (rb_type(value))
2465
2980
  {
2466
- case T_DATA:
2981
+ case RUBY_T_DATA:
2467
2982
  {
2468
2983
  // This is a wrapped vector (hopefully!)
2469
2984
  return *Data_Object<std::vector<T>>::from_ruby(value);
2470
2985
  }
2471
- case T_ARRAY:
2986
+ case RUBY_T_ARRAY:
2472
2987
  {
2473
2988
  // If this an Ruby array and the vector type is copyable
2474
2989
  if constexpr (std::is_default_constructible_v<T>)
2475
2990
  {
2476
- return vectorFromArray<T>(value);
2991
+ return Array(value).to_vector<T>();
2477
2992
  }
2478
2993
  }
2479
- case T_NIL:
2994
+ case RUBY_T_NIL:
2480
2995
  {
2481
2996
  if (this->arg_ && this->arg_->hasDefaultValue())
2482
2997
  {
@@ -2491,11 +3006,6 @@ namespace Rice
2491
3006
  }
2492
3007
  }
2493
3008
 
2494
- bool is_convertible(VALUE value)
2495
- {
2496
- return rb_type(value) == RUBY_T_ARRAY;
2497
- }
2498
-
2499
3009
  private:
2500
3010
  Arg* arg_ = nullptr;
2501
3011
  };
@@ -2510,25 +3020,40 @@ namespace Rice
2510
3020
  {
2511
3021
  }
2512
3022
 
3023
+ Convertible is_convertible(VALUE value)
3024
+ {
3025
+ switch (rb_type(value))
3026
+ {
3027
+ case RUBY_T_DATA:
3028
+ return Convertible::Exact;
3029
+ break;
3030
+ case RUBY_T_ARRAY:
3031
+ return Convertible::Cast;
3032
+ break;
3033
+ default:
3034
+ return Convertible::None;
3035
+ }
3036
+ }
3037
+
2513
3038
  std::vector<T>& convert(VALUE value)
2514
3039
  {
2515
3040
  switch (rb_type(value))
2516
3041
  {
2517
- case T_DATA:
3042
+ case RUBY_T_DATA:
2518
3043
  {
2519
3044
  // This is a wrapped vector (hopefully!)
2520
3045
  return *Data_Object<std::vector<T>>::from_ruby(value);
2521
3046
  }
2522
- case T_ARRAY:
3047
+ case RUBY_T_ARRAY:
2523
3048
  {
2524
3049
  // If this an Ruby array and the vector type is copyable
2525
3050
  if constexpr (std::is_default_constructible_v<T>)
2526
3051
  {
2527
- this->converted_ = vectorFromArray<T>(value);
3052
+ this->converted_ = Array(value).to_vector<T>();
2528
3053
  return this->converted_;
2529
3054
  }
2530
3055
  }
2531
- case T_NIL:
3056
+ case RUBY_T_NIL:
2532
3057
  {
2533
3058
  if (this->arg_ && this->arg_->hasDefaultValue())
2534
3059
  {
@@ -2543,11 +3068,6 @@ namespace Rice
2543
3068
  }
2544
3069
  }
2545
3070
 
2546
- bool is_convertible(VALUE value)
2547
- {
2548
- return rb_type(value) == RUBY_T_ARRAY;
2549
- }
2550
-
2551
3071
  private:
2552
3072
  Arg* arg_ = nullptr;
2553
3073
  std::vector<T> converted_;
@@ -2557,21 +3077,39 @@ namespace Rice
2557
3077
  class From_Ruby<std::vector<T>*>
2558
3078
  {
2559
3079
  public:
3080
+ Convertible is_convertible(VALUE value)
3081
+ {
3082
+ switch (rb_type(value))
3083
+ {
3084
+ case RUBY_T_DATA:
3085
+ return Convertible::Exact;
3086
+ break;
3087
+ case RUBY_T_NIL:
3088
+ return Convertible::Exact;
3089
+ break;
3090
+ case RUBY_T_ARRAY:
3091
+ return Convertible::Cast;
3092
+ break;
3093
+ default:
3094
+ return Convertible::None;
3095
+ }
3096
+ }
3097
+
2560
3098
  std::vector<T>* convert(VALUE value)
2561
3099
  {
2562
3100
  switch (rb_type(value))
2563
3101
  {
2564
- case T_DATA:
3102
+ case RUBY_T_DATA:
2565
3103
  {
2566
3104
  // This is a wrapped vector (hopefully!)
2567
3105
  return Data_Object<std::vector<T>>::from_ruby(value);
2568
3106
  }
2569
- case T_ARRAY:
3107
+ case RUBY_T_ARRAY:
2570
3108
  {
2571
- // If this an Ruby array and the vector type is copyable
3109
+ // If this a Ruby array and the vector type is copyable
2572
3110
  if constexpr (std::is_default_constructible_v<T>)
2573
3111
  {
2574
- this->converted_ = vectorFromArray<T>(value);
3112
+ this->converted_ = Array(value).to_vector<T>();
2575
3113
  return &this->converted_;
2576
3114
  }
2577
3115
  }
@@ -2583,15 +3121,24 @@ namespace Rice
2583
3121
  }
2584
3122
  }
2585
3123
 
2586
- bool is_convertible(VALUE value)
2587
- {
2588
- return rb_type(value) == RUBY_T_ARRAY;
2589
- }
2590
-
2591
3124
  private:
2592
3125
  std::vector<T> converted_;
2593
3126
  };
2594
3127
  }
3128
+
3129
+ // Special handling for std::vector<bool>
3130
+ namespace detail
3131
+ {
3132
+ template<>
3133
+ class To_Ruby<std::vector<bool>::reference>
3134
+ {
3135
+ public:
3136
+ VALUE convert(const std::vector<bool>::reference& value)
3137
+ {
3138
+ return value ? Qtrue : Qfalse;
3139
+ }
3140
+ };
3141
+ }
2595
3142
  }
2596
3143
 
2597
3144