#pragma once
#include <QtCore/QObject>
#include <QtCore/QEvent>
#include <QtCore/QDebug>
using QObjectErasedMethod = void (QObject::*)();
union SignalInner {
private:
ptrdiff_t rust_field_offset;
QObjectErasedMethod cpp_erased_method;
public:
explicit SignalInner(ptrdiff_t field_offset)
: rust_field_offset(field_offset)
{}
template<typename R, typename Type, typename ...Args>
SignalInner(R (Type::* qt_signal)(Args...))
: cpp_erased_method(*reinterpret_cast<QObjectErasedMethod *>(&qt_signal))
{}
void **asRawSignal() {
return reinterpret_cast<void **>(&cpp_erased_method);
}
};
struct TraitObject {
void *data;
void *vtable;
bool isValid() const {
return data && vtable;
}
inline void invalidate() {
data = nullptr;
vtable = nullptr;
}
};
extern "C" QMetaObject *RustObject_metaObject(TraitObject);
extern "C" void RustObject_destruct(TraitObject);
static constexpr int QtJambi_EventType_DeleteOnMainThread = 513;
template <typename Base>
struct RustObject : Base {
TraitObject rust_object; TraitObject ptr_qobject; void (*extra_destruct)(QObject *);
const QMetaObject *metaObject() const override {
return ptr_qobject.isValid() ? RustObject_metaObject(ptr_qobject) : Base::metaObject();
}
int qt_metacall(QMetaObject::Call _c, int _id, void **_a) override {
_id = Base::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
const QMetaObject *mo = metaObject();
if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) {
int methodCount = mo->methodCount();
if (_id < methodCount)
mo->d.static_metacall(this, _c, _id, _a);
_id -= methodCount;
} else if ((_c >= QMetaObject::ReadProperty && _c <=
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QMetaObject::QueryPropertyUser
#else
QMetaObject::ResetProperty
#endif
) || _c == QMetaObject::RegisterPropertyMetaType) {
int propertyCount = mo->propertyCount();
if (_id < propertyCount)
mo->d.static_metacall(this, _c, _id, _a);
_id -= propertyCount;
}
return _id;
}
bool event(QEvent *event) override {
if (ptr_qobject.isValid() && event->type() == QtJambi_EventType_DeleteOnMainThread) {
ptr_qobject.invalidate(); delete this;
return true;
}
return Base::event(event);
}
~RustObject() {
auto r = ptr_qobject;
ptr_qobject.invalidate();
if (extra_destruct)
extra_destruct(this);
if (r.isValid())
RustObject_destruct(r);
}
};
struct RustQObjectDescriptor {
size_t size;
const QMetaObject *baseMetaObject;
QObject *(*create)(const TraitObject *, const TraitObject *);
void (*qmlConstruct)(void *, const TraitObject *, const TraitObject *, void (*extra_destruct)(QObject *));
TraitObject (*get_rust_refcell)(QObject *);
template<typename T>
static const RustQObjectDescriptor *instance();
};
template<typename T>
const RustQObjectDescriptor *RustQObjectDescriptor::instance() {
static RustQObjectDescriptor desc {
sizeof(T),
&T::staticMetaObject,
[](
const TraitObject *self_pinned,
const TraitObject *self_ptr
) -> QObject * {
auto q = new T();
q->ptr_qobject = *self_ptr;
q->rust_object = *self_pinned;
return q;
},
[](
void *data,
const TraitObject *self_pinned,
const TraitObject *self_ptr,
void (*extra_destruct)(QObject *)
) {
auto *q = new (data) T();
q->rust_object = *self_pinned;
q->ptr_qobject = *self_ptr;
q->extra_destruct = extra_destruct;
},
[](QObject *q) {
return static_cast<T *>(q)->ptr_qobject;
}
};
return &desc;
}