qml 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }