ruby-qt6-rice 6.2.0 → 6.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a6aeeea52c229e9ec9107f0a878f810f4da0f57f1125e4d234a7cbee9f34f26
4
- data.tar.gz: b4a14875c07b82212e67509d0ca6554390a841e1c27a477a249f21329d67f223
3
+ metadata.gz: 7e2a94980ff633cdca492697fb85cbf928ffd56f15a331a2f0c333b38ac225d5
4
+ data.tar.gz: 33f79c9e4d15dcc41ca59680c4e0250873824e70a29deaf6c6869989a0f0d48f
5
5
  SHA512:
6
- metadata.gz: 1a0e49a306ecd7bb4cee1081b75e46255cb2d8a94a1da790d6b7863b1eecb657111a324faea87076eedd950471f049f8f9f21b718a8d476e7cf12d7b1b484bd3
7
- data.tar.gz: e8e55d43cabc562f8570fbb84c14405d336b37a2b31501c8f10f818c8911ff2bf53dc43db5fea72f1f6a1783edb78bcfd0540ce6b877d33850591b7cc948ae90
6
+ metadata.gz: d06f805fa53f1960d9a9a1e656f9d1f217c69ef0ec54afc5f9f9597307760600e485307c90089673aa5dcbf806bf3863c0f3aceedc9a0725103260f19e1667b4
7
+ data.tar.gz: 1f000daa8dfc865a39bd3e589713cf2ad065da20c67b130a9862c9c38146015fd79784e35d8c9f19dc2eff9dde3110cd1c42c24a76b474512f586bb43fbb254a
@@ -189,6 +189,9 @@ namespace Rice4RubyQt6
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
 
@@ -556,6 +559,27 @@ namespace Rice4RubyQt6::detail
556
559
  {
557
560
  };
558
561
 
562
+ // ref-qualified member Functions on C++ classes (C++20 uses these for std library types)
563
+ template<typename Return_T, typename Class_T, typename...Parameter_Ts>
564
+ struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) &> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
565
+ {
566
+ };
567
+
568
+ template<typename Return_T, typename Class_T, typename...Parameter_Ts>
569
+ struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) const&> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
570
+ {
571
+ };
572
+
573
+ template<typename Return_T, typename Class_T, typename...Parameter_Ts>
574
+ struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) & noexcept> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
575
+ {
576
+ };
577
+
578
+ template<typename Return_T, typename Class_T, typename...Parameter_Ts>
579
+ struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) const& noexcept> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
580
+ {
581
+ };
582
+
559
583
  /*// Functors and lambdas
560
584
  template<class Function_T>
561
585
  struct function_traits<Function_T&> : public function_traits<Function_T>
@@ -838,6 +862,7 @@ namespace Rice4RubyQt6::detail
838
862
  // ========= Anchor.hpp =========
839
863
 
840
864
  #include <ruby.h>
865
+ #include <ruby/vm.h>
841
866
 
842
867
  namespace Rice4RubyQt6
843
868
  {
@@ -872,7 +897,6 @@ namespace Rice4RubyQt6
872
897
  VALUE get() const;
873
898
 
874
899
  private:
875
- static void disable(VALUE);
876
900
  static void registerExitHandler();
877
901
 
878
902
  inline static bool enabled_ = true;
@@ -1073,6 +1097,7 @@ namespace Rice4RubyQt6
1073
1097
  break;
1074
1098
  case RUBY_TAG_THROW:
1075
1099
  this->message_ = "Unexpected throw";
1100
+ break;
1076
1101
  case RUBY_TAG_RAISE:
1077
1102
  this->message_ = "Ruby exception was thrown";
1078
1103
  break;
@@ -1569,6 +1594,7 @@ namespace Rice4RubyQt6::detail
1569
1594
  static constexpr double SignedToUnsigned = 0.5;// Penalty for signed to unsigned (can't represent negatives)
1570
1595
  static constexpr double FloatToInt = 0.5; // Domain change penalty when converting float to int (lossy)
1571
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
1572
1598
  };
1573
1599
  }
1574
1600
 
@@ -1646,23 +1672,28 @@ namespace Rice4RubyQt6
1646
1672
  {
1647
1673
  namespace detail
1648
1674
  {
1649
- inline Anchor::Anchor(VALUE value) : value_(value)
1675
+ inline Anchor::Anchor(VALUE value)
1650
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.
1651
1681
  if (!RB_SPECIAL_CONST_P(value))
1652
1682
  {
1653
1683
  Anchor::registerExitHandler();
1654
1684
  detail::protect(rb_gc_register_address, &this->value_);
1655
1685
  this->registered_ = true;
1656
1686
  }
1687
+ this->value_ = value;
1688
+ RB_GC_GUARD(value);
1657
1689
  }
1658
1690
 
1659
1691
  inline Anchor::~Anchor()
1660
1692
  {
1661
1693
  if (Anchor::enabled_ && this->registered_)
1662
1694
  {
1663
- detail::protect(rb_gc_unregister_address, &this->value_);
1695
+ rb_gc_unregister_address(&this->value_);
1664
1696
  }
1665
- // Ruby auto detects VALUEs in the stack, so make sure up in case this object is on the stack
1666
1697
  this->registered_ = false;
1667
1698
  this->value_ = Qnil;
1668
1699
  }
@@ -1672,17 +1703,18 @@ namespace Rice4RubyQt6
1672
1703
  return this->value_;
1673
1704
  }
1674
1705
 
1675
- // This will be called by ruby at exit - we want to disable further unregistering
1676
- inline void Anchor::disable(VALUE)
1677
- {
1678
- Anchor::enabled_ = false;
1679
- }
1680
-
1681
1706
  inline void Anchor::registerExitHandler()
1682
1707
  {
1683
1708
  if (!Anchor::exitHandlerRegistered_)
1684
1709
  {
1685
- 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; });
1686
1718
  Anchor::exitHandlerRegistered_ = true;
1687
1719
  }
1688
1720
  }
@@ -2005,7 +2037,7 @@ namespace Rice4RubyQt6
2005
2037
  * \endcode
2006
2038
  */
2007
2039
  template<typename ...Parameter_Ts>
2008
- Object call(Identifier id, Parameter_Ts... args) const;
2040
+ Object call(Identifier id, Parameter_Ts&&... args) const;
2009
2041
 
2010
2042
  //! Call the Ruby method specified by 'id' on object 'obj'.
2011
2043
  /*! Pass in arguments (arg1, arg2, ...). The arguments will be converted to
@@ -2028,7 +2060,7 @@ namespace Rice4RubyQt6
2028
2060
  * \endcode
2029
2061
  */
2030
2062
  template<typename ...Parameter_Ts>
2031
- Object call_kw(Identifier id, Parameter_Ts... args) const;
2063
+ Object call_kw(Identifier id, Parameter_Ts&&... args) const;
2032
2064
 
2033
2065
  //! Vectorized call.
2034
2066
  /*! Calls the method identified by id with the list of arguments
@@ -4261,7 +4293,7 @@ namespace Rice4RubyQt6
4261
4293
 
4262
4294
  public:
4263
4295
  Reference();
4264
- Reference(T& data);
4296
+ Reference(const T& data);
4265
4297
  Reference(VALUE value);
4266
4298
  T& get();
4267
4299
 
@@ -4270,7 +4302,7 @@ namespace Rice4RubyQt6
4270
4302
  };
4271
4303
 
4272
4304
  // Specialization needed when VALUE type matches T, causing constructor ambiguity
4273
- // between Reference(T&) and Reference(VALUE). VALUE is unsigned long when
4305
+ // between Reference(const T&) and Reference(VALUE). VALUE is unsigned long when
4274
4306
  // SIZEOF_LONG == SIZEOF_VOIDP (Linux/macOS) and unsigned long long when
4275
4307
  // SIZEOF_LONG_LONG == SIZEOF_VOIDP (Windows x64).
4276
4308
  #if SIZEOF_LONG == SIZEOF_VOIDP
@@ -4442,6 +4474,12 @@ namespace Rice4RubyQt6::detail
4442
4474
  {
4443
4475
  result = Convertible::None;
4444
4476
  }
4477
+ // Existing wrapped Ruby objects should prefer borrowing overloads to
4478
+ // rvalue-reference overloads so they are not silently moved-from.
4479
+ else if constexpr (std::is_rvalue_reference_v<T>)
4480
+ {
4481
+ result = Convertible::RValueMismatch;
4482
+ }
4445
4483
  // It is ok to send a non-const value to a const parameter but
4446
4484
  // prefer non-const to non-const by slightly decreasing the score
4447
4485
  else if (!isConst && is_const_any_v<T>)
@@ -4478,6 +4516,11 @@ namespace Rice4RubyQt6::detail
4478
4516
  {
4479
4517
  return this->fromRuby_.convert(valueOpt.value());
4480
4518
  }
4519
+ else if constexpr (std::is_rvalue_reference_v<T>)
4520
+ {
4521
+ // Rvalue-reference parameters cannot safely use stored default values.
4522
+ // Materializing them from std::any would require moving from shared state.
4523
+ }
4481
4524
  // Remember std::is_copy_constructible_v<std::vector<std::unique_ptr<T>>>> returns true. Sigh.
4482
4525
  // So special case vector handling
4483
4526
  else if constexpr (detail::is_std_vector_v<detail::intrinsic_type<T>>)
@@ -6442,6 +6485,25 @@ namespace Rice4RubyQt6
6442
6485
  Arg* arg_ = nullptr;
6443
6486
  };
6444
6487
 
6488
+ template<>
6489
+ class To_Ruby<char*&>
6490
+ {
6491
+ public:
6492
+ To_Ruby() = default;
6493
+
6494
+ explicit To_Ruby(Arg* arg) : arg_(arg)
6495
+ {
6496
+ }
6497
+
6498
+ VALUE convert(const char* data)
6499
+ {
6500
+ return To_Ruby<char*>(arg_).convert(data);
6501
+ }
6502
+
6503
+ private:
6504
+ Arg* arg_ = nullptr;
6505
+ };
6506
+
6445
6507
  template<int N>
6446
6508
  class To_Ruby<char[N]>
6447
6509
  {
@@ -6474,6 +6536,25 @@ namespace Rice4RubyQt6
6474
6536
  Arg* arg_ = nullptr;
6475
6537
  };
6476
6538
 
6539
+ template<int N>
6540
+ class To_Ruby<char(&)[N]>
6541
+ {
6542
+ public:
6543
+ To_Ruby() = default;
6544
+
6545
+ explicit To_Ruby(Arg* arg) : arg_(arg)
6546
+ {
6547
+ }
6548
+
6549
+ VALUE convert(const char (&buffer)[N])
6550
+ {
6551
+ return To_Ruby<char[N]>(arg_).convert(buffer);
6552
+ }
6553
+
6554
+ private:
6555
+ Arg* arg_ = nullptr;
6556
+ };
6557
+
6477
6558
  // =========== unsigned char ============
6478
6559
  template<>
6479
6560
  class To_Ruby<unsigned char>
@@ -7195,6 +7276,25 @@ namespace Rice4RubyQt6
7195
7276
  Arg* arg_ = nullptr;
7196
7277
  };
7197
7278
 
7279
+ template<>
7280
+ class To_Ruby<std::nullptr_t&>
7281
+ {
7282
+ public:
7283
+ To_Ruby() = default;
7284
+
7285
+ explicit To_Ruby(Arg* arg) : arg_(arg)
7286
+ {
7287
+ }
7288
+
7289
+ VALUE convert(std::nullptr_t const)
7290
+ {
7291
+ return Qnil;
7292
+ }
7293
+
7294
+ private:
7295
+ Arg* arg_ = nullptr;
7296
+ };
7297
+
7198
7298
  // =========== void ============
7199
7299
  template<>
7200
7300
  class To_Ruby<void>
@@ -7253,6 +7353,7 @@ namespace Rice4RubyQt6
7253
7353
  };
7254
7354
  }
7255
7355
  }
7356
+
7256
7357
  // ========= from_ruby.ipp =========
7257
7358
  #include <limits>
7258
7359
  #include <optional>
@@ -8864,31 +8965,15 @@ namespace Rice4RubyQt6::detail
8864
8965
  }
8865
8966
  }
8866
8967
 
8867
- void* convert(VALUE value)
8968
+ std::nullptr_t convert(VALUE value)
8868
8969
  {
8869
8970
  if (value == Qnil)
8870
8971
  {
8871
8972
  return nullptr;
8872
8973
  }
8873
8974
 
8874
- if (this->arg_ && this->arg_->isOpaque())
8875
- {
8876
- return (void*)value;
8877
- }
8878
-
8879
- switch (rb_type(value))
8880
- {
8881
- case RUBY_T_NIL:
8882
- {
8883
- return nullptr;
8884
- break;
8885
- }
8886
- default:
8887
- {
8888
- throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
8889
- detail::protect(rb_obj_classname, value), "nil");
8890
- }
8891
- }
8975
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
8976
+ detail::protect(rb_obj_classname, value), "nil");
8892
8977
  }
8893
8978
  private:
8894
8979
  Arg* arg_ = nullptr;
@@ -9049,7 +9134,7 @@ namespace Rice4RubyQt6
9049
9134
  }
9050
9135
 
9051
9136
  template<typename T>
9052
- inline Reference<T>::Reference(T& data) : data_(data)
9137
+ inline Reference<T>::Reference(const T& data) : data_(data)
9053
9138
  {
9054
9139
  }
9055
9140
 
@@ -10287,7 +10372,10 @@ namespace Rice4RubyQt6::detail
10287
10372
 
10288
10373
  if constexpr (is_complete_v<T>)
10289
10374
  {
10290
- if constexpr (std::is_destructible_v<T>)
10375
+ // is_polymorphic_v requires a complete type, so nest inside is_complete_v.
10376
+ // Deleting a polymorphic class through a non-virtual destructor is UB,
10377
+ // but it is safe if the destructor is virtual.
10378
+ if constexpr (std::is_destructible_v<T> && (!std::is_polymorphic_v<T> || std::has_virtual_destructor_v<T>))
10291
10379
  {
10292
10380
  if (this->isOwner_)
10293
10381
  {
@@ -12659,6 +12747,25 @@ namespace Rice4RubyQt6::detail
12659
12747
  }
12660
12748
  };
12661
12749
 
12750
+ // Wraps a C++ function as a Ruby proc
12751
+ template<typename Return_T, typename ...Parameter_Ts>
12752
+ class To_Ruby<Return_T(*&)(Parameter_Ts...)>
12753
+ {
12754
+ public:
12755
+ using Proc_T = Return_T(*&)(Parameter_Ts...);
12756
+
12757
+ To_Ruby() = default;
12758
+
12759
+ explicit To_Ruby(Arg*)
12760
+ {}
12761
+
12762
+ VALUE convert(Proc_T proc)
12763
+ {
12764
+ // Wrap the C+++ function pointer as a Ruby Proc
12765
+ return NativeProc<Proc_T>::createRubyProc(std::forward<Proc_T>(proc));
12766
+ }
12767
+ };
12768
+
12662
12769
  // Makes a Ruby proc callable as C callback
12663
12770
  template<typename Return_T, typename ...Parameter_Ts>
12664
12771
  class From_Ruby<Return_T(*)(Parameter_Ts...)>
@@ -12711,53 +12818,6 @@ namespace Rice4RubyQt6
12711
12818
  }
12712
12819
  }
12713
12820
 
12714
- /*namespace Rice4RubyQt6::detail
12715
- {
12716
- template<>
12717
- struct Type<Encoding>
12718
- {
12719
- static bool verify()
12720
- {
12721
- return true;
12722
- }
12723
- };
12724
-
12725
- template<>
12726
- class To_Ruby<Encoding>
12727
- {
12728
- public:
12729
- VALUE convert(const Encoding& encoding)
12730
- {
12731
- // return x.value();
12732
- }
12733
- };
12734
-
12735
- template<>
12736
- class From_Ruby<Encoding>
12737
- {
12738
- public:
12739
- Convertible is_convertible(VALUE value)
12740
- {
12741
- switch (rb_type(value))
12742
- {
12743
- case RUBY_T_SYMBOL:
12744
- return Convertible::Exact;
12745
- break;
12746
- case RUBY_T_STRING:
12747
- return Convertible::Cast;
12748
- break;
12749
- default:
12750
- return Convertible::None;
12751
- }
12752
- }
12753
-
12754
- Encoding convert(VALUE value)
12755
- {
12756
- // return Symbol(value);
12757
- }
12758
- };
12759
- }
12760
- */
12761
12821
  // ========= Object.ipp =========
12762
12822
  namespace Rice4RubyQt6
12763
12823
  {
@@ -12803,7 +12863,7 @@ namespace Rice4RubyQt6
12803
12863
  }
12804
12864
 
12805
12865
  template<typename ...Parameter_Ts>
12806
- inline Object Object::call(Identifier id, Parameter_Ts... args) const
12866
+ inline Object Object::call(Identifier id, Parameter_Ts&&... args) const
12807
12867
  {
12808
12868
  /* IMPORTANT - We store VALUEs in an array that is a local variable.
12809
12869
  That allows the Ruby garbage collector to find them when scanning
@@ -12817,10 +12877,10 @@ namespace Rice4RubyQt6
12817
12877
  }
12818
12878
 
12819
12879
  template<typename ...Parameter_Ts>
12820
- inline Object Object::call_kw(Identifier id, Parameter_Ts... args) const
12880
+ inline Object Object::call_kw(Identifier id, Parameter_Ts&&... args) const
12821
12881
  {
12822
12882
  /* IMPORTANT - See call() above */
12823
- std::array<VALUE, sizeof...(Parameter_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Parameter_Ts>>().convert(args)... };
12883
+ std::array<VALUE, sizeof...(Parameter_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Parameter_Ts>>().convert(std::forward<Parameter_Ts>(args))... };
12824
12884
  return detail::protect(rb_funcallv_kw, this->validated_value(), id.id(), (int)values.size(), (const VALUE*)values.data(), RB_PASS_KEYWORDS);
12825
12885
  }
12826
12886
 
@@ -13168,6 +13228,25 @@ namespace Rice4RubyQt6::detail
13168
13228
  return x.value();
13169
13229
  }
13170
13230
 
13231
+ private:
13232
+ Arg* arg_ = nullptr;
13233
+ };
13234
+
13235
+ template<>
13236
+ class To_Ruby<String&>
13237
+ {
13238
+ public:
13239
+ To_Ruby() = default;
13240
+
13241
+ explicit To_Ruby(Arg* arg) : arg_(arg)
13242
+ {
13243
+ }
13244
+
13245
+ VALUE convert(String const& x)
13246
+ {
13247
+ return x.value();
13248
+ }
13249
+
13171
13250
  private:
13172
13251
  Arg* arg_ = nullptr;
13173
13252
  };
@@ -13901,6 +13980,25 @@ namespace Rice4RubyQt6::detail
13901
13980
  Arg* arg_ = nullptr;
13902
13981
  };
13903
13982
 
13983
+ template<>
13984
+ class To_Ruby<Hash&>
13985
+ {
13986
+ public:
13987
+ To_Ruby() = default;
13988
+
13989
+ explicit To_Ruby(Arg* arg) : arg_(arg)
13990
+ {
13991
+ }
13992
+
13993
+ VALUE convert(Hash const& x)
13994
+ {
13995
+ return x.value();
13996
+ }
13997
+
13998
+ private:
13999
+ Arg* arg_ = nullptr;
14000
+ };
14001
+
13904
14002
  template<>
13905
14003
  class From_Ruby<Hash>
13906
14004
  {
@@ -15132,7 +15230,7 @@ namespace Rice4RubyQt6
15132
15230
  static void initialize(VALUE self, Parameter_Ts...args)
15133
15231
  {
15134
15232
  // Call C++ constructor
15135
- T* data = new T(args...);
15233
+ T* data = new T(std::forward<Parameter_Ts>(args)...);
15136
15234
  detail::wrapConstructed<T>(self, Data_Type<T>::ruby_data_type(), data);
15137
15235
  }
15138
15236
 
@@ -15166,11 +15264,12 @@ namespace Rice4RubyQt6
15166
15264
  static void initialize(Object self, Parameter_Ts...args)
15167
15265
  {
15168
15266
  // Call C++ constructor
15169
- T* data = new T(self, args...);
15267
+ T* data = new T(self, std::forward<Parameter_Ts>(args)...);
15170
15268
  detail::wrapConstructed<T>(self.value(), Data_Type<T>::ruby_data_type(), data);
15171
15269
  }
15172
15270
  };
15173
15271
  }
15272
+
15174
15273
  // ========= Callback.hpp =========
15175
15274
 
15176
15275
  namespace Rice4RubyQt6
@@ -15533,16 +15632,6 @@ namespace Rice4RubyQt6::detail
15533
15632
  Arg* arg_ = nullptr;
15534
15633
  };
15535
15634
 
15536
- template<typename T>
15537
- class To_Ruby<Data_Object<T>>
15538
- {
15539
- public:
15540
- VALUE convert(const Object& x)
15541
- {
15542
- return x.value();
15543
- }
15544
- };
15545
-
15546
15635
  template <typename T>
15547
15636
  class From_Ruby
15548
15637
  {
@@ -15888,38 +15977,6 @@ namespace Rice4RubyQt6::detail
15888
15977
  Arg* arg_ = nullptr;
15889
15978
  std::vector<Intrinsic_T*> vector_;
15890
15979
  };
15891
-
15892
- template<typename T>
15893
- class From_Ruby<Data_Object<T>>
15894
- {
15895
- static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
15896
- "Data_Object cannot be used with fundamental types");
15897
-
15898
- static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
15899
- !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
15900
- !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
15901
- !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
15902
- !std::is_same_v<T, std::vector<T>>,
15903
- "Please include rice/stl.hpp header for STL support");
15904
-
15905
- public:
15906
- double is_convertible(VALUE value)
15907
- {
15908
- switch (rb_type(value))
15909
- {
15910
- case RUBY_T_DATA:
15911
- return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
15912
- break;
15913
- default:
15914
- return Convertible::None;
15915
- }
15916
- }
15917
-
15918
- static Data_Object<T> convert(VALUE value)
15919
- {
15920
- return Data_Object<T>(value);
15921
- }
15922
- };
15923
15980
  }
15924
15981
 
15925
15982
  // ========= Enum.hpp =========
@@ -151,9 +151,9 @@ namespace Rice4RubyQt6::stl
151
151
  klass_.define_method("initialize", [](VALUE self, VALUE callable) -> void
152
152
  {
153
153
  // Create std::function that wraps the Ruby callable
154
- Function_T* data = new Function_T([callable](auto... args)
154
+ Function_T* data = new Function_T([callable](auto&&... args)
155
155
  {
156
- Object result = Object(callable).call("call", args...);
156
+ Object result = Object(callable).call("call", std::forward<decltype(args)>(args)...);
157
157
 
158
158
  using Return_T = typename Function_T::result_type;
159
159
  if constexpr (!std::is_void_v<Return_T>)
@@ -211,6 +211,146 @@ namespace Rice4RubyQt6
211
211
 
212
212
  namespace Rice4RubyQt6::detail
213
213
  {
214
+ template<typename Return_T, typename ...Parameter_Ts>
215
+ inline std::function<Return_T(Parameter_Ts...)> makeRubyFunction(VALUE value)
216
+ {
217
+ Pin proc(value);
218
+
219
+ return [proc = std::move(proc)](Parameter_Ts... args) -> Return_T
220
+ {
221
+ Object result = Object(proc.value()).call("call", std::forward<Parameter_Ts>(args)...);
222
+
223
+ if constexpr (!std::is_void_v<Return_T>)
224
+ {
225
+ return From_Ruby<std::remove_cv_t<Return_T>>().convert(result);
226
+ }
227
+ };
228
+ }
229
+
230
+ template<typename Return_T, typename ...Parameter_Ts>
231
+ class From_Ruby<std::function<Return_T(Parameter_Ts...)>>
232
+ {
233
+ public:
234
+ using Function_T = std::function<Return_T(Parameter_Ts...)>;
235
+
236
+ From_Ruby() = default;
237
+
238
+ explicit From_Ruby(Arg* arg) : arg_(arg)
239
+ {
240
+ }
241
+
242
+ double is_convertible(VALUE value)
243
+ {
244
+ switch (rb_type(value))
245
+ {
246
+ case RUBY_T_DATA:
247
+ return Data_Type<Function_T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
248
+ default:
249
+ return protect(rb_obj_is_proc, value) == Qtrue ? Convertible::ConstMismatch : Convertible::None;
250
+ }
251
+ }
252
+
253
+ Function_T convert(VALUE value)
254
+ {
255
+ if (Data_Type<Function_T>::is_descendant(value))
256
+ {
257
+ return *detail::unwrap<Function_T>(value, Data_Type<Function_T>::ruby_data_type(), false);
258
+ }
259
+ else if (protect(rb_obj_is_proc, value) == Qtrue)
260
+ {
261
+ return makeRubyFunction<Return_T, Parameter_Ts...>(value);
262
+ }
263
+ else
264
+ {
265
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
266
+ detail::protect(rb_obj_classname, value), "std::function");
267
+ }
268
+ }
269
+
270
+ private:
271
+ Arg* arg_ = nullptr;
272
+ };
273
+
274
+ template<typename Return_T, typename ...Parameter_Ts>
275
+ class From_Ruby<std::function<Return_T(Parameter_Ts...)>&>
276
+ {
277
+ public:
278
+ using Function_T = std::function<Return_T(Parameter_Ts...)>;
279
+
280
+ From_Ruby() = default;
281
+
282
+ explicit From_Ruby(Arg* arg) : arg_(arg)
283
+ {
284
+ }
285
+
286
+ double is_convertible(VALUE value)
287
+ {
288
+ return From_Ruby<Function_T>(arg_).is_convertible(value);
289
+ }
290
+
291
+ Function_T& convert(VALUE value)
292
+ {
293
+ if (Data_Type<Function_T>::is_descendant(value))
294
+ {
295
+ return *detail::unwrap<Function_T>(value, Data_Type<Function_T>::ruby_data_type(), false);
296
+ }
297
+ else if (protect(rb_obj_is_proc, value) == Qtrue)
298
+ {
299
+ converted_ = makeRubyFunction<Return_T, Parameter_Ts...>(value);
300
+ return converted_;
301
+ }
302
+ else
303
+ {
304
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
305
+ detail::protect(rb_obj_classname, value), "std::function");
306
+ }
307
+ }
308
+
309
+ private:
310
+ Arg* arg_ = nullptr;
311
+ Function_T converted_;
312
+ };
313
+
314
+ template<typename Return_T, typename ...Parameter_Ts>
315
+ class From_Ruby<std::function<Return_T(Parameter_Ts...)>&&>
316
+ {
317
+ public:
318
+ using Function_T = std::function<Return_T(Parameter_Ts...)>;
319
+
320
+ From_Ruby() = default;
321
+
322
+ explicit From_Ruby(Arg* arg) : arg_(arg)
323
+ {
324
+ }
325
+
326
+ double is_convertible(VALUE value)
327
+ {
328
+ return From_Ruby<Function_T>(arg_).is_convertible(value);
329
+ }
330
+
331
+ Function_T&& convert(VALUE value)
332
+ {
333
+ if (Data_Type<Function_T>::is_descendant(value))
334
+ {
335
+ return std::move(*detail::unwrap<Function_T>(value, Data_Type<Function_T>::ruby_data_type(), false));
336
+ }
337
+ else if (protect(rb_obj_is_proc, value) == Qtrue)
338
+ {
339
+ converted_ = makeRubyFunction<Return_T, Parameter_Ts...>(value);
340
+ return std::move(converted_);
341
+ }
342
+ else
343
+ {
344
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
345
+ detail::protect(rb_obj_classname, value), "std::function");
346
+ }
347
+ }
348
+
349
+ private:
350
+ Arg* arg_ = nullptr;
351
+ Function_T converted_;
352
+ };
353
+
214
354
  template<typename Signature_T>
215
355
  struct Type<std::function<Signature_T>>
216
356
  {
@@ -867,6 +1007,24 @@ namespace Rice4RubyQt6::detail
867
1007
  Arg* arg_ = nullptr;
868
1008
  };
869
1009
 
1010
+ template<>
1011
+ class To_Ruby<std::nullopt_t&>
1012
+ {
1013
+ public:
1014
+ To_Ruby() = default;
1015
+
1016
+ explicit To_Ruby(Arg* arg) : arg_(arg)
1017
+ {}
1018
+
1019
+ VALUE convert(const std::nullopt_t&)
1020
+ {
1021
+ return Qnil;
1022
+ }
1023
+
1024
+ private:
1025
+ Arg* arg_ = nullptr;
1026
+ };
1027
+
870
1028
  template<typename T>
871
1029
  class To_Ruby<std::optional<T>>
872
1030
  {
@@ -1133,8 +1291,12 @@ namespace Rice4RubyQt6::stl
1133
1291
 
1134
1292
  void define_methods()
1135
1293
  {
1294
+ #if __cplusplus >= 202002L
1295
+ klass_.define_method<std::string(std::ostringstream::*)() const&>("str", &std::ostringstream::str)
1296
+ #else
1136
1297
  klass_.define_method<std::string(std::ostringstream::*)() const>("str", &std::ostringstream::str)
1137
- .define_method("str=", [](std::ostringstream& stream, const std::string& s) { stream.str(s); }, Arg("str"));
1298
+ #endif
1299
+ .define_method("str=", [](std::ostringstream& stream, const std::string& s) { stream.str(s); }, Arg("str"));
1138
1300
 
1139
1301
  rb_define_alias(klass_, "to_s", "str");
1140
1302
  }
@@ -1310,8 +1472,12 @@ namespace Rice4RubyQt6
1310
1472
  private:
1311
1473
  void define_constructors()
1312
1474
  {
1313
- klass_.define_constructor(Constructor<T>())
1314
- .define_constructor(Constructor<T, First_Parameter_T, Second_Parameter_T>(), Arg("x").keepAlive(), Arg("y").keepAlive());
1475
+ if constexpr (std::is_default_constructible_v<T>)
1476
+ {
1477
+ klass_.define_constructor(Constructor<T>());
1478
+ }
1479
+
1480
+ klass_.define_constructor(Constructor<T, First_Parameter_T, Second_Parameter_T>(), Arg("x").keepAlive(), Arg("y").keepAlive());
1315
1481
 
1316
1482
  if constexpr (std::is_copy_constructible_v<First_T> && std::is_copy_constructible_v<Second_T>)
1317
1483
  {
@@ -1455,6 +1621,24 @@ namespace Rice4RubyQt6::detail
1455
1621
  Arg* arg_ = nullptr;
1456
1622
  };
1457
1623
 
1624
+ template<typename T>
1625
+ class To_Ruby<std::reference_wrapper<T>&>
1626
+ {
1627
+ public:
1628
+ To_Ruby() = default;
1629
+
1630
+ explicit To_Ruby(Arg* arg) : arg_(arg)
1631
+ {}
1632
+
1633
+ VALUE convert(const std::reference_wrapper<T>& data)
1634
+ {
1635
+ return To_Ruby<T&>().convert(data.get());
1636
+ }
1637
+
1638
+ private:
1639
+ Arg* arg_ = nullptr;
1640
+ };
1641
+
1458
1642
  template<typename T>
1459
1643
  class From_Ruby<std::reference_wrapper<T>>
1460
1644
  {
@@ -1618,16 +1802,8 @@ namespace Rice4RubyQt6
1618
1802
  return it != map.end();
1619
1803
  }, Arg("value"));
1620
1804
  rb_define_alias(klass_, "eql?", "==");
1805
+ rb_define_alias(klass_, "has_value", "value?");
1621
1806
  }
1622
- else
1623
- {
1624
- klass_.define_method("value?", [](T&, Mapped_Parameter_T) -> bool
1625
- {
1626
- return false;
1627
- }, Arg("value"));
1628
- }
1629
-
1630
- rb_define_alias(klass_, "has_value", "value?");
1631
1807
  }
1632
1808
 
1633
1809
  void define_modify_methods()
@@ -1650,7 +1826,7 @@ namespace Rice4RubyQt6
1650
1826
  }, Arg("key"))
1651
1827
  .define_method("[]=", [](T& map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
1652
1828
  {
1653
- map[key] = value;
1829
+ map.insert_or_assign(key, value);
1654
1830
  return value;
1655
1831
  }, Arg("key").keepAlive(), Arg("value").keepAlive());
1656
1832
 
@@ -1772,7 +1948,7 @@ namespace Rice4RubyQt6
1772
1948
  // exceptions propogate back to Ruby
1773
1949
  return cpp_protect([&]
1774
1950
  {
1775
- result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
1951
+ result->insert_or_assign(From_Ruby<T>().convert(key), From_Ruby<U>().convert(value));
1776
1952
  return ST_CONTINUE;
1777
1953
  });
1778
1954
  }
@@ -1961,6 +2137,7 @@ namespace Rice4RubyQt6
1961
2137
  }
1962
2138
  }
1963
2139
 
2140
+
1964
2141
  // ========= monostate.hpp =========
1965
2142
 
1966
2143
 
@@ -2222,16 +2399,8 @@ namespace Rice4RubyQt6
2222
2399
  return it != multimap.end();
2223
2400
  }, Arg("value"));
2224
2401
  rb_define_alias(klass_, "eql?", "==");
2402
+ rb_define_alias(klass_, "has_value", "value?");
2225
2403
  }
2226
- else
2227
- {
2228
- klass_.define_method("value?", [](T&, Mapped_Parameter_T) -> bool
2229
- {
2230
- return false;
2231
- }, Arg("value"));
2232
- }
2233
-
2234
- rb_define_alias(klass_, "has_value", "value?");
2235
2404
  }
2236
2405
 
2237
2406
  void define_modify_methods()
@@ -2546,6 +2715,7 @@ namespace Rice4RubyQt6
2546
2715
  }
2547
2716
  }
2548
2717
 
2718
+
2549
2719
  // ========= set.hpp =========
2550
2720
 
2551
2721
  namespace Rice4RubyQt6
@@ -2659,23 +2829,23 @@ namespace Rice4RubyQt6
2659
2829
 
2660
2830
  void define_operators()
2661
2831
  {
2662
- klass_
2663
- .define_method("<<", [](T& self, Parameter_T value) -> T&
2664
- {
2665
- self.insert(value);
2666
- return self;
2667
- }, Arg("value").keepAlive())
2668
- .define_method("==", [](const T& self, const T& other) -> bool
2832
+ klass_.define_method("<<", [](T& self, Parameter_T value) -> T&
2833
+ {
2834
+ self.insert(value);
2835
+ return self;
2836
+ }, Arg("value").keepAlive());
2837
+
2838
+ if constexpr (detail::is_comparable_v<Value_T>)
2839
+ {
2840
+ klass_.define_method("==", [](const T& self, const T& other) -> bool
2669
2841
  {
2670
- if constexpr (detail::is_comparable_v<Value_T>)
2671
- {
2672
- return self == other;
2673
- }
2674
- else
2675
- {
2676
- return false;
2677
- }
2678
- }, Arg("other"))
2842
+ return self == other;
2843
+ }, Arg("other"));
2844
+
2845
+ rb_define_alias(klass_, "eql?", "==");
2846
+ }
2847
+
2848
+ klass_
2679
2849
  .define_method("&", [](const T& self, const T& other) -> T
2680
2850
  {
2681
2851
  T result;
@@ -2722,15 +2892,14 @@ namespace Rice4RubyQt6
2722
2892
  return std::includes(self.begin(), self.end(),
2723
2893
  other.begin(), other.end());
2724
2894
  }, Arg("other"));
2725
-
2726
- rb_define_alias(klass_, "eql?", "==");
2727
- rb_define_alias(klass_, "intersection", "&");
2728
- rb_define_alias(klass_, "union", "|");
2729
- rb_define_alias(klass_, "difference", "-");
2730
- rb_define_alias(klass_, "proper_subset?", "<");
2731
- rb_define_alias(klass_, "subset?", "<");
2732
- rb_define_alias(klass_, "proper_superset?", ">");
2733
- rb_define_alias(klass_, "superset?", ">");
2895
+
2896
+ rb_define_alias(klass_, "intersection", "&");
2897
+ rb_define_alias(klass_, "union", "|");
2898
+ rb_define_alias(klass_, "difference", "-");
2899
+ rb_define_alias(klass_, "proper_subset?", "<");
2900
+ rb_define_alias(klass_, "subset?", "<");
2901
+ rb_define_alias(klass_, "proper_superset?", ">");
2902
+ rb_define_alias(klass_, "superset?", ">");
2734
2903
  }
2735
2904
 
2736
2905
  void define_enumerable()
@@ -3201,7 +3370,11 @@ namespace Rice4RubyQt6
3201
3370
 
3202
3371
  if constexpr (detail::is_complete_v<T> && !std::is_void_v<T>)
3203
3372
  {
3204
- result.define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
3373
+ // is_abstract_v requires a complete type, so it must be nested inside the is_complete_v check
3374
+ if constexpr (!std::is_abstract_v<T>)
3375
+ {
3376
+ result.define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
3377
+ }
3205
3378
  }
3206
3379
 
3207
3380
  // Forward methods to wrapped T
@@ -3256,7 +3429,7 @@ namespace Rice4RubyQt6::detail
3256
3429
  }
3257
3430
  else if (rb_typeddata_inherited_p(this->inner_rb_data_type_, requestedType))
3258
3431
  {
3259
- return this->data_.get();
3432
+ return (void*)this->data_.get();
3260
3433
  }
3261
3434
  else
3262
3435
  {
@@ -3853,6 +4026,9 @@ namespace Rice4RubyQt6
3853
4026
  template<typename T>
3854
4027
  Data_Type<std::unique_ptr<T>> define_unique_ptr(std::string klassName)
3855
4028
  {
4029
+ static_assert(detail::is_complete_v<T>,
4030
+ "Rice does not support binding std::unique_ptr<T> when T is incomplete.");
4031
+
3856
4032
  using UniquePtr_T = std::unique_ptr<T>;
3857
4033
  using Data_Type_T = Data_Type<UniquePtr_T>;
3858
4034
 
@@ -3931,7 +4107,7 @@ namespace Rice4RubyQt6::detail
3931
4107
  }
3932
4108
  else if (rb_typeddata_inherited_p(this->inner_rb_data_type_, requestedType))
3933
4109
  {
3934
- return this->data_.get();
4110
+ return (void*)this->data_.get();
3935
4111
  }
3936
4112
  else
3937
4113
  {
@@ -4139,16 +4315,8 @@ namespace Rice4RubyQt6
4139
4315
  return it != unordered_map.end();
4140
4316
  }, Arg("value"));
4141
4317
  rb_define_alias(klass_, "eql?", "==");
4318
+ rb_define_alias(klass_, "has_value", "value?");
4142
4319
  }
4143
- else
4144
- {
4145
- klass_.define_method("value?", [](T&, Mapped_Parameter_T) -> bool
4146
- {
4147
- return false;
4148
- }, Arg("value"));
4149
- }
4150
-
4151
- rb_define_alias(klass_, "has_value", "value?");
4152
4320
  }
4153
4321
 
4154
4322
  void define_modify_methods()
@@ -4171,7 +4339,7 @@ namespace Rice4RubyQt6
4171
4339
  }, Arg("key"))
4172
4340
  .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
4173
4341
  {
4174
- unordered_map[key] = value;
4342
+ unordered_map.insert_or_assign(key, value);
4175
4343
  return value;
4176
4344
  }, Arg("key").keepAlive(), Arg("value").keepAlive());
4177
4345
 
@@ -4293,7 +4461,7 @@ namespace Rice4RubyQt6
4293
4461
  // exceptions propogate back to Ruby
4294
4462
  return cpp_protect([&]
4295
4463
  {
4296
- result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
4464
+ result->insert_or_assign(From_Ruby<T>().convert(key), From_Ruby<U>().convert(value));
4297
4465
  return ST_CONTINUE;
4298
4466
  });
4299
4467
  }
@@ -4482,6 +4650,7 @@ namespace Rice4RubyQt6
4482
4650
  }
4483
4651
  }
4484
4652
 
4653
+
4485
4654
  // ========= vector.hpp =========
4486
4655
 
4487
4656
  namespace Rice4RubyQt6
@@ -4790,21 +4959,6 @@ namespace Rice4RubyQt6
4790
4959
  }, Arg("value"));
4791
4960
  rb_define_alias(klass_, "eql?", "==");
4792
4961
  }
4793
- else
4794
- {
4795
- klass_.define_method("delete", [](T&, Parameter_T) -> std::optional<Value_T>
4796
- {
4797
- return std::nullopt;
4798
- }, Arg("value"))
4799
- .define_method("include?", [](const T&, Parameter_T)
4800
- {
4801
- return false;
4802
- }, Arg("value"))
4803
- .define_method("index", [](const T&, Parameter_T) -> std::optional<Difference_T>
4804
- {
4805
- return std::nullopt;
4806
- }, Arg("value"));
4807
- }
4808
4962
  }
4809
4963
 
4810
4964
  void define_modify_methods()
@@ -5215,6 +5369,24 @@ namespace Rice4RubyQt6
5215
5369
  private:
5216
5370
  Arg* arg_ = nullptr;
5217
5371
  };
5372
+
5373
+ template<>
5374
+ class To_Ruby<std::vector<bool>::reference&>
5375
+ {
5376
+ public:
5377
+ To_Ruby() = default;
5378
+
5379
+ explicit To_Ruby(Arg* arg) : arg_(arg)
5380
+ {}
5381
+
5382
+ VALUE convert(const std::vector<bool>::reference& value)
5383
+ {
5384
+ return value ? Qtrue : Qfalse;
5385
+ }
5386
+
5387
+ private:
5388
+ Arg* arg_ = nullptr;
5389
+ };
5218
5390
  }
5219
5391
  }
5220
5392
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RubyQt6
4
4
  module Rice
5
- RICE_RUBYGEM_VERSION = "6.2.0"
5
+ RICE_RUBYGEM_VERSION = "6.3.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-qt6-rice
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.0
4
+ version: 6.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Doe