qml 0.0.1

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 (170) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +46 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +15 -0
  5. data/.yardopts +4 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +351 -0
  9. data/Rakefile +6 -0
  10. data/examples/assets/fonts/fontawesome-webfont.ttf +0 -0
  11. data/examples/fizzbuzz/fizzbuzz.rb +43 -0
  12. data/examples/fizzbuzz/main.qml +38 -0
  13. data/examples/imageprovider/imageprovider.rb +57 -0
  14. data/examples/imageprovider/main.qml +51 -0
  15. data/examples/todo/main.qml +70 -0
  16. data/examples/todo/todo.rb +36 -0
  17. data/examples/twitter/main.qml +36 -0
  18. data/examples/twitter/twitter.rb +55 -0
  19. data/ext/qml/accessclass.cpp +71 -0
  20. data/ext/qml/accessclass.h +19 -0
  21. data/ext/qml/accessobject.cpp +30 -0
  22. data/ext/qml/accessobject.h +22 -0
  23. data/ext/qml/application.cpp +54 -0
  24. data/ext/qml/application.h +17 -0
  25. data/ext/qml/common.h +18 -0
  26. data/ext/qml/ext_accesssupport.cpp +77 -0
  27. data/ext/qml/ext_accesssupport.h +42 -0
  28. data/ext/qml/ext_gcmarker.cpp +39 -0
  29. data/ext/qml/ext_gcmarker.h +27 -0
  30. data/ext/qml/ext_kernel.cpp +62 -0
  31. data/ext/qml/ext_kernel.h +11 -0
  32. data/ext/qml/ext_metaobject.cpp +410 -0
  33. data/ext/qml/ext_metaobject.h +62 -0
  34. data/ext/qml/ext_pluginloader.cpp +55 -0
  35. data/ext/qml/ext_pluginloader.h +32 -0
  36. data/ext/qml/ext_pointer.cpp +134 -0
  37. data/ext/qml/ext_pointer.h +43 -0
  38. data/ext/qml/ext_testutil.cpp +42 -0
  39. data/ext/qml/ext_testutil.h +11 -0
  40. data/ext/qml/extconf.rb +84 -0
  41. data/ext/qml/foreignclass.cpp +72 -0
  42. data/ext/qml/foreignclass.h +88 -0
  43. data/ext/qml/foreignmetaobject.cpp +345 -0
  44. data/ext/qml/foreignmetaobject.h +46 -0
  45. data/ext/qml/foreignobject.cpp +22 -0
  46. data/ext/qml/foreignobject.h +21 -0
  47. data/ext/qml/functioninfo.h +16 -0
  48. data/ext/qml/init.cpp +69 -0
  49. data/ext/qml/listmodel.cpp +112 -0
  50. data/ext/qml/listmodel.h +43 -0
  51. data/ext/qml/markable.h +12 -0
  52. data/ext/qml/objectdata.cpp +26 -0
  53. data/ext/qml/objectdata.h +20 -0
  54. data/ext/qml/objectgc.cpp +69 -0
  55. data/ext/qml/objectgc.h +28 -0
  56. data/ext/qml/plugins/core/applicationextension.cpp +34 -0
  57. data/ext/qml/plugins/core/applicationextension.h +28 -0
  58. data/ext/qml/plugins/core/componentextension.cpp +41 -0
  59. data/ext/qml/plugins/core/componentextension.h +28 -0
  60. data/ext/qml/plugins/core/contextextension.cpp +39 -0
  61. data/ext/qml/plugins/core/contextextension.h +29 -0
  62. data/ext/qml/plugins/core/core.pro +29 -0
  63. data/ext/qml/plugins/core/coreplugin.cpp +87 -0
  64. data/ext/qml/plugins/core/coreplugin.h +49 -0
  65. data/ext/qml/plugins/core/engineextension.cpp +27 -0
  66. data/ext/qml/plugins/core/engineextension.h +28 -0
  67. data/ext/qml/plugins/core/imageprovider.cpp +38 -0
  68. data/ext/qml/plugins/core/imageprovider.h +18 -0
  69. data/ext/qml/plugins/core/imagerequestpromise.cpp +19 -0
  70. data/ext/qml/plugins/core/imagerequestpromise.h +21 -0
  71. data/ext/qml/plugins/core/qmlexception.cpp +11 -0
  72. data/ext/qml/plugins/core/qmlexception.h +17 -0
  73. data/ext/qml/plugins/testutil/objectlifechecker.cpp +17 -0
  74. data/ext/qml/plugins/testutil/objectlifechecker.h +24 -0
  75. data/ext/qml/plugins/testutil/ownershiptest.cpp +26 -0
  76. data/ext/qml/plugins/testutil/ownershiptest.h +30 -0
  77. data/ext/qml/plugins/testutil/testobject.cpp +6 -0
  78. data/ext/qml/plugins/testutil/testobject.h +108 -0
  79. data/ext/qml/plugins/testutil/testobjectsubclass.cpp +10 -0
  80. data/ext/qml/plugins/testutil/testobjectsubclass.h +19 -0
  81. data/ext/qml/plugins/testutil/testutil.pro +20 -0
  82. data/ext/qml/plugins/testutil/testutilplugin.cpp +47 -0
  83. data/ext/qml/plugins/testutil/testutilplugin.h +32 -0
  84. data/ext/qml/qmltyperegisterer.cpp +74 -0
  85. data/ext/qml/qmltyperegisterer.h +30 -0
  86. data/ext/qml/rubyclass.cpp +94 -0
  87. data/ext/qml/rubyclass.h +234 -0
  88. data/ext/qml/rubyvalue.cpp +690 -0
  89. data/ext/qml/rubyvalue.h +256 -0
  90. data/ext/qml/signalforwarder.cpp +66 -0
  91. data/ext/qml/signalforwarder.h +29 -0
  92. data/ext/qml/util.cpp +120 -0
  93. data/ext/qml/util.h +101 -0
  94. data/ext/qml/valuereference.cpp +50 -0
  95. data/ext/qml/valuereference.h +22 -0
  96. data/ext/qml/weakvaluereference.cpp +27 -0
  97. data/ext/qml/weakvaluereference.h +19 -0
  98. data/lib/qml.rb +41 -0
  99. data/lib/qml/access.rb +137 -0
  100. data/lib/qml/application.rb +139 -0
  101. data/lib/qml/class_builder.rb +126 -0
  102. data/lib/qml/component.rb +53 -0
  103. data/lib/qml/context.rb +71 -0
  104. data/lib/qml/data.rb +2 -0
  105. data/lib/qml/data/array_model.rb +103 -0
  106. data/lib/qml/data/error.rb +5 -0
  107. data/lib/qml/data/list_model.rb +146 -0
  108. data/lib/qml/dispatchable.rb +34 -0
  109. data/lib/qml/dispatcher.rb +61 -0
  110. data/lib/qml/engine.rb +54 -0
  111. data/lib/qml/error_converter.rb +15 -0
  112. data/lib/qml/errors.rb +26 -0
  113. data/lib/qml/geometry.rb +3 -0
  114. data/lib/qml/geometry/point.rb +5 -0
  115. data/lib/qml/geometry/rectangle.rb +5 -0
  116. data/lib/qml/geometry/size.rb +5 -0
  117. data/lib/qml/image_provider.rb +87 -0
  118. data/lib/qml/meta_object.rb +20 -0
  119. data/lib/qml/models.rb +1 -0
  120. data/lib/qml/name_helper.rb +12 -0
  121. data/lib/qml/platform.rb +15 -0
  122. data/lib/qml/plugin_loader.rb +46 -0
  123. data/lib/qml/plugins.rb +26 -0
  124. data/lib/qml/qml.rb +1 -0
  125. data/lib/qml/qt.rb +6 -0
  126. data/lib/qml/qt_classes.rb +9 -0
  127. data/lib/qml/qt_object_base.rb +108 -0
  128. data/lib/qml/reactive.rb +8 -0
  129. data/lib/qml/reactive/bindable.rb +79 -0
  130. data/lib/qml/reactive/chained_signal.rb +25 -0
  131. data/lib/qml/reactive/error.rb +5 -0
  132. data/lib/qml/reactive/object.rb +278 -0
  133. data/lib/qml/reactive/property.rb +19 -0
  134. data/lib/qml/reactive/signal.rb +116 -0
  135. data/lib/qml/reactive/signal_spy.rb +27 -0
  136. data/lib/qml/reactive/signals/map_signal.rb +21 -0
  137. data/lib/qml/reactive/signals/merge_signal.rb +21 -0
  138. data/lib/qml/reactive/signals/select_signal.rb +21 -0
  139. data/lib/qml/reactive/simple_property.rb +17 -0
  140. data/lib/qml/reactive/unbound_property.rb +42 -0
  141. data/lib/qml/reactive/unbound_signal.rb +51 -0
  142. data/lib/qml/root_path.rb +3 -0
  143. data/lib/qml/test_util.rb +1 -0
  144. data/lib/qml/test_util/object_life_checker.rb +17 -0
  145. data/lib/qml/version.rb +3 -0
  146. data/lib/qml/wrappable.rb +9 -0
  147. data/qml.gemspec +28 -0
  148. data/spec/assets/testobj.qml +5 -0
  149. data/spec/qml/.access_spec.rb.swp +0 -0
  150. data/spec/qml/access_spec.rb +162 -0
  151. data/spec/qml/application_spec.rb +43 -0
  152. data/spec/qml/component_spec.rb +44 -0
  153. data/spec/qml/context_spec.rb +43 -0
  154. data/spec/qml/conversion_spec.rb +59 -0
  155. data/spec/qml/data/array_model_spec.rb +215 -0
  156. data/spec/qml/dispatchable_spec.rb +26 -0
  157. data/spec/qml/dispatcher_spec.rb +48 -0
  158. data/spec/qml/geometry/point_spec.rb +4 -0
  159. data/spec/qml/geometry/rectangle_spec.rb +4 -0
  160. data/spec/qml/geometry/size_spec.rb +4 -0
  161. data/spec/qml/plugin_loader_spec.rb +33 -0
  162. data/spec/qml/qt_object_base_spec.rb +119 -0
  163. data/spec/qml/reactive/object_spec.rb +273 -0
  164. data/spec/qml/reactive/property_spec.rb +70 -0
  165. data/spec/qml/reactive/signal_spec.rb +191 -0
  166. data/spec/qml/reactive/signal_spy_spec.rb +26 -0
  167. data/spec/qml/test_object_spec.rb +186 -0
  168. data/spec/qml_spec.rb +7 -0
  169. data/spec/spec_helper.rb +5 -0
  170. metadata +321 -0
@@ -0,0 +1,256 @@
1
+ #pragma once
2
+ #include "util.h"
3
+ #include <ruby.h>
4
+ #include <array>
5
+
6
+ class QVariant;
7
+
8
+ namespace RubyQml {
9
+
10
+ namespace detail {
11
+ template <typename T, typename Enable = void> struct Conversion
12
+ {
13
+ static T from(RubyValue x);
14
+ static RubyValue to(typename std::conditional<std::is_scalar<T>::value, T, const T &>::type str);
15
+ };
16
+
17
+ }
18
+
19
+ #define RUBYQML_INTERN(str) \
20
+ [] { static auto id = rb_intern(str); return id; }()
21
+
22
+ class RubyModule;
23
+
24
+ class RubyValue
25
+ {
26
+ public:
27
+ RubyValue() = default;
28
+ RubyValue(VALUE value) : mValue(value) {}
29
+
30
+ template <typename T> static RubyValue from(const T &value)
31
+ {
32
+ return detail::Conversion<T>::to(value);
33
+ }
34
+
35
+ template <typename T> T to() const
36
+ {
37
+ return detail::Conversion<T>::from(*this);
38
+ }
39
+
40
+ operator VALUE() const { return mValue; }
41
+
42
+ template <typename ... TArgs>
43
+ RubyValue send(ID method, TArgs ... args) const
44
+ {
45
+ constexpr int argc = sizeof...(args);
46
+ std::array<VALUE, argc> argv = {{ VALUE(args)... }};
47
+ return protect([&] {
48
+ return rb_funcall2(mValue, method, argc, argv.data());
49
+ });
50
+ }
51
+
52
+ template <typename ... TArgs>
53
+ RubyValue send(const char *method, TArgs ... args) const
54
+ {
55
+ return send(rb_intern(method), args...);
56
+ }
57
+
58
+ bool operator==(const RubyValue &other) const { return mValue == other.mValue; }
59
+ bool operator!=(const RubyValue &other) const { return !operator==(other); }
60
+ explicit operator bool() const { return RTEST(mValue); }
61
+
62
+ bool isKindOf(const RubyModule &module) const;
63
+ bool isConvertibleTo(int metaType) const;
64
+ int defaultMetaType() const;
65
+
66
+ static RubyValue fromVariant(const QVariant &value);
67
+ QVariant toVariant() const;
68
+ QVariant toVariant(int type) const;
69
+ static RubyValue fromQObject(QObject *obj, bool implicit = true);
70
+ QObject *toQObject() const;
71
+
72
+ ID toID() const;
73
+ static RubyValue fromID(ID id) { return ID2SYM(id); }
74
+
75
+ static void addEnumeratorMetaType(int metaType);
76
+
77
+ private:
78
+ volatile VALUE mValue = Qnil;
79
+ };
80
+
81
+ namespace detail {
82
+
83
+ template <>
84
+ struct Conversion<RubyValue>
85
+ {
86
+ static RubyValue from(RubyValue x) { return x; }
87
+ static RubyValue to(RubyValue x) { return x; }
88
+ };
89
+
90
+ template <>
91
+ struct Conversion<bool>
92
+ {
93
+ static bool from(RubyValue value) { return value; }
94
+ static RubyValue to(bool x) { return x ? Qtrue : Qfalse; }
95
+ };
96
+
97
+ // signed integers
98
+
99
+ template <typename T>
100
+ struct Conversion<T, typename std::enable_if<std::is_signed<T>::value && std::is_integral<T>::value>::type>
101
+ {
102
+ static T from(RubyValue x)
103
+ {
104
+ return protect([&] {
105
+ return NUM2LL(x);
106
+ });
107
+ }
108
+ static RubyValue to(T x)
109
+ {
110
+ return LL2NUM(x);
111
+ }
112
+ };
113
+
114
+ // unsigned integers
115
+
116
+ template <typename T>
117
+ struct Conversion<T, typename std::enable_if<std::is_unsigned<T>::value && std::is_integral<T>::value>::type>
118
+ {
119
+ static T from(RubyValue x)
120
+ {
121
+ return protect([&] {
122
+ return NUM2ULL(x);
123
+ });
124
+ }
125
+ static RubyValue to(T x)
126
+ {
127
+ return ULL2NUM(x);
128
+ }
129
+ };
130
+
131
+ // floating point values
132
+
133
+ template <typename T>
134
+ struct Conversion<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
135
+ {
136
+ static T from(RubyValue x)
137
+ {
138
+ return protect([&] {
139
+ auto type = rb_type(x);
140
+ if (type == T_FIXNUM || type == T_BIGNUM) {
141
+ return double(NUM2LL(x));
142
+ } else {
143
+ return rb_float_value(x);
144
+ }
145
+ });
146
+ }
147
+ static RubyValue to(T x)
148
+ {
149
+ return rb_float_new(x);
150
+ }
151
+ };
152
+
153
+ // QList and QVector
154
+
155
+ template <class T> struct IsQListLike : std::false_type {};
156
+ template <class V> struct IsQListLike<QList<V>> : std::true_type {};
157
+ template <class V> struct IsQListLike<QVector<V>> : std::true_type {};
158
+
159
+ template <template<class> class T, class V>
160
+ struct Conversion<T<V>, typename std::enable_if<IsQListLike<T<V>>::value>::type>
161
+ {
162
+ static T<V> from(RubyValue x)
163
+ {
164
+ protect([&] {
165
+ x = rb_convert_type(x, T_ARRAY, "Array", "to_ary");
166
+ });
167
+ int length = RARRAY_LEN(VALUE(x));
168
+ T<V> list;
169
+ list.reserve(length);
170
+ for (int i = 0; i < length; ++i) {
171
+ list << RubyValue(RARRAY_AREF(VALUE(x), i)).to<V>();
172
+ }
173
+ return list;
174
+ }
175
+ static RubyValue to(const T<V> &list)
176
+ {
177
+ RubyValue ary = protect([&] {
178
+ return rb_ary_new();
179
+ });
180
+ for (const auto &elem : list) {
181
+ auto x = RubyValue::from(elem);
182
+ protect([&] {
183
+ rb_ary_push(ary, x);
184
+ });
185
+ }
186
+ return ary;
187
+ }
188
+ };
189
+
190
+ // QHash and QMap
191
+
192
+ template <class T> struct IsQHashLike : std::false_type {};
193
+ template <class K, class V> struct IsQHashLike<QHash<K, V>> : std::true_type {};
194
+ template <class K, class V> struct IsQHashLike<QMap<K, V>> : std::true_type {};
195
+
196
+ template <template<class, class> class T, class K, class V>
197
+ struct Conversion<T<K, V>, typename std::enable_if<IsQHashLike<T<K, V>>::value>::type>
198
+ {
199
+ static T<K, V> from(RubyValue x)
200
+ {
201
+ protect([&] {
202
+ x = rb_convert_type(x, T_HASH, "Hash", "to_hash");
203
+ });
204
+ T<K, V> hash;
205
+ protect([&] {
206
+ auto each = [](VALUE key, VALUE value, VALUE arg) -> int {
207
+ auto &hash = *reinterpret_cast<T<K, V> *>(arg);
208
+ unprotect([&] {
209
+ hash[RubyValue(key).to<K>()] = RubyValue(value).to<V>();
210
+ });
211
+ return ST_CONTINUE;
212
+ };
213
+ auto eachPtr = (int (*)(VALUE, VALUE, VALUE))each;
214
+ rb_hash_foreach(x, (int (*)(...))eachPtr, (VALUE)(&hash));
215
+ });
216
+ return hash;
217
+ }
218
+ static RubyValue to(const T<K, V> &hash)
219
+ {
220
+ RubyValue rubyHash = protect([&] {
221
+ return rb_hash_new();
222
+ });
223
+ for (auto i = hash.begin(); i != hash.end(); ++i) {
224
+ auto k = RubyValue::from(i.key());
225
+ auto v = RubyValue::from(i.value());
226
+ protect([&] {
227
+ rb_hash_aset(rubyHash, k, v);
228
+ });
229
+ }
230
+ return rubyHash;
231
+ }
232
+ };
233
+
234
+ // QObject-derived
235
+
236
+ template <typename T>
237
+ struct Conversion<
238
+ T *,
239
+ typename std::enable_if<
240
+ std::is_base_of<QObject, T>::value
241
+ >::type
242
+ >
243
+ {
244
+ static T *from(RubyValue value) { return dynamic_cast<T *>(value.toQObject()); }
245
+ static RubyValue to(T *value) { return RubyValue::fromQObject(value); }
246
+ };
247
+
248
+ template <>
249
+ struct Conversion<const char *>
250
+ {
251
+ static RubyValue to(const char *str);
252
+ };
253
+
254
+ } // namespace detail
255
+
256
+ } // namespace RubyQml
@@ -0,0 +1,66 @@
1
+ #include "signalforwarder.h"
2
+ #include "util.h"
3
+ #include <QtCore/QDebug>
4
+
5
+ namespace RubyQml {
6
+
7
+ SignalForwarder::SignalForwarder(QObject *obj, const QMetaMethod &signal, RubyValue proc) :
8
+ QObject(obj),
9
+ mSignal(signal),
10
+ mProcRef(proc)
11
+ {
12
+ QMetaObject::connect(obj, signal.methodIndex(), this, QObject::staticMetaObject.methodCount());
13
+ }
14
+
15
+ SignalForwarder::~SignalForwarder()
16
+ {
17
+ }
18
+
19
+ int SignalForwarder::qt_metacall(QMetaObject::Call call, int id, void **args)
20
+ {
21
+ id = QObject::qt_metacall(call, id, args);
22
+ if (id < 0) {
23
+ return id;
24
+ }
25
+ if (call == QMetaObject::InvokeMetaMethod) {
26
+ if (id == 0) {
27
+ forwardArgs(args);
28
+ }
29
+ --id;
30
+ }
31
+ return id;
32
+ }
33
+
34
+ void SignalForwarder::gc_mark()
35
+ {
36
+ rb_gc_mark(mProcRef.value());
37
+ }
38
+
39
+ void SignalForwarder::forwardArgs(void **args)
40
+ {
41
+ QVariantList list;
42
+ list.reserve(mSignal.parameterCount());
43
+ for (int i = 0; i < mSignal.parameterCount(); ++i) {
44
+ auto type = mSignal.parameterType(i);
45
+ if (type == QMetaType::QVariant) {
46
+ list << *static_cast<QVariant *>(args[i + 1]);
47
+ } else {
48
+ list << QVariant(type, args[i + 1]);
49
+ }
50
+ }
51
+ callProc(list);
52
+ }
53
+
54
+ void SignalForwarder::callProc(const QVariantList &list)
55
+ {
56
+ if (mProcRef.hasValue()) {
57
+ withGvl([&] {
58
+ auto args = RubyValue::from(list);
59
+ protect([&] {
60
+ rb_funcall2(mProcRef.value(), rb_intern("call"), RARRAY_LEN(VALUE(args)), RARRAY_PTR(VALUE(args)));
61
+ });
62
+ });
63
+ }
64
+ }
65
+
66
+ } // namespace RubyQml
@@ -0,0 +1,29 @@
1
+ #pragma once
2
+ #include "rubyvalue.h"
3
+ #include "weakvaluereference.h"
4
+ #include "markable.h"
5
+ #include <QObject>
6
+ #include <QMetaMethod>
7
+
8
+ namespace RubyQml {
9
+
10
+ class SignalForwarder : public QObject, public Markable
11
+ {
12
+ public:
13
+ SignalForwarder(QObject *obj, const QMetaMethod &signal, RubyValue proc);
14
+ ~SignalForwarder();
15
+
16
+ int qt_metacall(QMetaObject::Call call, int id, void **args) override;
17
+
18
+ void gc_mark() override;
19
+
20
+ private:
21
+ void forwardArgs(void **args);
22
+ void callProc(const QVariantList &list);
23
+
24
+ QMetaMethod mSignal;
25
+ WeakValueReference mProcRef;
26
+ };
27
+
28
+ } // namespace RubyQml
29
+
@@ -0,0 +1,120 @@
1
+ #include "util.h"
2
+ #include "rubyvalue.h"
3
+ #include <QString>
4
+ #include <ruby/thread.h>
5
+ #include <string>
6
+ #include <memory>
7
+ #include <cxxabi.h>
8
+
9
+ namespace RubyQml {
10
+
11
+ void protect(const std::function<void ()> &doAction)
12
+ {
13
+ auto callback = [](VALUE data) {
14
+ auto &doAction= *reinterpret_cast<const std::function<void ()> *>(data);
15
+ doAction();
16
+ return Qnil;
17
+ };
18
+ int state;
19
+ rb_protect(callback, reinterpret_cast<VALUE>(&doAction), &state);
20
+ if (state) {
21
+ throw RubyException(state);
22
+ }
23
+ }
24
+
25
+ void unprotect(const std::function<void ()> &doAction) noexcept
26
+ {
27
+ int state = 0;
28
+ bool cppErrorOccured= false;
29
+ VALUE cppErrorClassName = Qnil;
30
+ VALUE cppErrorMessage = Qnil;
31
+ try {
32
+ doAction();
33
+ }
34
+ catch (const RubyException &ex) {
35
+ state = ex.state();
36
+ }
37
+ catch (const std::exception &ex) {
38
+ cppErrorOccured = true;
39
+ int status;
40
+ auto classname = abi::__cxa_demangle(typeid(ex).name(), nullptr, nullptr, &status);
41
+ cppErrorClassName = rb_str_new_cstr(classname);
42
+ free(classname);
43
+ cppErrorMessage = rb_str_new_cstr(ex.what());
44
+ }
45
+ if (state) {
46
+ rb_jump_tag(state);
47
+ }
48
+ if (cppErrorOccured) {
49
+ auto patterns = rb_funcall(rb_path2class("QML::ErrorConverter"), rb_intern("patterns"), 0);
50
+ auto rubyClass = rb_hash_aref(patterns, cppErrorClassName);
51
+ VALUE exc;
52
+ if (RTEST(rubyClass)) {
53
+ exc = rb_funcall(rubyClass, rb_intern("new"), 1, cppErrorMessage);
54
+ } else {
55
+ exc = rb_funcall(rb_path2class("QML::CppError"), rb_intern("new"), 2, cppErrorClassName, cppErrorMessage);
56
+ }
57
+ rb_exc_raise(exc);
58
+ }
59
+ }
60
+
61
+ void rescue(const std::function<void ()> &doAction, const std::function<void (RubyValue)> &handleException)
62
+ {
63
+ VALUE (*callback)(VALUE) = [](VALUE data) {
64
+ (*reinterpret_cast<std::function<void ()> *>(data))();
65
+ return Qnil;
66
+ };
67
+ VALUE (*rescueCallback)(VALUE, VALUE) = [](VALUE data, VALUE excObject) {
68
+ (*reinterpret_cast<std::function<void (VALUE)>*>(data))(excObject);
69
+ return Qnil;
70
+ };
71
+ rb_rescue((VALUE (*)(...))callback, (VALUE)&doAction, (VALUE (*)(...))rescueCallback, (VALUE)&handleException);
72
+ }
73
+
74
+ namespace {
75
+
76
+ void changeGvl(const std::function<void ()> &doAction, bool gvl)
77
+ {
78
+ auto actionPtr = const_cast<void *>(static_cast<const void *>(&doAction));
79
+ auto f = [](void *data) -> void * {
80
+ auto &doAction= *static_cast<const std::function<void ()> *>(data);
81
+ try {
82
+ doAction();
83
+ } catch (...) {
84
+ return new std::exception_ptr(std::current_exception());
85
+ }
86
+ return nullptr;
87
+ };
88
+ void *result;
89
+ if (gvl) {
90
+ result = rb_thread_call_with_gvl(f, actionPtr );
91
+ } else {
92
+ result = rb_thread_call_without_gvl(f, actionPtr , RUBY_UBF_IO, nullptr);
93
+ }
94
+ std::unique_ptr<std::exception_ptr> exc(static_cast<std::exception_ptr *>(result));
95
+ if (exc && *exc) {
96
+ std::rethrow_exception(*exc);
97
+ }
98
+ }
99
+
100
+ }
101
+
102
+ void withoutGvl(const std::function<void ()> &doAction)
103
+ {
104
+ changeGvl(doAction, false);
105
+ }
106
+
107
+ void withGvl(const std::function<void ()> &doAction)
108
+ {
109
+ changeGvl(doAction, true);
110
+ }
111
+
112
+ void fail(const char *errorClassName, const QString &message)
113
+ {
114
+ auto msg = message.toUtf8();
115
+ protect([&] {
116
+ rb_raise(rb_path2class(errorClassName), "%s", msg.data());
117
+ });
118
+ }
119
+
120
+ }