#include "dynamicmetaobjectdata.h"
#include "dispatchmetacallcpp.h"
#include "rustconv.h"
#include <QtLogging>
void DynamicMetaObjectData::addProperty(uint32_t userId, const QMetaType& metaType)
{
m_properties.push_back(PropertyInfo{ userId, metaType });
}
void DynamicMetaObjectData::addSignal(const QByteArray& name)
{
m_signals.push_back(SignalInfo{ name });
}
void DynamicMetaObjectData::addSlot(uint32_t userId, Mutability mutability)
{
m_slots.push_back(SlotInfo{ userId, mutability });
}
void DynamicMetaObjectData::emitSignal(QObject& obj, rust::Str name, rust::Slice<const uint8_t* const> argvSlice) const
{
const QByteArray signalName = RustStrToQByteArray(name);
if (auto index = getSignalIndex(signalName))
{
auto argv = reinterpret_cast<void**>(const_cast<uint8_t**>(argvSlice.data()));
QMetaObject::activate(&obj, m_metaObject.get(), *index, argv);
}
else
qFatal() << "Failed to find signal " << signalName << " by name";
}
std::optional<int> DynamicMetaObjectData::getSignalIndex(const QByteArray& name) const
{
const size_t size = static_cast<size_t>(m_signals.size());
for (size_t index = 0u; index < size; ++index)
{
if (m_signals[index].m_name == name)
return index;
}
return std::nullopt;
}
void DynamicMetaObjectData::setMetaObject(std::unique_ptr<QMetaObject, QScopedPointerPodDeleter> metaObject)
{
m_metaObject = std::move(metaObject);
}
bool DynamicMetaObjectData::isMetaObjectSet() const
{
return static_cast<bool>(m_metaObject);
}
QMetaObject* DynamicMetaObjectData::getMetaObject() const
{
return m_metaObject.get();
}
void DynamicMetaObjectData::objectDestroyed(QObject *)
{
}
QMetaObject* DynamicMetaObjectData::toDynamicMetaObject(QObject* )
{
return getMetaObject();
}
int DynamicMetaObjectData::metaCall(QObject* o, QMetaObject::Call call, int id, void** argv)
{
if (!m_metaObject)
qFatal() << __func__ << "() called before setMetaObject()";
auto dispatch = dynamic_cast<DispatchMetaCallCpp*>(o);
if (!dispatch)
qFatal("Failed to get pointer to QObject handling meta call");
switch (call)
{
case QMetaObject::InvokeMetaMethod:
if (handleMetaCallInvoke(o, *dispatch, id, argv))
return -1;
break;
case QMetaObject::ReadProperty:
if (handleMetaCallReadProperty(*dispatch, id, argv))
return -1;
break;
case QMetaObject::WriteProperty:
if (handleMetaCallWriteProperty(*dispatch, id, argv))
return -1;
break;
default:
break;
}
return o->qt_metacall(call, id, argv);
}
bool DynamicMetaObjectData::handleMetaCallInvoke(QObject* o, DispatchMetaCallCpp& dispatch, int id, void** argv)
{
const int methodId = id - m_metaObject->methodOffset();
if (methodId < 0 || methodId >= m_metaObject->methodCount())
return false;
if (methodId < m_signals.size())
{
QMetaObject::activate(o, id, argv);
return true;
}
const int slotId = methodId - m_signals.size();
if (slotId >= m_slots.size())
return false;
const SlotInfo& slotInfo = m_slots[slotId];
QMetaMethod method = m_metaObject->method(id);
const int paramCount = method.parameterCount();
const QMetaType returnType = method.returnMetaType();
if ((paramCount > 0 || returnType.isValid()) && !argv)
qFatal() << __func__ << "(): input meta params are null";
uint8_t* const* u8Argv = reinterpret_cast<uint8_t* const*>(argv);
const uint8_t* const* inputsBegin = u8Argv + 1;
rust::Slice inputsSlice(inputsBegin, static_cast<size_t>(paramCount));
auto outputSlice = returnType.isValid() ?
rust::Slice<uint8_t* const>(u8Argv, 1) :
rust::Slice<uint8_t* const>();
const uint32_t userId = slotInfo.m_userId;
slotInfo.m_mutability == Mutability::Mutable ?
dispatch.invokeSlotMut(userId, inputsSlice, outputSlice) :
dispatch.invokeSlot(userId, inputsSlice, outputSlice);
return true;
}
bool DynamicMetaObjectData::handleMetaCallReadProperty(const DispatchMetaCallCpp& dispatch, int id, void** argv)
{
const int propId = id - m_metaObject->propertyOffset();
if (propId < 0 || propId >= m_metaObject->propertyCount())
return false; if (propId >= m_properties.size())
return false;
const PropertyInfo& propInfo = m_properties[propId];
void* dstArg = argv[0];
if (!dstArg)
return false;
const QMetaProperty property = m_metaObject->property(id);
const QVariant result = dispatch.readProperty(propInfo.m_userId);
if (!QMetaType::convert(result.metaType(), result.data(), property.metaType(), dstArg))
qFatal() << "Property type mismatch";
return true;
}
bool DynamicMetaObjectData::handleMetaCallWriteProperty(DispatchMetaCallCpp& dispatch, int id, void** argv)
{
const int propId = id - m_metaObject->propertyOffset();
if (propId < 0 || propId >= m_metaObject->propertyCount())
return false; if (propId >= m_properties.size())
return false;
const PropertyInfo& propInfo = m_properties[propId];
void* arg = argv[0];
if (!arg)
return false;
const QMetaProperty property = m_metaObject->property(id);
const QVariant value = QVariant::fromMetaType(property.metaType(), arg);
dispatch.writeProperty(propInfo.m_userId, value);
return true;
}