diff --git a/CMakeLists.txt b/CMakeLists.txt index fd20dfa..9933c21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,28 +15,13 @@ include(KDECMakeSettings) include(KDECompilerSettings) include(FeatureSummary) -#add_custom_target(rust -# OUTPUT "${CMAKE_SOURCE_DIR}/target/debug/librust.a" -# COMMAND cargo build -# COMMAND cargo build --release -# DEPENDS - set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/Rust) -ExternalProject_Add( - rust - DOWNLOAD_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND cargo build - COMMAND cargo build --release - BINARY_DIR "${CMAKE_SOURCE_DIR}/common-rust" - INSTALL_COMMAND "" - LOG_BUILD ON) - # Find Qt modules find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core # QCommandLineParser, QStringLiteral Quick + Test Widgets # QApplication ) @@ -51,12 +36,38 @@ feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAG add_subdirectory(rust_qt_binding_generator) - +string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_UPPER) +if(CMAKE_BUILD_TYPE_UPPER STREQUAL DEBUG) + set(RUST_TARGET_DIR target/debug/) + set(RUST_BUILD_FLAG) +else() + set(RUST_TARGET_DIR target/release/) + set(RUST_BUILD_FLAG --release) +endif() + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/common-rust/src/testinterface.rs" + COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/bindings.json" + DEPENDS rust_qt_binding_generator bindings.json +) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/common-rust/${RUST_TARGET_DIR}/librust.a" + COMMAND cargo build ${RUST_BUILD_FLAG} + DEPENDS common-rust/src/lib.rs + common-rust/src/testimplementation.rs + common-rust/src/testinterface.rs + common-rust/src/implementation.rs + common-rust/src/interface.rs + common-rust/src/types.rs + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/common-rust" +) +add_custom_target(rust_target DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/common-rust/${RUST_TARGET_DIR}/librust.a") + set(RMail_SRCS src/main.cpp src/RMailObject.cpp src/tmp.cpp) add_executable(RMail ${RMail_SRCS}) - -add_dependencies(RMail rust) +add_dependencies(RMail rust_target) target_link_libraries(RMail Qt5::Quick @@ -64,8 +75,7 @@ target_link_libraries(RMail KF5::CoreAddons KF5::I18n KF5::WidgetsAddons - debug "${CMAKE_SOURCE_DIR}/common-rust/target/debug/librust.a" - optimized "${CMAKE_SOURCE_DIR}/common-rust/target/release/librust.a" + "${CMAKE_CURRENT_SOURCE_DIR}/common-rust/${RUST_TARGET_DIR}/librust.a" ) set_target_properties(RMail PROPERTIES @@ -74,3 +84,6 @@ set_target_properties(RMail PROPERTIES ) install(TARGETS RMail ${INSTALL_TARGETS_DEFAULT_ARGS}) + +add_subdirectory(tests) + diff --git a/dev b/dev index 3f00c6c..0aa4423 100644 --- a/dev +++ b/dev @@ -1,3 +1,3 @@ #!/usr/bin/bash rm -rf __nix_qt5__/ -nix-shell -p qtcreator cmake ninja gcc rustc cargo qt5.full extra-cmake-modules kdeFrameworks.kwidgetsaddons kdeFrameworks.kcoreaddons kdeFrameworks.ki18n appstream +nix-shell -p qtcreator cmake ninja gcc rustc cargo qt5.full extra-cmake-modules kdeFrameworks.kwidgetsaddons kdeFrameworks.kcoreaddons kdeFrameworks.ki18n appstream cmakeCurses diff --git a/rust_qt_binding_generator/rust_qt_binding_generator.cpp b/rust_qt_binding_generator/rust_qt_binding_generator.cpp index 2f38ea3..e0edc84 100644 --- a/rust_qt_binding_generator/rust_qt_binding_generator.cpp +++ b/rust_qt_binding_generator/rust_qt_binding_generator.cpp @@ -100,6 +100,7 @@ parseConfiguration(const QString& path) { const QJsonObject o = doc.object(); Configuration c; c.cppFile = QFileInfo(base, o.value("cppFile").toString()); + QDir(c.cppFile.dir()).mkpath("."); c.hFile = QFileInfo(c.cppFile.dir(), c.cppFile.completeBaseName() + ".h"); for (const QJsonValue& val: o.value("objects").toArray()) { c.objects.append(parseObject(val.toObject())); diff --git a/src/main.cpp b/src/main.cpp index 37efb4f..2b44d2c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,7 +62,7 @@ int main (int argc, char *argv[]) view.show(); engine.rootContext()->setContextProperty("fsModel", &model); - engine.load(QUrl(QStringLiteral("test.qml"))); + engine.load(QUrl(QStringLiteral("../test.qml"))); return app.exec(); /* diff --git a/src/tmp.cpp b/src/tmp.cpp new file mode 100644 index 0000000..910d0c9 --- /dev/null +++ b/src/tmp.cpp @@ -0,0 +1,275 @@ +/* generated by rust_qt_binding_generator */ +#include "tmp.h" +#include + +namespace { + struct qbytearray_t { + private: + const char* data; + int len; + public: + qbytearray_t(const QByteArray& v): + data(v.data()), + len(v.size()) { + } + operator QByteArray() const { + return QByteArray(data, len); + } + }; + struct qstring_t { + private: + const void* data; + int len; + public: + qstring_t(const QString& v): + data(static_cast(v.utf16())), + len(v.size()) { + } + operator QString() const { + return QString::fromUtf8(static_cast(data), len); + } + }; + struct qmodelindex_t { + int row; + int column; + uint64_t id; + qmodelindex_t(const QModelIndex& m): + row(m.row()), column(m.column()), id(m.internalId()) {} + }; + struct qvariant_t { + unsigned int type; + int value; + const char* data; + }; + QVariant variant(const qvariant_t& v) { + switch (v.type) { + case QVariant::Bool: return QVariant((bool)v.value); + case QVariant::String: return QString::fromUtf8(static_cast(v.data), v.value); + default:; + } + return QVariant(); + } + void variant(const QByteArray& v, void* d, void (*set)(void*, qvariant_t)) { + set(d, { + .type = QVariant::ByteArray, + .value = v.length(), + .data = v.data() + }); + } + void variant(const QString& v, void* d, void (*set)(void*, qvariant_t)) { + set(d, { + .type = QVariant::String, + .value = v.size(), + .data = static_cast(static_cast(v.utf16())) + }); + } + void variant(const QVariant& v, void* d, void (*set)(void*, qvariant_t)) { + switch (v.type()) { + case QVariant::Bool: + set(d, { + .type = QVariant::Bool, + .value = v.toBool(), + .data = 0 + }); + break; + case QVariant::Int: + set(d, { + .type = QVariant::Int, + .value = v.toInt(), + .data = 0 + }); + break; + case QVariant::ByteArray: + variant(v.toByteArray(), d, set); + break; + case QVariant::String: + variant(v.toString(), d, set); + break; + default: + set(d, { + .type = QVariant::Invalid, + .value = 0, + .data = 0 + }); + } + } +} +typedef void (*qstring_set)(QString*, qstring_t*); +void set_qstring(QString* v, qstring_t* val) { + *v = *val; +} +typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); +void set_qbytearray(QByteArray* v, qbytearray_t* val) { + *v = *val; +} +typedef void (*qvariant_set)(QVariant*, qvariant_t*); +void set_qvariant(QVariant* v, qvariant_t* val) { + *v = variant(*val); +} + +extern "C" { + PersonInterface* person_new(Person*, void (*)(Person*), void (*)(Person*), void (*)(Person*), void (*)(Person*), void (*)(Person*)); + void person_free(PersonInterface*); + void person_user_name_get(PersonInterface*, QString*, qstring_set); + void person_user_name_set(void*, qstring_t); + int person_age_get(PersonInterface*); + bool person_active_get(PersonInterface*); + void person_active_set(void*, bool); + void person_misc_get(PersonInterface*, QVariant*, qvariant_set); + void person_misc_set(void*, qvariant_t); + void person_icon_get(PersonInterface*, QByteArray*, qbytearray_set); + void person_icon_set(void*, qbytearray_t); + DirectoryInterface* directory_new(Directory*, void (*)(Directory*), + void (*)(Directory*, int, int), + void (*)(Directory*), + void (*)(Directory*, int, int), + void (*)(Directory*)); + void directory_free(DirectoryInterface*); + void directory_path_get(DirectoryInterface*, QString*, qstring_set); + void directory_path_set(void*, qstring_t); +}; +Person::Person(QObject *parent): + QObject(parent), + d(person_new(this, + [](Person* o) { emit o->userNameChanged(); }, + [](Person* o) { emit o->ageChanged(); }, + [](Person* o) { emit o->activeChanged(); }, + [](Person* o) { emit o->miscChanged(); }, + [](Person* o) { emit o->iconChanged(); })) {} + +Person::~Person() { + person_free(d); +} +QString Person::userName() const +{ + QString v; + person_user_name_get(d, &v, set_qstring); + return v; +} +void Person::setUserName(const QString& v) { + person_user_name_set(d, v); +} +int Person::age() const +{ + return person_age_get(d); +} +bool Person::active() const +{ + return person_active_get(d); +} +void Person::setActive(bool v) { + person_active_set(d, v); +} +QVariant Person::misc() const +{ + QVariant v; + person_misc_get(d, &v, set_qvariant); + return v; +} +void Person::setMisc(const QVariant& v) { + variant(v, d, person_misc_set); +} +QByteArray Person::icon() const +{ + QByteArray v; + person_icon_get(d, &v, set_qbytearray); + return v; +} +void Person::setIcon(const QByteArray& v) { + person_icon_set(d, v); +} +Directory::Directory(QObject *parent): + QAbstractItemModel(parent), + d(directory_new(this, + [](Directory* o) { emit o->pathChanged(); }, + [](Directory* o, int first, int last) { + emit o->beginInsertRows(QModelIndex(), first, last); + }, + [](Directory* o) { + emit o->endInsertRows(); + }, + [](Directory* o, int first, int last) { + emit o->beginRemoveRows(QModelIndex(), first, last); + }, + [](Directory* o) { + emit o->endRemoveRows(); + } +)) {} + +Directory::~Directory() { + directory_free(d); +} +QString Directory::path() const +{ + QString v; + directory_path_get(d, &v, set_qstring); + return v; +} +void Directory::setPath(const QString& v) { + directory_path_set(d, v); +} +enum DirectoryRole { + DirectoryRoleFileIcon = Qt::DecorationRole, + DirectoryRoleFilePath = Qt::UserRole + 1, + DirectoryRoleFileName = Qt::UserRole + 2, + DirectoryRoleFilePermissions = Qt::UserRole + 3, +}; + +extern "C" { + void directory_data_file_icon(DirectoryInterface*, int, QVariant*, qvariant_set); + void directory_data_file_path(DirectoryInterface*, int, QVariant*, qvariant_set); + void directory_data_file_name(DirectoryInterface*, int, QVariant*, qvariant_set); + void directory_data_file_permissions(DirectoryInterface*, int, QVariant*, qvariant_set); + + int directory_row_count(DirectoryInterface*, qmodelindex_t parent); +} +int Directory::columnCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : 1; +} + +int Directory::rowCount(const QModelIndex &parent) const +{ + return (parent.isValid()) ? 0 : directory_row_count(d, parent); +} + +QModelIndex Directory::index(int row, int column, const QModelIndex &parent) const +{ + if (!parent.isValid() && column == 0) { + return createIndex(row, 0, (quintptr)0); + } + return QModelIndex(); +} + +QModelIndex Directory::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +QVariant Directory::data(const QModelIndex &index, int role) const +{ + QVariant v; + switch ((DirectoryRole)role) { + case DirectoryRoleFileIcon: + directory_data_file_icon(d, index.row(), &v, set_qvariant); + break; + case DirectoryRoleFilePath: + directory_data_file_path(d, index.row(), &v, set_qvariant); + break; + case DirectoryRoleFileName: + directory_data_file_name(d, index.row(), &v, set_qvariant); + break; + case DirectoryRoleFilePermissions: + directory_data_file_permissions(d, index.row(), &v, set_qvariant); + break; + } + return v; +} +QHash Directory::roleNames() const { + QHash names; + names.insert(Qt::DecorationRole, "FileIcon"); + names.insert(Qt::UserRole + 1, "FilePath"); + names.insert(Qt::UserRole + 2, "FileName"); + names.insert(Qt::UserRole + 3, "FilePermissions"); + return names; +} \ No newline at end of file diff --git a/src/tmp.h b/src/tmp.h new file mode 100644 index 0000000..c81b52d --- /dev/null +++ b/src/tmp.h @@ -0,0 +1,70 @@ +/* generated by rust_qt_binding_generator */ +#ifndef TMP_H +#define TMP_H + +#include +#include +#include + +class PersonInterface; +class Person : public QObject +{ + Q_OBJECT + PersonInterface * const d; + Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged FINAL) + Q_PROPERTY(int age READ age NOTIFY ageChanged FINAL) + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged FINAL) + Q_PROPERTY(QVariant misc READ misc WRITE setMisc NOTIFY miscChanged FINAL) + Q_PROPERTY(QByteArray icon READ icon WRITE setIcon NOTIFY iconChanged FINAL) +public: + explicit Person(QObject *parent = nullptr); + ~Person(); + QString userName() const; + void setUserName(const QString& v); + int age() const; + bool active() const; + void setActive(bool v); + QVariant misc() const; + void setMisc(const QVariant& v); + QByteArray icon() const; + void setIcon(const QByteArray& v); +signals: + void userNameChanged(); + void ageChanged(); + void activeChanged(); + void miscChanged(); + void iconChanged(); +private: + QString m_userName; + int m_age; + bool m_active; + QVariant m_misc; + QByteArray m_icon; +}; + +class DirectoryInterface; +class Directory : public QAbstractItemModel +{ + Q_OBJECT + DirectoryInterface * const d; + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged FINAL) +public: + explicit Directory(QObject *parent = nullptr); + ~Directory(); + QString path() const; + void setPath(const QString& v); + + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent) const; + QHash roleNames() const; +signals: + void newDataReady(); +signals: + void pathChanged(); +private: + QString m_path; +}; +#endif // TMP_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..c6b3687 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,33 @@ +enable_testing() + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/src/interface.rs" + COMMAND "${CMAKE_COMMAND}" -E remove "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/src/implementation.rs" + COMMAND ${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator "${CMAKE_CURRENT_SOURCE_DIR}/test_object.json" + DEPENDS rust_qt_binding_generator test_object.json +) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/${RUST_TARGET_DIR}/librust.a" + COMMAND cargo build ${RUST_BUILD_FLAG} + DEPENDS rust_object/src/lib.rs + rust_object/src/implementation.rs + rust_object/src/interface.rs + rust_object/src/types.rs + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/rust_object" +) +add_custom_target(test_rust_object DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/${RUST_TARGET_DIR}/librust.a") + +add_executable(test_object test_object.cpp test_object_rust.cpp) +add_dependencies(test_object test_rust_object) +target_link_libraries(test_object + Qt5::Core + Qt5::Test + "${CMAKE_CURRENT_SOURCE_DIR}/rust_object/${RUST_TARGET_DIR}/librust.a" +) + +add_test(remove_test_object "${CMAKE_COMMAND}" -E remove test_object) +add_test(build_test_object "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target test_object) +set_tests_properties(build_test_object PROPERTIES DEPENDS remove_test_object) +add_test(test_object test_object) +set_tests_properties(test_object PROPERTIES DEPENDS build_test_object) diff --git a/tests/rust_object/Cargo.toml b/tests/rust_object/Cargo.toml new file mode 100644 index 0000000..b52f0f0 --- /dev/null +++ b/tests/rust_object/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust_object" +version = "1.0.0" + +[dependencies] +libc = "*" + +[lib] +name = "rust" +crate-type = ["staticlib"] diff --git a/tests/rust_object/src/implementation.rs b/tests/rust_object/src/implementation.rs new file mode 100644 index 0000000..2bd6f1e --- /dev/null +++ b/tests/rust_object/src/implementation.rs @@ -0,0 +1,27 @@ +use libc::c_int; +use types::*; +use interface::*; + +pub struct Person { + emit: PersonEmitter, + user_name: String, +} + +impl PersonTrait for Person { + fn create(emit: PersonEmitter) -> Person { + Person { + emit: emit, + user_name: String::new(), + } + } + fn emit(&self) -> &PersonEmitter { + &self.emit + } + fn get_user_name(&self) -> String { + self.user_name.clone() + } + fn set_user_name(&mut self, value: String) { + self.user_name = value; + self.emit.user_name_changed(); + } +} diff --git a/tests/rust_object/src/lib.rs b/tests/rust_object/src/lib.rs new file mode 100644 index 0000000..94e4632 --- /dev/null +++ b/tests/rust_object/src/lib.rs @@ -0,0 +1,5 @@ +extern crate libc; + +mod types; +pub mod interface; +mod implementation; diff --git a/tests/rust_object/src/types.rs b/tests/rust_object/src/types.rs new file mode 100644 index 0000000..180ae6e --- /dev/null +++ b/tests/rust_object/src/types.rs @@ -0,0 +1,184 @@ +use std::slice; +use libc::{c_int, c_uint, uint8_t, uint16_t}; +use std::ptr::null; +use std::marker::PhantomData; + +#[repr(C)] +pub struct QString { + data: *const uint8_t, + len: c_int, +} + +#[repr(C)] +pub struct QStringIn { + data: *const uint16_t, + len: c_int, +} + +impl QStringIn { + pub fn convert(&self) -> String { + let data = unsafe { slice::from_raw_parts(self.data, self.len as usize) }; + String::from_utf16_lossy(data) + } +} + +impl<'a> From<&'a String> for QString { + fn from(string: &'a String) -> QString { + QString { + len: string.len() as c_int, + data: string.as_ptr(), + } + } +} + +#[repr(C)] +pub struct QByteArray { + data: *const uint8_t, + len: c_int, +} + +impl QByteArray { + pub fn convert(&self) -> Vec { + let data = unsafe { slice::from_raw_parts(self.data, self.len as usize) }; + Vec::from(data) + } +} + +impl<'a> From<&'a Vec> for QByteArray { + fn from(value: &'a Vec) -> QByteArray { + QByteArray { + len: value.len() as c_int, + data: value.as_ptr(), + } + } +} + +#[derive(Clone)] +pub enum Variant { + None, + Bool(bool), + String(String), + ByteArray(Vec), +} + +impl From for Variant { + fn from(value: bool) -> Variant { + Variant::Bool(value) + } +} + +impl From for Variant { + fn from(value: String) -> Variant { + Variant::String(value) + } +} + +/* values from qvariant.h and qmetatype.h */ +#[repr(u32)] +#[derive(Clone, Copy)] +enum VariantType { + Invalid = 0, + Bool = 1, + String = 10, + ByteArray = 12, +} + +#[repr(C)] +pub struct QVariant<'a> { + type_: c_uint, + len: c_int, + data: *const uint8_t, + phantom: PhantomData<&'a u8>, +} + +impl<'a> QVariant<'a> { + pub fn type_(&self) -> u32 { + self.type_ as u32 + } + pub fn convert(&self) -> Variant { + // TODO + Variant::None + } +} + +impl<'a> From<&'a Variant> for QVariant<'a> { + fn from(variant: &'a Variant) -> QVariant { + match *variant { + Variant::None => { + QVariant { + data: null(), + len: 0, + type_: VariantType::Invalid as c_uint, + phantom: PhantomData, + } + } + Variant::Bool(v) => { + QVariant { + data: null(), + len: v as c_int, + type_: VariantType::Bool as c_uint, + phantom: PhantomData, + } + } + Variant::String(ref v) => { + QVariant { + data: v.as_ptr(), + len: v.len() as c_int, + type_: VariantType::String as c_uint, + phantom: PhantomData, + } + } + Variant::ByteArray(ref v) => { + QVariant { + data: v.as_ptr(), + len: v.len() as c_int, + type_: VariantType::ByteArray as c_uint, + phantom: PhantomData, + } + } + } + } +} + +#[repr(C)] +pub struct QModelIndex { + row: c_int, + column: c_int, + internal_id: usize, +} + +impl QModelIndex { + pub fn invalid() -> QModelIndex { + QModelIndex { + row: -1, + column: -1, + internal_id: 0, + } + } + pub fn create(row: c_int, column: c_int, id: usize) -> QModelIndex { + QModelIndex { + row: row, + column: column, + internal_id: id, + } + } + pub fn flat(row: c_int, column: c_int) -> QModelIndex { + QModelIndex { + row: row, + column: column, + internal_id: 1, + } + } + pub fn is_valid(&self) -> bool { + self.internal_id != 0 && self.row >= 0 && self.column >= 0 + } + pub fn row(&self) -> c_int { + self.row + } + pub fn column(&self) -> c_int { + self.column + } + pub fn id(&self) -> usize { + self.internal_id + } +} diff --git a/tests/test_object.cpp b/tests/test_object.cpp new file mode 100644 index 0000000..a51fcfa --- /dev/null +++ b/tests/test_object.cpp @@ -0,0 +1,32 @@ +#include "test_object_rust.h" +#include + +class TestRustObject : public QObject +{ + Q_OBJECT +private slots: + void testConstructor(); + void testStringGetter(); + void testStringSetter(); +}; + +void TestRustObject::testConstructor() +{ + Person person; +} + +void TestRustObject::testStringGetter() +{ + Person person; + person.setUserName("Konqi"); +} + +void TestRustObject::testStringSetter() +{ + Person person; + person.setUserName("Konqi"); + QCOMPARE(person.userName(), QString("Konqi")); +} + +QTEST_MAIN(TestRustObject) +#include "test_object.moc" diff --git a/tests/test_object.json b/tests/test_object.json new file mode 100644 index 0000000..cfed296 --- /dev/null +++ b/tests/test_object.json @@ -0,0 +1,17 @@ +{ + "cppFile": "test_object_rust.cpp", + "rust": { + "dir": "rust_object", + "interfaceModule": "interface", + "implementationModule": "implementation" + }, + "objects": [{ + "name": "Person", + "type": "Object", + "properties": [{ + "name": "userName", + "type": "QString", + "write": true + }] + }] +} diff --git a/tests/test_object_rust.cpp b/tests/test_object_rust.cpp new file mode 100644 index 0000000..e55ff2f --- /dev/null +++ b/tests/test_object_rust.cpp @@ -0,0 +1,132 @@ +/* generated by rust_qt_binding_generator */ +#include "test_object_rust.h" +#include + +namespace { + struct qbytearray_t { + private: + const char* data; + int len; + public: + qbytearray_t(const QByteArray& v): + data(v.data()), + len(v.size()) { + } + operator QByteArray() const { + return QByteArray(data, len); + } + }; + struct qstring_t { + private: + const void* data; + int len; + public: + qstring_t(const QString& v): + data(static_cast(v.utf16())), + len(v.size()) { + } + operator QString() const { + return QString::fromUtf8(static_cast(data), len); + } + }; + struct qmodelindex_t { + int row; + int column; + uint64_t id; + qmodelindex_t(const QModelIndex& m): + row(m.row()), column(m.column()), id(m.internalId()) {} + }; + struct qvariant_t { + unsigned int type; + int value; + const char* data; + }; + QVariant variant(const qvariant_t& v) { + switch (v.type) { + case QVariant::Bool: return QVariant((bool)v.value); + case QVariant::String: return QString::fromUtf8(static_cast(v.data), v.value); + default:; + } + return QVariant(); + } + void variant(const QByteArray& v, void* d, void (*set)(void*, qvariant_t)) { + set(d, { + .type = QVariant::ByteArray, + .value = v.length(), + .data = v.data() + }); + } + void variant(const QString& v, void* d, void (*set)(void*, qvariant_t)) { + set(d, { + .type = QVariant::String, + .value = v.size(), + .data = static_cast(static_cast(v.utf16())) + }); + } + void variant(const QVariant& v, void* d, void (*set)(void*, qvariant_t)) { + switch (v.type()) { + case QVariant::Bool: + set(d, { + .type = QVariant::Bool, + .value = v.toBool(), + .data = 0 + }); + break; + case QVariant::Int: + set(d, { + .type = QVariant::Int, + .value = v.toInt(), + .data = 0 + }); + break; + case QVariant::ByteArray: + variant(v.toByteArray(), d, set); + break; + case QVariant::String: + variant(v.toString(), d, set); + break; + default: + set(d, { + .type = QVariant::Invalid, + .value = 0, + .data = 0 + }); + } + } +} +typedef void (*qstring_set)(QString*, qstring_t*); +void set_qstring(QString* v, qstring_t* val) { + *v = *val; +} +typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); +void set_qbytearray(QByteArray* v, qbytearray_t* val) { + *v = *val; +} +typedef void (*qvariant_set)(QVariant*, qvariant_t*); +void set_qvariant(QVariant* v, qvariant_t* val) { + *v = variant(*val); +} + +extern "C" { + PersonInterface* person_new(Person*, void (*)(Person*)); + void person_free(PersonInterface*); + void person_user_name_get(PersonInterface*, QString*, qstring_set); + void person_user_name_set(void*, qstring_t); +}; +Person::Person(QObject *parent): + QObject(parent), + d(person_new(this, + [](Person* o) { emit o->userNameChanged(); })) {} + +Person::~Person() { + person_free(d); +} +QString Person::userName() const +{ + QString v; + person_user_name_get(d, &v, set_qstring); + return v; +} +void Person::setUserName(const QString& v) { + person_user_name_set(d, v); +} diff --git a/tests/test_object_rust.h b/tests/test_object_rust.h new file mode 100644 index 0000000..c45dda0 --- /dev/null +++ b/tests/test_object_rust.h @@ -0,0 +1,25 @@ +/* generated by rust_qt_binding_generator */ +#ifndef TEST_OBJECT_RUST_H +#define TEST_OBJECT_RUST_H + +#include +#include +#include + +class PersonInterface; +class Person : public QObject +{ + Q_OBJECT + PersonInterface * const d; + Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged FINAL) +public: + explicit Person(QObject *parent = nullptr); + ~Person(); + QString userName() const; + void setUserName(const QString& v); +signals: + void userNameChanged(); +private: + QString m_userName; +}; +#endif // TEST_OBJECT_RUST_H