1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
#include "qml_method_invoker.h"
#include "rustconv.h"
#include <QMetaMethod>
void connect_destroyed_callback(QObject *obj, std::uintptr_t flag_ptr)
{
QObject::connect(obj, &QObject::destroyed, [flag_ptr](QObject *) {
on_qobject_destroyed(flag_ptr);
});
}
bool invoke_method(QObject *obj, rust::Str name, const QList<QVariant> &args)
{
const QByteArray nameBa = RustStrToQByteArray(name);
const QMetaObject *mo = obj->metaObject();
const int argCount = static_cast<int>(args.size());
if (argCount > 10)
return false;
// Traverse from the most-derived meta-object down to the base. Method
// indices are laid out base-first, so scanning high -> low visits
// QML-added members first, then Rust, then the C++ base. A candidate
// matches when its name and parameter count match and every argument
// actually converts to the corresponding parameter type; converting is the
// selection test, so a candidate whose arguments don't convert is skipped
// in favour of a less-derived one.
for (int i = mo->methodCount() - 1; i >= 0; --i) {
const QMetaMethod method = mo->method(i);
if (method.name() != nameBa || method.parameterCount() != argCount)
continue;
QVariant converted[10];
bool matches = true;
for (int k = 0; k < argCount; ++k) {
converted[k] = args.at(k);
// canConvert() can be misleading: it reports whether a conversion
// between the two types exists at all, not whether this particular
// value converts. For example a QString may be convertible to int in
// principle, but only convert() tells us whether the actual value
// converts.
if (!converted[k].convert(method.parameterMetaType(k))) {
matches = false;
break;
}
}
if (!matches)
continue;
QGenericArgument gargs[10];
for (int k = 0; k < argCount; ++k)
gargs[k] = QGenericArgument(method.parameterMetaType(k).name(), converted[k].data());
// Invoke by index so a same-named member cannot be re-resolved on the call.
return method.invoke(obj, Qt::QueuedConnection, gargs[0], gargs[1], gargs[2],
gargs[3], gargs[4], gargs[5], gargs[6], gargs[7], gargs[8],
gargs[9]);
}
return false;
}