rice 4.11.4 → 4.12.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/CMakePresets.json +3 -3
  4. data/bin/rice-doc.rb +2 -0
  5. data/include/rice/rice.hpp +162 -113
  6. data/include/rice/stl.hpp +229 -69
  7. data/lib/mkmf-rice.rb +2 -2
  8. data/lib/rice/version.rb +1 -1
  9. data/rice/Constructor.ipp +3 -3
  10. data/rice/Data_Object.ipp +0 -42
  11. data/rice/JumpException.ipp +1 -0
  12. data/rice/Reference.hpp +2 -2
  13. data/rice/Reference.ipp +1 -1
  14. data/rice/cpp_api/Encoding.ipp +0 -48
  15. data/rice/cpp_api/Hash.ipp +19 -0
  16. data/rice/cpp_api/Object.hpp +2 -2
  17. data/rice/cpp_api/Object.ipp +3 -3
  18. data/rice/cpp_api/String.ipp +19 -0
  19. data/rice/detail/Anchor.hpp +1 -1
  20. data/rice/detail/Anchor.ipp +16 -10
  21. data/rice/detail/Parameter.ipp +11 -0
  22. data/rice/detail/Proc.ipp +19 -0
  23. data/rice/detail/Wrapper.ipp +3 -3
  24. data/rice/detail/from_ruby.hpp +1 -0
  25. data/rice/detail/to_ruby.ipp +58 -1
  26. data/rice/stl/function.ipp +142 -2
  27. data/rice/stl/map.ipp +2 -10
  28. data/rice/stl/multimap.ipp +2 -10
  29. data/rice/stl/optional.ipp +18 -0
  30. data/rice/stl/reference_wrapper.ipp +18 -0
  31. data/rice/stl/set.ipp +24 -25
  32. data/rice/stl/unique_ptr.ipp +3 -0
  33. data/rice/stl/unordered_map.ipp +2 -10
  34. data/rice/stl/vector.ipp +18 -15
  35. data/rice/traits/rice_traits.hpp +3 -0
  36. data/test/test_Attribute.cpp +6 -6
  37. data/test/test_Constructor.cpp +140 -1
  38. data/test/test_File.cpp +2 -3
  39. data/test/test_From_Ruby.cpp +3 -3
  40. data/test/test_Hash.cpp +8 -0
  41. data/test/test_Object.cpp +76 -0
  42. data/test/test_Overloads.cpp +74 -1
  43. data/test/test_Proc.cpp +11 -1
  44. data/test/test_Reference.cpp +20 -1
  45. data/test/test_Stl_Exception.cpp +2 -5
  46. data/test/test_Stl_Function.cpp +72 -7
  47. data/test/test_Stl_Map.cpp +10 -1
  48. data/test/test_Stl_Multimap.cpp +11 -2
  49. data/test/test_Stl_Optional.cpp +9 -0
  50. data/test/test_Stl_Reference_Wrapper.cpp +11 -0
  51. data/test/test_Stl_Set.cpp +12 -0
  52. data/test/test_Stl_Unordered_Map.cpp +10 -1
  53. data/test/test_Stl_Vector.cpp +130 -11
  54. data/test/test_String.cpp +7 -0
  55. data/test/test_To_Ruby.cpp +24 -1
  56. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '07196451c8152b8110d5a2aa17d9d1073c846139a8e08d3fe71217095c3386d6'
4
- data.tar.gz: d0a84860a008461a29396679953abe8377f24b92ee9085ed84820dd946065390
3
+ metadata.gz: ee35bcabc987b70a0614689a9fe28f60ceeb0d63ad492ebc1d1914acebfb63d8
4
+ data.tar.gz: 40451a4f9531b935f70aefb2fc2e7ecb5bd75a546035fb7c3eed3af8f47f2911
5
5
  SHA512:
6
- metadata.gz: 1d560e79db1a4645bd6d1084e0df00a44d79795b14d963292e731912c1bcabf29578846ff18a2bf8f8cdb171419c1b13be66b358582328ff5e4d18c61aee8731
7
- data.tar.gz: bfa6478914622bf559db804f3ccb10fd51c39973ff7032a07d2ced37c7d5fbbacd3b9417ed4399499f97f209ec115daecabd7e9ab75a145dfaba9c6c2d94478e
6
+ metadata.gz: 8cc76f3c9395f94bf5830cc60ad5c327ab9941b0f532ac095553f774481d04cf72ddc2abf7db167438063c7e3e91455a2cc660fbd37d2e917276b30bef6a3203
7
+ data.tar.gz: 4ffb5214a1bf6dfeda4222a6c6c7006313820eac1cf17fdf36994a70099506ec591be20cd77db52f8034ed47cb65297d0b80c9dd3ff08aed70ade273f1cc492e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.12.0 (2026-04-09)
4
+
5
+ ### Bug Fixes
6
+
7
+ * Fix undefined behavior when deleting polymorphic classes with non-virtual destructors
8
+ * Fix overload resolution to prefer `T&` or `const T&` over `T&&` after perfect forwarding changes
9
+ * Fix `Reference<T>` constructor overload resolution so forwarded arguments bind to the typed overload instead of falling through to `Reference(VALUE)`
10
+ * Reject incomplete `std::unique_ptr` bindings at compile time
11
+
12
+ ### Enhancements
13
+
14
+ * Forward `Object::call` arguments without copying
15
+ * Forward Rice constructor rvalue arguments
16
+ * Forward `std::function` callback arguments
17
+ * Add support for `To_Ruby<T&>` for types missing it
18
+ * Allow raw Ruby procs and lambdas to convert directly to `std::function` parameters while keeping the callable alive with `Pin`
19
+ * Only define equality-based STL container methods when the contained type supports C++ equality comparison
20
+
21
+ ## 4.11.5 (2026-03-24)
22
+
23
+ ### Bug Fixes
24
+
25
+ * Fix Valgrind invalid reads caused by stale GC root addresses (#399)
26
+ * Fix `rb_gc_register_address()` triggering GC before Anchor stores heap object — use `RB_GC_GUARD` to keep VALUE alive
27
+ * Fix gem packaging warning
28
+
3
29
  ## 4.11.4 (2026-03-13)
4
30
 
5
31
  ### Bug Fixes
data/CMakePresets.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "installDir": "${sourceDir}/install/${presetName}",
10
10
  "cacheVariables": {
11
11
  "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
12
- "CMAKE_CXX_FLAGS": "-Wall -ftemplate-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden"
12
+ "CMAKE_CXX_FLAGS": "-Wall -Wno-array-bounds -ftemplate-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden"
13
13
  }
14
14
  },
15
15
  {
@@ -81,7 +81,7 @@
81
81
  "cacheVariables": {
82
82
  "CMAKE_BUILD_TYPE": "Debug",
83
83
  "CMAKE_CXX_COMPILER": "g++.exe",
84
- "CMAKE_CXX_FLAGS": "-Wall -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -fvisibility=hidden -fvisibility-inlines-hidden",
84
+ "CMAKE_CXX_FLAGS": "-Wall -Wno-array-bounds -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -fvisibility=hidden -fvisibility-inlines-hidden",
85
85
  "CMAKE_CXX_FLAGS_DEBUG": "-g3 -Og -fno-omit-frame-pointer -fno-inline -gsplit-dwarf"
86
86
  },
87
87
  "condition": {
@@ -97,7 +97,7 @@
97
97
  "cacheVariables": {
98
98
  "CMAKE_BUILD_TYPE": "Release",
99
99
  "CMAKE_CXX_COMPILER": "g++.exe",
100
- "CMAKE_CXX_FLAGS": "-Wall -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -fvisibility=hidden -fvisibility-inlines-hidden",
100
+ "CMAKE_CXX_FLAGS": "-Wall -Wno-array-bounds -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -fvisibility=hidden -fvisibility-inlines-hidden",
101
101
  "CMAKE_CXX_FLAGS_RELEASE": "-O3 -DNDEBUG",
102
102
  "CMAKE_SHARED_LINKER_FLAGS_RELEASE": "-Wl,--exclude-all-symbols"
103
103
  },
data/bin/rice-doc.rb CHANGED
@@ -1,3 +1,5 @@
1
+ #! /usr/bin/env ruby
2
+
1
3
  require 'libxml-ruby'
2
4
 
3
5
  # Require rice
@@ -189,6 +189,9 @@ namespace Rice
189
189
  constexpr bool is_ostreamable_v = is_ostreamable<T>::value;
190
190
 
191
191
  // Is the type comparable?
192
+ // Libraries with unconstrained operator== declarations may specialize this
193
+ // trait to false when equality is not actually usable by Rice's STL
194
+ // wrappers.
192
195
  template<typename T, typename SFINAE = void>
193
196
  struct is_comparable : std::false_type {};
194
197
 
@@ -859,6 +862,7 @@ namespace Rice::detail
859
862
  // ========= Anchor.hpp =========
860
863
 
861
864
  #include <ruby.h>
865
+ #include <ruby/vm.h>
862
866
 
863
867
  namespace Rice
864
868
  {
@@ -893,7 +897,6 @@ namespace Rice
893
897
  VALUE get() const;
894
898
 
895
899
  private:
896
- static void disable(VALUE);
897
900
  static void registerExitHandler();
898
901
 
899
902
  inline static bool enabled_ = true;
@@ -1094,6 +1097,7 @@ namespace Rice
1094
1097
  break;
1095
1098
  case RUBY_TAG_THROW:
1096
1099
  this->message_ = "Unexpected throw";
1100
+ break;
1097
1101
  case RUBY_TAG_RAISE:
1098
1102
  this->message_ = "Ruby exception was thrown";
1099
1103
  break;
@@ -1590,6 +1594,7 @@ namespace Rice::detail
1590
1594
  static constexpr double SignedToUnsigned = 0.5;// Penalty for signed to unsigned (can't represent negatives)
1591
1595
  static constexpr double FloatToInt = 0.5; // Domain change penalty when converting float to int (lossy)
1592
1596
  static constexpr double ConstMismatch = 0.99; // Penalty for const mismatch
1597
+ static constexpr double RValueMismatch = 0.98; // Prefer borrowing wrapped objects over moving from them
1593
1598
  };
1594
1599
  }
1595
1600
 
@@ -1667,23 +1672,28 @@ namespace Rice
1667
1672
  {
1668
1673
  namespace detail
1669
1674
  {
1670
- inline Anchor::Anchor(VALUE value) : value_(value)
1675
+ inline Anchor::Anchor(VALUE value)
1671
1676
  {
1677
+ // rb_gc_register_address() can trigger GC, so we must register the
1678
+ // empty this->value_ slot before storing a heap VALUE in it.
1679
+ // RB_GC_GUARD(value) keeps the ctor argument alive through the end of
1680
+ // this method until the registered slot has been updated.
1672
1681
  if (!RB_SPECIAL_CONST_P(value))
1673
1682
  {
1674
1683
  Anchor::registerExitHandler();
1675
1684
  detail::protect(rb_gc_register_address, &this->value_);
1676
1685
  this->registered_ = true;
1677
1686
  }
1687
+ this->value_ = value;
1688
+ RB_GC_GUARD(value);
1678
1689
  }
1679
1690
 
1680
1691
  inline Anchor::~Anchor()
1681
1692
  {
1682
1693
  if (Anchor::enabled_ && this->registered_)
1683
1694
  {
1684
- detail::protect(rb_gc_unregister_address, &this->value_);
1695
+ rb_gc_unregister_address(&this->value_);
1685
1696
  }
1686
- // Ruby auto detects VALUEs in the stack, so make sure up in case this object is on the stack
1687
1697
  this->registered_ = false;
1688
1698
  this->value_ = Qnil;
1689
1699
  }
@@ -1693,17 +1703,18 @@ namespace Rice
1693
1703
  return this->value_;
1694
1704
  }
1695
1705
 
1696
- // This will be called by ruby at exit - we want to disable further unregistering
1697
- inline void Anchor::disable(VALUE)
1698
- {
1699
- Anchor::enabled_ = false;
1700
- }
1701
-
1702
1706
  inline void Anchor::registerExitHandler()
1703
1707
  {
1704
1708
  if (!Anchor::exitHandlerRegistered_)
1705
1709
  {
1706
- detail::protect(rb_set_end_proc, &Anchor::disable, Qnil);
1710
+ // Use ruby_vm_at_exit which fires AFTER the VM is destroyed,
1711
+ // not rb_set_end_proc which fires BEFORE. rb_set_end_proc
1712
+ // runs as an end_proc in LIFO order alongside at_exit blocks,
1713
+ // so its timing depends on require order — if the extension
1714
+ // loads after minitest/autorun, the disable callback runs
1715
+ // before tests execute, causing Anchor destructors to skip
1716
+ // rb_gc_unregister_address and leave dangling root pointers.
1717
+ ruby_vm_at_exit([](ruby_vm_t*) { Anchor::enabled_ = false; });
1707
1718
  Anchor::exitHandlerRegistered_ = true;
1708
1719
  }
1709
1720
  }
@@ -2026,7 +2037,7 @@ namespace Rice
2026
2037
  * \endcode
2027
2038
  */
2028
2039
  template<typename ...Parameter_Ts>
2029
- Object call(Identifier id, Parameter_Ts... args) const;
2040
+ Object call(Identifier id, Parameter_Ts&&... args) const;
2030
2041
 
2031
2042
  //! Call the Ruby method specified by 'id' on object 'obj'.
2032
2043
  /*! Pass in arguments (arg1, arg2, ...). The arguments will be converted to
@@ -2049,7 +2060,7 @@ namespace Rice
2049
2060
  * \endcode
2050
2061
  */
2051
2062
  template<typename ...Parameter_Ts>
2052
- Object call_kw(Identifier id, Parameter_Ts... args) const;
2063
+ Object call_kw(Identifier id, Parameter_Ts&&... args) const;
2053
2064
 
2054
2065
  //! Vectorized call.
2055
2066
  /*! Calls the method identified by id with the list of arguments
@@ -4272,7 +4283,7 @@ namespace Rice
4272
4283
 
4273
4284
  public:
4274
4285
  Reference();
4275
- Reference(T& data);
4286
+ Reference(const T& data);
4276
4287
  Reference(VALUE value);
4277
4288
  T& get();
4278
4289
 
@@ -4281,7 +4292,7 @@ namespace Rice
4281
4292
  };
4282
4293
 
4283
4294
  // Specialization needed when VALUE type matches T, causing constructor ambiguity
4284
- // between Reference(T&) and Reference(VALUE). VALUE is unsigned long when
4295
+ // between Reference(const T&) and Reference(VALUE). VALUE is unsigned long when
4285
4296
  // SIZEOF_LONG == SIZEOF_VOIDP (Linux/macOS) and unsigned long long when
4286
4297
  // SIZEOF_LONG_LONG == SIZEOF_VOIDP (Windows x64).
4287
4298
  #if SIZEOF_LONG == SIZEOF_VOIDP
@@ -4453,6 +4464,12 @@ namespace Rice::detail
4453
4464
  {
4454
4465
  result = Convertible::None;
4455
4466
  }
4467
+ // Existing wrapped Ruby objects should prefer borrowing overloads to
4468
+ // rvalue-reference overloads so they are not silently moved-from.
4469
+ else if constexpr (std::is_rvalue_reference_v<T>)
4470
+ {
4471
+ result = Convertible::RValueMismatch;
4472
+ }
4456
4473
  // It is ok to send a non-const value to a const parameter but
4457
4474
  // prefer non-const to non-const by slightly decreasing the score
4458
4475
  else if (!isConst && is_const_any_v<T>)
@@ -4489,6 +4506,11 @@ namespace Rice::detail
4489
4506
  {
4490
4507
  return this->fromRuby_.convert(valueOpt.value());
4491
4508
  }
4509
+ else if constexpr (std::is_rvalue_reference_v<T>)
4510
+ {
4511
+ // Rvalue-reference parameters cannot safely use stored default values.
4512
+ // Materializing them from std::any would require moving from shared state.
4513
+ }
4492
4514
  // Remember std::is_copy_constructible_v<std::vector<std::unique_ptr<T>>>> returns true. Sigh.
4493
4515
  // So special case vector handling
4494
4516
  else if constexpr (detail::is_std_vector_v<detail::intrinsic_type<T>>)
@@ -6453,6 +6475,25 @@ namespace Rice
6453
6475
  Arg* arg_ = nullptr;
6454
6476
  };
6455
6477
 
6478
+ template<>
6479
+ class To_Ruby<char*&>
6480
+ {
6481
+ public:
6482
+ To_Ruby() = default;
6483
+
6484
+ explicit To_Ruby(Arg* arg) : arg_(arg)
6485
+ {
6486
+ }
6487
+
6488
+ VALUE convert(const char* data)
6489
+ {
6490
+ return To_Ruby<char*>(arg_).convert(data);
6491
+ }
6492
+
6493
+ private:
6494
+ Arg* arg_ = nullptr;
6495
+ };
6496
+
6456
6497
  template<int N>
6457
6498
  class To_Ruby<char[N]>
6458
6499
  {
@@ -6485,6 +6526,25 @@ namespace Rice
6485
6526
  Arg* arg_ = nullptr;
6486
6527
  };
6487
6528
 
6529
+ template<int N>
6530
+ class To_Ruby<char(&)[N]>
6531
+ {
6532
+ public:
6533
+ To_Ruby() = default;
6534
+
6535
+ explicit To_Ruby(Arg* arg) : arg_(arg)
6536
+ {
6537
+ }
6538
+
6539
+ VALUE convert(const char (&buffer)[N])
6540
+ {
6541
+ return To_Ruby<char[N]>(arg_).convert(buffer);
6542
+ }
6543
+
6544
+ private:
6545
+ Arg* arg_ = nullptr;
6546
+ };
6547
+
6488
6548
  // =========== unsigned char ============
6489
6549
  template<>
6490
6550
  class To_Ruby<unsigned char>
@@ -7206,6 +7266,25 @@ namespace Rice
7206
7266
  Arg* arg_ = nullptr;
7207
7267
  };
7208
7268
 
7269
+ template<>
7270
+ class To_Ruby<std::nullptr_t&>
7271
+ {
7272
+ public:
7273
+ To_Ruby() = default;
7274
+
7275
+ explicit To_Ruby(Arg* arg) : arg_(arg)
7276
+ {
7277
+ }
7278
+
7279
+ VALUE convert(std::nullptr_t const)
7280
+ {
7281
+ return Qnil;
7282
+ }
7283
+
7284
+ private:
7285
+ Arg* arg_ = nullptr;
7286
+ };
7287
+
7209
7288
  // =========== void ============
7210
7289
  template<>
7211
7290
  class To_Ruby<void>
@@ -7264,6 +7343,7 @@ namespace Rice
7264
7343
  };
7265
7344
  }
7266
7345
  }
7346
+
7267
7347
  // ========= from_ruby.ipp =========
7268
7348
  #include <limits>
7269
7349
  #include <optional>
@@ -9044,7 +9124,7 @@ namespace Rice
9044
9124
  }
9045
9125
 
9046
9126
  template<typename T>
9047
- inline Reference<T>::Reference(T& data) : data_(data)
9127
+ inline Reference<T>::Reference(const T& data) : data_(data)
9048
9128
  {
9049
9129
  }
9050
9130
 
@@ -10282,10 +10362,10 @@ namespace Rice::detail
10282
10362
 
10283
10363
  if constexpr (is_complete_v<T>)
10284
10364
  {
10285
- // is_abstract_v requires a complete type, so nest inside is_complete_v.
10286
- // Deleting an abstract class through a non-virtual destructor is UB,
10365
+ // is_polymorphic_v requires a complete type, so nest inside is_complete_v.
10366
+ // Deleting a polymorphic class through a non-virtual destructor is UB,
10287
10367
  // but it is safe if the destructor is virtual.
10288
- if constexpr (std::is_destructible_v<T> && (!std::is_abstract_v<T> || std::has_virtual_destructor_v<T>))
10368
+ if constexpr (std::is_destructible_v<T> && (!std::is_polymorphic_v<T> || std::has_virtual_destructor_v<T>))
10289
10369
  {
10290
10370
  if (this->isOwner_)
10291
10371
  {
@@ -12657,6 +12737,25 @@ namespace Rice::detail
12657
12737
  }
12658
12738
  };
12659
12739
 
12740
+ // Wraps a C++ function as a Ruby proc
12741
+ template<typename Return_T, typename ...Parameter_Ts>
12742
+ class To_Ruby<Return_T(*&)(Parameter_Ts...)>
12743
+ {
12744
+ public:
12745
+ using Proc_T = Return_T(*&)(Parameter_Ts...);
12746
+
12747
+ To_Ruby() = default;
12748
+
12749
+ explicit To_Ruby(Arg*)
12750
+ {}
12751
+
12752
+ VALUE convert(Proc_T proc)
12753
+ {
12754
+ // Wrap the C+++ function pointer as a Ruby Proc
12755
+ return NativeProc<Proc_T>::createRubyProc(std::forward<Proc_T>(proc));
12756
+ }
12757
+ };
12758
+
12660
12759
  // Makes a Ruby proc callable as C callback
12661
12760
  template<typename Return_T, typename ...Parameter_Ts>
12662
12761
  class From_Ruby<Return_T(*)(Parameter_Ts...)>
@@ -12709,53 +12808,6 @@ namespace Rice
12709
12808
  }
12710
12809
  }
12711
12810
 
12712
- /*namespace Rice::detail
12713
- {
12714
- template<>
12715
- struct Type<Encoding>
12716
- {
12717
- static bool verify()
12718
- {
12719
- return true;
12720
- }
12721
- };
12722
-
12723
- template<>
12724
- class To_Ruby<Encoding>
12725
- {
12726
- public:
12727
- VALUE convert(const Encoding& encoding)
12728
- {
12729
- // return x.value();
12730
- }
12731
- };
12732
-
12733
- template<>
12734
- class From_Ruby<Encoding>
12735
- {
12736
- public:
12737
- Convertible is_convertible(VALUE value)
12738
- {
12739
- switch (rb_type(value))
12740
- {
12741
- case RUBY_T_SYMBOL:
12742
- return Convertible::Exact;
12743
- break;
12744
- case RUBY_T_STRING:
12745
- return Convertible::Cast;
12746
- break;
12747
- default:
12748
- return Convertible::None;
12749
- }
12750
- }
12751
-
12752
- Encoding convert(VALUE value)
12753
- {
12754
- // return Symbol(value);
12755
- }
12756
- };
12757
- }
12758
- */
12759
12811
  // ========= Object.ipp =========
12760
12812
  namespace Rice
12761
12813
  {
@@ -12801,7 +12853,7 @@ namespace Rice
12801
12853
  }
12802
12854
 
12803
12855
  template<typename ...Parameter_Ts>
12804
- inline Object Object::call(Identifier id, Parameter_Ts... args) const
12856
+ inline Object Object::call(Identifier id, Parameter_Ts&&... args) const
12805
12857
  {
12806
12858
  /* IMPORTANT - We store VALUEs in an array that is a local variable.
12807
12859
  That allows the Ruby garbage collector to find them when scanning
@@ -12815,10 +12867,10 @@ namespace Rice
12815
12867
  }
12816
12868
 
12817
12869
  template<typename ...Parameter_Ts>
12818
- inline Object Object::call_kw(Identifier id, Parameter_Ts... args) const
12870
+ inline Object Object::call_kw(Identifier id, Parameter_Ts&&... args) const
12819
12871
  {
12820
12872
  /* IMPORTANT - See call() above */
12821
- std::array<VALUE, sizeof...(Parameter_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Parameter_Ts>>().convert(args)... };
12873
+ std::array<VALUE, sizeof...(Parameter_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Parameter_Ts>>().convert(std::forward<Parameter_Ts>(args))... };
12822
12874
  return detail::protect(rb_funcallv_kw, this->validated_value(), id.id(), (int)values.size(), (const VALUE*)values.data(), RB_PASS_KEYWORDS);
12823
12875
  }
12824
12876
 
@@ -13166,6 +13218,25 @@ namespace Rice::detail
13166
13218
  return x.value();
13167
13219
  }
13168
13220
 
13221
+ private:
13222
+ Arg* arg_ = nullptr;
13223
+ };
13224
+
13225
+ template<>
13226
+ class To_Ruby<String&>
13227
+ {
13228
+ public:
13229
+ To_Ruby() = default;
13230
+
13231
+ explicit To_Ruby(Arg* arg) : arg_(arg)
13232
+ {
13233
+ }
13234
+
13235
+ VALUE convert(String const& x)
13236
+ {
13237
+ return x.value();
13238
+ }
13239
+
13169
13240
  private:
13170
13241
  Arg* arg_ = nullptr;
13171
13242
  };
@@ -13899,6 +13970,25 @@ namespace Rice::detail
13899
13970
  Arg* arg_ = nullptr;
13900
13971
  };
13901
13972
 
13973
+ template<>
13974
+ class To_Ruby<Hash&>
13975
+ {
13976
+ public:
13977
+ To_Ruby() = default;
13978
+
13979
+ explicit To_Ruby(Arg* arg) : arg_(arg)
13980
+ {
13981
+ }
13982
+
13983
+ VALUE convert(Hash const& x)
13984
+ {
13985
+ return x.value();
13986
+ }
13987
+
13988
+ private:
13989
+ Arg* arg_ = nullptr;
13990
+ };
13991
+
13902
13992
  template<>
13903
13993
  class From_Ruby<Hash>
13904
13994
  {
@@ -15113,7 +15203,7 @@ namespace Rice
15113
15203
  static void initialize(VALUE self, Parameter_Ts...args)
15114
15204
  {
15115
15205
  // Call C++ constructor
15116
- T* data = new T(args...);
15206
+ T* data = new T(std::forward<Parameter_Ts>(args)...);
15117
15207
  detail::wrapConstructed<T>(self, Data_Type<T>::ruby_data_type(), data);
15118
15208
  }
15119
15209
 
@@ -15147,11 +15237,12 @@ namespace Rice
15147
15237
  static void initialize(Object self, Parameter_Ts...args)
15148
15238
  {
15149
15239
  // Call C++ constructor
15150
- T* data = new T(self, args...);
15240
+ T* data = new T(self, std::forward<Parameter_Ts>(args)...);
15151
15241
  detail::wrapConstructed<T>(self.value(), Data_Type<T>::ruby_data_type(), data);
15152
15242
  }
15153
15243
  };
15154
15244
  }
15245
+
15155
15246
  // ========= Callback.hpp =========
15156
15247
 
15157
15248
  namespace Rice
@@ -15514,16 +15605,6 @@ namespace Rice::detail
15514
15605
  Arg* arg_ = nullptr;
15515
15606
  };
15516
15607
 
15517
- template<typename T>
15518
- class To_Ruby<Data_Object<T>>
15519
- {
15520
- public:
15521
- VALUE convert(const Object& x)
15522
- {
15523
- return x.value();
15524
- }
15525
- };
15526
-
15527
15608
  template <typename T>
15528
15609
  class From_Ruby
15529
15610
  {
@@ -15869,38 +15950,6 @@ namespace Rice::detail
15869
15950
  Arg* arg_ = nullptr;
15870
15951
  std::vector<Intrinsic_T*> vector_;
15871
15952
  };
15872
-
15873
- template<typename T>
15874
- class From_Ruby<Data_Object<T>>
15875
- {
15876
- static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
15877
- "Data_Object cannot be used with fundamental types");
15878
-
15879
- static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
15880
- !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
15881
- !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
15882
- !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
15883
- !std::is_same_v<T, std::vector<T>>,
15884
- "Please include rice/stl.hpp header for STL support");
15885
-
15886
- public:
15887
- double is_convertible(VALUE value)
15888
- {
15889
- switch (rb_type(value))
15890
- {
15891
- case RUBY_T_DATA:
15892
- return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
15893
- break;
15894
- default:
15895
- return Convertible::None;
15896
- }
15897
- }
15898
-
15899
- static Data_Object<T> convert(VALUE value)
15900
- {
15901
- return Data_Object<T>(value);
15902
- }
15903
- };
15904
15953
  }
15905
15954
 
15906
15955
  // ========= Enum.hpp =========