From 64bcac54f01ee971f1ac91d4f715c432bd7584f6 Mon Sep 17 00:00:00 2001 From: Jos van den Oever Date: Sat, 26 Aug 2017 19:10:18 +0200 Subject: [PATCH] Allow nesting of binding types. --- demo/demo.qml | 10 + demo/rust/src/fibonacci_interface.rs | 22 +- demo/rust/src/interface.rs | 12 +- demo/rust/src/processes_interface.rs | 12 +- demo/rust/src/time_series_interface.rs | 12 +- demo/src/Fibonacci.cpp | 56 ++-- demo/src/Fibonacci.h | 12 +- demo/src/Processes.cpp | 52 ++-- demo/src/Processes.h | 5 +- demo/src/TimeSeries.cpp | 36 ++- demo/src/TimeSeries.h | 5 +- demo/src/Tree.cpp | 66 +++-- demo/src/Tree.h | 6 +- src/cpp.cpp | 278 ++++++++++++------ src/parseJson.cpp | 139 ++++----- src/rust.cpp | 224 +++++++++----- src/structs.h | 25 +- tests/CMakeLists.txt | 1 + tests/rust_list/src/interface.rs | 12 +- tests/rust_object/src/implementation.rs | 2 +- tests/rust_object/src/interface.rs | 10 +- tests/rust_object_types/src/implementation.rs | 16 +- tests/rust_object_types/src/interface.rs | 10 +- tests/rust_objects/Cargo.toml | 10 + tests/rust_objects/src/implementation.rs | 50 ++++ tests/rust_objects/src/interface.rs | 148 ++++++++++ tests/rust_objects/src/lib.rs | 4 + tests/rust_tree/src/interface.rs | 12 +- tests/test_list_rust.cpp | 28 +- tests/test_list_rust.h | 5 +- tests/test_object_rust.cpp | 24 +- tests/test_object_rust.h | 6 +- tests/test_object_types_rust.cpp | 98 ++++-- tests/test_object_types_rust.h | 13 +- tests/test_objects.cpp | 41 +++ tests/test_objects.json | 28 ++ tests/test_objects_rust.cpp | 123 ++++++++ tests/test_objects_rust.h | 48 +++ tests/test_tree_rust.cpp | 38 ++- tests/test_tree_rust.h | 5 +- 40 files changed, 1234 insertions(+), 470 deletions(-) create mode 100644 tests/rust_objects/Cargo.toml create mode 100644 tests/rust_objects/src/implementation.rs create mode 100644 tests/rust_objects/src/interface.rs create mode 100644 tests/rust_objects/src/lib.rs create mode 100644 tests/test_objects.cpp create mode 100644 tests/test_objects.json create mode 100644 tests/test_objects_rust.cpp create mode 100644 tests/test_objects_rust.h diff --git a/demo/demo.qml b/demo/demo.qml index fbaefe4..c749814 100644 --- a/demo/demo.qml +++ b/demo/demo.qml @@ -14,6 +14,10 @@ ApplicationWindow { id: selectionModel model: sortedFileSystem } + ItemSelectionModel { + id: processSelection + model: processes + } TabView { id: tabView anchors.fill: parent @@ -116,11 +120,17 @@ ApplicationWindow { } } TreeView { + onClicked: { + processSelection.select(index, ItemSelectionModel.ToggleCurrent); + } width: parent.width anchors.top: processFilterInput.bottom anchors.bottom: parent.bottom id: processView model: processes + selection: processSelection + selectionMode: SelectionMode.ExtendedSelection +// selectionMode: SelectionMode.SingleSelection sortIndicatorVisible: true alternatingRowColors: true TableViewColumn { diff --git a/demo/rust/src/fibonacci_interface.rs b/demo/rust/src/fibonacci_interface.rs index 3e0a0f3..acab3df 100644 --- a/demo/rust/src/fibonacci_interface.rs +++ b/demo/rust/src/fibonacci_interface.rs @@ -83,17 +83,17 @@ pub trait FibonacciTrait { } #[no_mangle] -pub extern "C" fn fibonacci_new(qobject: *const FibonacciQObject, +pub extern "C" fn fibonacci_new(fibonacci: *mut FibonacciQObject, input_changed: fn(*const FibonacciQObject), result_changed: fn(*const FibonacciQObject)) -> *mut Fibonacci { - let emit = FibonacciEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let fibonacci_emit = FibonacciEmitter { + qobject: Arc::new(Mutex::new(fibonacci)), input_changed: input_changed, result_changed: result_changed, }; - let d = Fibonacci::create(emit); - Box::into_raw(Box::new(d)) + let d_fibonacci = Fibonacci::create(fibonacci_emit); + Box::into_raw(Box::new(d_fibonacci)) } #[no_mangle] @@ -180,7 +180,7 @@ pub trait FibonacciListTrait { } #[no_mangle] -pub extern "C" fn fibonacci_list_new(qobject: *const FibonacciListQObject, +pub extern "C" fn fibonacci_list_new(fibonacci_list: *mut FibonacciListQObject, new_data_ready: fn(*const FibonacciListQObject), begin_reset_model: fn(*const FibonacciListQObject), end_reset_model: fn(*const FibonacciListQObject), @@ -193,12 +193,12 @@ pub extern "C" fn fibonacci_list_new(qobject: *const FibonacciListQObject, usize), end_remove_rows: fn(*const FibonacciListQObject)) -> *mut FibonacciList { - let emit = FibonacciListEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let fibonacci_list_emit = FibonacciListEmitter { + qobject: Arc::new(Mutex::new(fibonacci_list)), new_data_ready: new_data_ready, }; let model = FibonacciListList { - qobject: qobject, + qobject: fibonacci_list, begin_reset_model: begin_reset_model, end_reset_model: end_reset_model, begin_insert_rows: begin_insert_rows, @@ -206,8 +206,8 @@ pub extern "C" fn fibonacci_list_new(qobject: *const FibonacciListQObject, begin_remove_rows: begin_remove_rows, end_remove_rows: end_remove_rows, }; - let d = FibonacciList::create(emit, model); - Box::into_raw(Box::new(d)) + let d_fibonacci_list = FibonacciList::create(fibonacci_list_emit, model); + Box::into_raw(Box::new(d_fibonacci_list)) } #[no_mangle] diff --git a/demo/rust/src/interface.rs b/demo/rust/src/interface.rs index b5a4c7a..8db5f21 100644 --- a/demo/rust/src/interface.rs +++ b/demo/rust/src/interface.rs @@ -178,7 +178,7 @@ pub trait TreeTrait { } #[no_mangle] -pub extern "C" fn tree_new(qobject: *const TreeQObject, +pub extern "C" fn tree_new(tree: *mut TreeQObject, path_changed: fn(*const TreeQObject), new_data_ready: fn(*const TreeQObject, item: usize, valid: bool), begin_reset_model: fn(*const TreeQObject), @@ -192,13 +192,13 @@ pub extern "C" fn tree_new(qobject: *const TreeQObject, usize), end_remove_rows: fn(*const TreeQObject)) -> *mut Tree { - let emit = TreeEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let tree_emit = TreeEmitter { + qobject: Arc::new(Mutex::new(tree)), path_changed: path_changed, new_data_ready: new_data_ready, }; let model = TreeUniformTree { - qobject: qobject, + qobject: tree, begin_reset_model: begin_reset_model, end_reset_model: end_reset_model, begin_insert_rows: begin_insert_rows, @@ -206,8 +206,8 @@ pub extern "C" fn tree_new(qobject: *const TreeQObject, begin_remove_rows: begin_remove_rows, end_remove_rows: end_remove_rows, }; - let d = Tree::create(emit, model); - Box::into_raw(Box::new(d)) + let d_tree = Tree::create(tree_emit, model); + Box::into_raw(Box::new(d_tree)) } #[no_mangle] diff --git a/demo/rust/src/processes_interface.rs b/demo/rust/src/processes_interface.rs index 0737172..45680f8 100644 --- a/demo/rust/src/processes_interface.rs +++ b/demo/rust/src/processes_interface.rs @@ -147,7 +147,7 @@ pub trait ProcessesTrait { } #[no_mangle] -pub extern "C" fn processes_new(qobject: *const ProcessesQObject, +pub extern "C" fn processes_new(processes: *mut ProcessesQObject, new_data_ready: fn(*const ProcessesQObject, item: usize, valid: bool), begin_reset_model: fn(*const ProcessesQObject), end_reset_model: fn(*const ProcessesQObject), @@ -160,12 +160,12 @@ pub extern "C" fn processes_new(qobject: *const ProcessesQObject, usize), end_remove_rows: fn(*const ProcessesQObject)) -> *mut Processes { - let emit = ProcessesEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let processes_emit = ProcessesEmitter { + qobject: Arc::new(Mutex::new(processes)), new_data_ready: new_data_ready, }; let model = ProcessesUniformTree { - qobject: qobject, + qobject: processes, begin_reset_model: begin_reset_model, end_reset_model: end_reset_model, begin_insert_rows: begin_insert_rows, @@ -173,8 +173,8 @@ pub extern "C" fn processes_new(qobject: *const ProcessesQObject, begin_remove_rows: begin_remove_rows, end_remove_rows: end_remove_rows, }; - let d = Processes::create(emit, model); - Box::into_raw(Box::new(d)) + let d_processes = Processes::create(processes_emit, model); + Box::into_raw(Box::new(d_processes)) } #[no_mangle] diff --git a/demo/rust/src/time_series_interface.rs b/demo/rust/src/time_series_interface.rs index 77de8ae..58a2ca6 100644 --- a/demo/rust/src/time_series_interface.rs +++ b/demo/rust/src/time_series_interface.rs @@ -112,7 +112,7 @@ pub trait TimeSeriesTrait { } #[no_mangle] -pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject, +pub extern "C" fn time_series_new(time_series: *mut TimeSeriesQObject, new_data_ready: fn(*const TimeSeriesQObject), begin_reset_model: fn(*const TimeSeriesQObject), end_reset_model: fn(*const TimeSeriesQObject), @@ -125,12 +125,12 @@ pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject, usize), end_remove_rows: fn(*const TimeSeriesQObject)) -> *mut TimeSeries { - let emit = TimeSeriesEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let time_series_emit = TimeSeriesEmitter { + qobject: Arc::new(Mutex::new(time_series)), new_data_ready: new_data_ready, }; let model = TimeSeriesList { - qobject: qobject, + qobject: time_series, begin_reset_model: begin_reset_model, end_reset_model: end_reset_model, begin_insert_rows: begin_insert_rows, @@ -138,8 +138,8 @@ pub extern "C" fn time_series_new(qobject: *const TimeSeriesQObject, begin_remove_rows: begin_remove_rows, end_remove_rows: end_remove_rows, }; - let d = TimeSeries::create(emit, model); - Box::into_raw(Box::new(d)) + let d_time_series = TimeSeries::create(time_series_emit, model); + Box::into_raw(Box::new(d_time_series)) } #[no_mangle] diff --git a/demo/src/Fibonacci.cpp b/demo/src/Fibonacci.cpp index fe78585..bf4bce4 100644 --- a/demo/src/Fibonacci.cpp +++ b/demo/src/Fibonacci.cpp @@ -44,6 +44,15 @@ namespace { int row; quintptr id; }; + inline void fibonacciInputChanged(Fibonacci* o) + { + emit o->inputChanged(); + } + inline void fibonacciResultChanged(Fibonacci* o) + { + emit o->resultChanged(); + } + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,7 +62,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { Fibonacci::Private* fibonacci_new(Fibonacci*, void (*)(Fibonacci*), void (*)(Fibonacci*)); void fibonacci_free(Fibonacci::Private*); @@ -81,7 +89,7 @@ bool FibonacciList::hasChildren(const QModelIndex &parent) const int FibonacciList::rowCount(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : fibonacci_list_row_count(d); + return (parent.isValid()) ? 0 : fibonacci_list_row_count(m_d); } QModelIndex FibonacciList::index(int row, int column, const QModelIndex &parent) const @@ -99,19 +107,19 @@ QModelIndex FibonacciList::parent(const QModelIndex &) const bool FibonacciList::canFetchMore(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : fibonacci_list_can_fetch_more(d); + return (parent.isValid()) ? 0 : fibonacci_list_can_fetch_more(m_d); } void FibonacciList::fetchMore(const QModelIndex &parent) { if (!parent.isValid()) { - fibonacci_list_fetch_more(d); + fibonacci_list_fetch_more(m_d); } } void FibonacciList::sort(int column, Qt::SortOrder order) { - fibonacci_list_sort(d, column, order); + fibonacci_list_sort(m_d, column, order); } Qt::ItemFlags FibonacciList::flags(const QModelIndex &i) const { @@ -129,7 +137,7 @@ QVariant FibonacciList::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: case Qt::UserRole + 0: - v = fibonacci_list_data_result(d, index.row()); + v = fibonacci_list_data_result(m_d, index.row()); break; } break; @@ -160,29 +168,41 @@ extern "C" { void (*)(FibonacciList*)); void fibonacci_list_free(FibonacciList::Private*); }; +Fibonacci::Fibonacci(bool /*owned*/, QObject *parent): + QObject(parent), + m_d(0), + m_ownsPrivate(false) {} Fibonacci::Fibonacci(QObject *parent): QObject(parent), - d(fibonacci_new(this, - [](Fibonacci* o) { emit o->inputChanged(); }, - [](Fibonacci* o) { emit o->resultChanged(); })) {} + m_d(fibonacci_new(this, + fibonacciInputChanged, + fibonacciResultChanged)), + m_ownsPrivate(true) { +} Fibonacci::~Fibonacci() { - fibonacci_free(d); + if (m_ownsPrivate) { + fibonacci_free(m_d); + } } quint32 Fibonacci::input() const { - return fibonacci_input_get(d); + return fibonacci_input_get(m_d); } void Fibonacci::setInput(uint v) { - fibonacci_input_set(d, v); + fibonacci_input_set(m_d, v); } quint64 Fibonacci::result() const { - return fibonacci_result_get(d); + return fibonacci_result_get(m_d); } +FibonacciList::FibonacciList(bool /*owned*/, QObject *parent): + QAbstractItemModel(parent), + m_d(0), + m_ownsPrivate(false) {} FibonacciList::FibonacciList(QObject *parent): QAbstractItemModel(parent), - d(fibonacci_list_new(this, + m_d(fibonacci_list_new(this, [](const FibonacciList* o) { emit o->newDataReady(QModelIndex()); }, @@ -204,13 +224,15 @@ FibonacciList::FibonacciList(QObject *parent): [](FibonacciList* o) { o->endRemoveRows(); } - )) { +)), + m_ownsPrivate(true) { connect(this, &FibonacciList::newDataReady, this, [this](const QModelIndex& i) { fetchMore(i); }, Qt::QueuedConnection); } - FibonacciList::~FibonacciList() { - fibonacci_list_free(d); + if (m_ownsPrivate) { + fibonacci_list_free(m_d); + } } diff --git a/demo/src/Fibonacci.h b/demo/src/Fibonacci.h index 3cf9e05..0dd97a3 100644 --- a/demo/src/Fibonacci.h +++ b/demo/src/Fibonacci.h @@ -11,9 +11,11 @@ class Fibonacci : public QObject public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; Q_PROPERTY(quint32 input READ input WRITE setInput NOTIFY inputChanged FINAL) Q_PROPERTY(quint64 result READ result NOTIFY resultChanged FINAL) + explicit Fibonacci(bool owned, QObject *parent); public: explicit Fibonacci(QObject *parent = nullptr); ~Fibonacci(); @@ -23,9 +25,6 @@ public: signals: void inputChanged(); void resultChanged(); -private: - quint32 m_input; - quint64 m_result; }; class FibonacciList : public QAbstractItemModel @@ -34,7 +33,9 @@ class FibonacciList : public QAbstractItemModel public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; + explicit FibonacciList(bool owned, QObject *parent); public: explicit FibonacciList(QObject *parent = nullptr); ~FibonacciList(); @@ -55,6 +56,5 @@ signals: // new data is ready to be made available to the model with fetchMore() void newDataReady(const QModelIndex &parent) const; signals: -private: }; #endif // FIBONACCI_H diff --git a/demo/src/Processes.cpp b/demo/src/Processes.cpp index 15be0eb..923b05d 100644 --- a/demo/src/Processes.cpp +++ b/demo/src/Processes.cpp @@ -44,6 +44,7 @@ namespace { int row; quintptr id; }; + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { void processes_data_cmd(const Processes::Private*, quintptr, QString*, qstring_set); quint8 processes_data_cpu_percentage(const Processes::Private*, quintptr); @@ -86,7 +86,7 @@ int Processes::rowCount(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return 0; } - return processes_row_count(d, parent.internalId(), parent.isValid()); + return processes_row_count(m_d, parent.internalId(), parent.isValid()); } QModelIndex Processes::index(int row, int column, const QModelIndex &parent) const @@ -100,7 +100,7 @@ QModelIndex Processes::index(int row, int column, const QModelIndex &parent) con if (row >= rowCount(parent)) { return QModelIndex(); } - const quintptr id = processes_index(d, parent.internalId(), parent.isValid(), row); + const quintptr id = processes_index(m_d, parent.internalId(), parent.isValid(), row); return createIndex(row, column, id); } @@ -109,7 +109,7 @@ QModelIndex Processes::parent(const QModelIndex &index) const if (!index.isValid()) { return QModelIndex(); } - const qmodelindex_t parent = processes_parent(d, index.internalId()); + const qmodelindex_t parent = processes_parent(m_d, index.internalId()); return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex(); } @@ -118,17 +118,17 @@ bool Processes::canFetchMore(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return false; } - return processes_can_fetch_more(d, parent.internalId(), parent.isValid()); + return processes_can_fetch_more(m_d, parent.internalId(), parent.isValid()); } void Processes::fetchMore(const QModelIndex &parent) { - processes_fetch_more(d, parent.internalId(), parent.isValid()); + processes_fetch_more(m_d, parent.internalId(), parent.isValid()); } void Processes::sort(int column, Qt::SortOrder order) { - processes_sort(d, column, order); + processes_sort(m_d, column, order); } Qt::ItemFlags Processes::flags(const QModelIndex &i) const { @@ -145,29 +145,29 @@ QVariant Processes::data(const QModelIndex &index, int role) const case 0: switch (role) { case Qt::UserRole + 0: - processes_data_cmd(d, index.internalId(), &s, set_qstring); + processes_data_cmd(m_d, index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; case Qt::UserRole + 1: - v = processes_data_cpu_percentage(d, index.internalId()); + v = processes_data_cpu_percentage(m_d, index.internalId()); break; case Qt::UserRole + 2: - v = processes_data_cpu_usage(d, index.internalId()); + v = processes_data_cpu_usage(m_d, index.internalId()); break; case Qt::UserRole + 3: - v = processes_data_memory(d, index.internalId()); + v = processes_data_memory(m_d, index.internalId()); break; case Qt::DisplayRole: case Qt::UserRole + 4: - processes_data_name(d, index.internalId(), &s, set_qstring); + processes_data_name(m_d, index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; case Qt::ToolTipRole: case Qt::UserRole + 5: - v = processes_data_pid(d, index.internalId()); + v = processes_data_pid(m_d, index.internalId()); break; case Qt::UserRole + 6: - v = processes_data_uid(d, index.internalId()); + v = processes_data_uid(m_d, index.internalId()); break; } break; @@ -175,7 +175,7 @@ QVariant Processes::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: case Qt::UserRole + 2: - v = processes_data_cpu_usage(d, index.internalId()); + v = processes_data_cpu_usage(m_d, index.internalId()); break; } break; @@ -183,7 +183,7 @@ QVariant Processes::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: case Qt::UserRole + 3: - v = processes_data_memory(d, index.internalId()); + v = processes_data_memory(m_d, index.internalId()); break; } break; @@ -220,12 +220,16 @@ extern "C" { void (*)(Processes*)); void processes_free(Processes::Private*); }; +Processes::Processes(bool /*owned*/, QObject *parent): + QAbstractItemModel(parent), + m_d(0), + m_ownsPrivate(false) {} Processes::Processes(QObject *parent): QAbstractItemModel(parent), - d(processes_new(this, + m_d(processes_new(this, [](const Processes* o, quintptr id, bool valid) { if (valid) { - int row = processes_row(o->d, id); + int row = processes_row(o->m_d, id); emit o->newDataReady(o->createIndex(row, 0, id)); } else { emit o->newDataReady(QModelIndex()); @@ -239,7 +243,7 @@ Processes::Processes(QObject *parent): }, [](Processes* o, option id, int first, int last) { if (id.some) { - int row = processes_row(o->d, id.value); + int row = processes_row(o->m_d, id.value); o->beginInsertRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginInsertRows(QModelIndex(), first, last); @@ -250,7 +254,7 @@ Processes::Processes(QObject *parent): }, [](Processes* o, option id, int first, int last) { if (id.some) { - int row = processes_row(o->d, id.value); + int row = processes_row(o->m_d, id.value); o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginRemoveRows(QModelIndex(), first, last); @@ -259,13 +263,15 @@ Processes::Processes(QObject *parent): [](Processes* o) { o->endRemoveRows(); } - )) { +)), + m_ownsPrivate(true) { connect(this, &Processes::newDataReady, this, [this](const QModelIndex& i) { fetchMore(i); }, Qt::QueuedConnection); } - Processes::~Processes() { - processes_free(d); + if (m_ownsPrivate) { + processes_free(m_d); + } } diff --git a/demo/src/Processes.h b/demo/src/Processes.h index ef8af66..0600132 100644 --- a/demo/src/Processes.h +++ b/demo/src/Processes.h @@ -11,7 +11,9 @@ class Processes : public QAbstractItemModel public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; + explicit Processes(bool owned, QObject *parent); public: explicit Processes(QObject *parent = nullptr); ~Processes(); @@ -32,6 +34,5 @@ signals: // new data is ready to be made available to the model with fetchMore() void newDataReady(const QModelIndex &parent) const; signals: -private: }; #endif // PROCESSES_H diff --git a/demo/src/TimeSeries.cpp b/demo/src/TimeSeries.cpp index a7cc714..4d58b55 100644 --- a/demo/src/TimeSeries.cpp +++ b/demo/src/TimeSeries.cpp @@ -44,6 +44,7 @@ namespace { int row; quintptr id; }; + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { uint time_series_data_input(const TimeSeries::Private*, int); bool time_series_set_data_input(TimeSeries::Private*, int, uint); @@ -77,7 +77,7 @@ bool TimeSeries::hasChildren(const QModelIndex &parent) const int TimeSeries::rowCount(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : time_series_row_count(d); + return (parent.isValid()) ? 0 : time_series_row_count(m_d); } QModelIndex TimeSeries::index(int row, int column, const QModelIndex &parent) const @@ -95,19 +95,19 @@ QModelIndex TimeSeries::parent(const QModelIndex &) const bool TimeSeries::canFetchMore(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : time_series_can_fetch_more(d); + return (parent.isValid()) ? 0 : time_series_can_fetch_more(m_d); } void TimeSeries::fetchMore(const QModelIndex &parent) { if (!parent.isValid()) { - time_series_fetch_more(d); + time_series_fetch_more(m_d); } } void TimeSeries::sort(int column, Qt::SortOrder order) { - time_series_sort(d, column, order); + time_series_sort(m_d, column, order); } Qt::ItemFlags TimeSeries::flags(const QModelIndex &i) const { @@ -132,10 +132,10 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const case Qt::DisplayRole: case Qt::EditRole: case Qt::UserRole + 0: - v = time_series_data_input(d, index.row()); + v = time_series_data_input(m_d, index.row()); break; case Qt::UserRole + 1: - v = time_series_data_result(d, index.row()); + v = time_series_data_result(m_d, index.row()); break; } break; @@ -144,7 +144,7 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const case Qt::DisplayRole: case Qt::EditRole: case Qt::UserRole + 1: - v = time_series_data_result(d, index.row()); + v = time_series_data_result(m_d, index.row()); break; } break; @@ -162,15 +162,15 @@ bool TimeSeries::setData(const QModelIndex &index, const QVariant &value, int ro bool set = false; if (index.column() == 0) { if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) { - set = time_series_set_data_input(d, index.row(), value.value()); + set = time_series_set_data_input(m_d, index.row(), value.value()); } if (role == Qt::UserRole + 1) { - set = time_series_set_data_result(d, index.row(), value.value()); + set = time_series_set_data_result(m_d, index.row(), value.value()); } } if (index.column() == 1) { if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 1) { - set = time_series_set_data_result(d, index.row(), value.value()); + set = time_series_set_data_result(m_d, index.row(), value.value()); } } if (set) { @@ -189,9 +189,13 @@ extern "C" { void (*)(TimeSeries*)); void time_series_free(TimeSeries::Private*); }; +TimeSeries::TimeSeries(bool /*owned*/, QObject *parent): + QAbstractItemModel(parent), + m_d(0), + m_ownsPrivate(false) {} TimeSeries::TimeSeries(QObject *parent): QAbstractItemModel(parent), - d(time_series_new(this, + m_d(time_series_new(this, [](const TimeSeries* o) { emit o->newDataReady(QModelIndex()); }, @@ -213,13 +217,15 @@ TimeSeries::TimeSeries(QObject *parent): [](TimeSeries* o) { o->endRemoveRows(); } - )) { +)), + m_ownsPrivate(true) { connect(this, &TimeSeries::newDataReady, this, [this](const QModelIndex& i) { fetchMore(i); }, Qt::QueuedConnection); } - TimeSeries::~TimeSeries() { - time_series_free(d); + if (m_ownsPrivate) { + time_series_free(m_d); + } } diff --git a/demo/src/TimeSeries.h b/demo/src/TimeSeries.h index 27b0627..756cfac 100644 --- a/demo/src/TimeSeries.h +++ b/demo/src/TimeSeries.h @@ -11,7 +11,9 @@ class TimeSeries : public QAbstractItemModel public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; + explicit TimeSeries(bool owned, QObject *parent); public: explicit TimeSeries(QObject *parent = nullptr); ~TimeSeries(); @@ -32,6 +34,5 @@ signals: // new data is ready to be made available to the model with fetchMore() void newDataReady(const QModelIndex &parent) const; signals: -private: }; #endif // TIMESERIES_H diff --git a/demo/src/Tree.cpp b/demo/src/Tree.cpp index d8968fd..1bd65e0 100644 --- a/demo/src/Tree.cpp +++ b/demo/src/Tree.cpp @@ -44,6 +44,11 @@ namespace { int row; quintptr id; }; + inline void treePathChanged(Tree* o) + { + emit o->pathChanged(); + } + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,7 +58,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { void tree_data_file_icon(const Tree::Private*, quintptr, QByteArray*, qbytearray_set); void tree_data_file_name(const Tree::Private*, quintptr, QString*, qstring_set); @@ -85,7 +89,7 @@ int Tree::rowCount(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return 0; } - return tree_row_count(d, parent.internalId(), parent.isValid()); + return tree_row_count(m_d, parent.internalId(), parent.isValid()); } QModelIndex Tree::index(int row, int column, const QModelIndex &parent) const @@ -99,7 +103,7 @@ QModelIndex Tree::index(int row, int column, const QModelIndex &parent) const if (row >= rowCount(parent)) { return QModelIndex(); } - const quintptr id = tree_index(d, parent.internalId(), parent.isValid(), row); + const quintptr id = tree_index(m_d, parent.internalId(), parent.isValid(), row); return createIndex(row, column, id); } @@ -108,7 +112,7 @@ QModelIndex Tree::parent(const QModelIndex &index) const if (!index.isValid()) { return QModelIndex(); } - const qmodelindex_t parent = tree_parent(d, index.internalId()); + const qmodelindex_t parent = tree_parent(m_d, index.internalId()); return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex(); } @@ -117,17 +121,17 @@ bool Tree::canFetchMore(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return false; } - return tree_can_fetch_more(d, parent.internalId(), parent.isValid()); + return tree_can_fetch_more(m_d, parent.internalId(), parent.isValid()); } void Tree::fetchMore(const QModelIndex &parent) { - tree_fetch_more(d, parent.internalId(), parent.isValid()); + tree_fetch_more(m_d, parent.internalId(), parent.isValid()); } void Tree::sort(int column, Qt::SortOrder order) { - tree_sort(d, column, order); + tree_sort(m_d, column, order); } Qt::ItemFlags Tree::flags(const QModelIndex &i) const { @@ -145,26 +149,26 @@ QVariant Tree::data(const QModelIndex &index, int role) const switch (role) { case Qt::DecorationRole: case Qt::UserRole + 0: - tree_data_file_icon(d, index.internalId(), &b, set_qbytearray); + tree_data_file_icon(m_d, index.internalId(), &b, set_qbytearray); if (!b.isNull()) v.setValue(b); break; case Qt::DisplayRole: case Qt::UserRole + 1: - tree_data_file_name(d, index.internalId(), &s, set_qstring); + tree_data_file_name(m_d, index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; case Qt::UserRole + 2: - tree_data_file_path(d, index.internalId(), &s, set_qstring); + tree_data_file_path(m_d, index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; case Qt::UserRole + 3: - v = tree_data_file_permissions(d, index.internalId()); + v = tree_data_file_permissions(m_d, index.internalId()); break; case Qt::UserRole + 4: - v = tree_data_file_size(d, index.internalId()); + v = tree_data_file_size(m_d, index.internalId()); break; case Qt::UserRole + 5: - v = tree_data_file_type(d, index.internalId()); + v = tree_data_file_type(m_d, index.internalId()); break; } break; @@ -172,7 +176,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: case Qt::UserRole + 4: - v = tree_data_file_size(d, index.internalId()); + v = tree_data_file_size(m_d, index.internalId()); break; } break; @@ -180,7 +184,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: case Qt::UserRole + 2: - tree_data_file_path(d, index.internalId(), &s, set_qstring); + tree_data_file_path(m_d, index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; } @@ -189,7 +193,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: case Qt::UserRole + 3: - v = tree_data_file_permissions(d, index.internalId()); + v = tree_data_file_permissions(m_d, index.internalId()); break; } break; @@ -197,7 +201,7 @@ QVariant Tree::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: case Qt::UserRole + 5: - v = tree_data_file_type(d, index.internalId()); + v = tree_data_file_type(m_d, index.internalId()); break; } break; @@ -236,13 +240,17 @@ extern "C" { void tree_path_set(Tree::Private*, qstring_t); void tree_path_set_none(Tree::Private*); }; +Tree::Tree(bool /*owned*/, QObject *parent): + QAbstractItemModel(parent), + m_d(0), + m_ownsPrivate(false) {} Tree::Tree(QObject *parent): QAbstractItemModel(parent), - d(tree_new(this, - [](Tree* o) { emit o->pathChanged(); }, + m_d(tree_new(this, + treePathChanged, [](const Tree* o, quintptr id, bool valid) { if (valid) { - int row = tree_row(o->d, id); + int row = tree_row(o->m_d, id); emit o->newDataReady(o->createIndex(row, 0, id)); } else { emit o->newDataReady(QModelIndex()); @@ -256,7 +264,7 @@ Tree::Tree(QObject *parent): }, [](Tree* o, option id, int first, int last) { if (id.some) { - int row = tree_row(o->d, id.value); + int row = tree_row(o->m_d, id.value); o->beginInsertRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginInsertRows(QModelIndex(), first, last); @@ -267,7 +275,7 @@ Tree::Tree(QObject *parent): }, [](Tree* o, option id, int first, int last) { if (id.some) { - int row = tree_row(o->d, id.value); + int row = tree_row(o->m_d, id.value); o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginRemoveRows(QModelIndex(), first, last); @@ -276,26 +284,28 @@ Tree::Tree(QObject *parent): [](Tree* o) { o->endRemoveRows(); } - )) { +)), + m_ownsPrivate(true) { connect(this, &Tree::newDataReady, this, [this](const QModelIndex& i) { fetchMore(i); }, Qt::QueuedConnection); } - Tree::~Tree() { - tree_free(d); + if (m_ownsPrivate) { + tree_free(m_d); + } } QString Tree::path() const { QString v; - tree_path_get(d, &v, set_qstring); + tree_path_get(m_d, &v, set_qstring); return v; } void Tree::setPath(const QString& v) { if (v.isNull()) { - tree_path_set_none(d); + tree_path_set_none(m_d); } else { - tree_path_set(d, v); + tree_path_set(m_d, v); } } diff --git a/demo/src/Tree.h b/demo/src/Tree.h index d3720e5..cfb2378 100644 --- a/demo/src/Tree.h +++ b/demo/src/Tree.h @@ -11,8 +11,10 @@ class Tree : public QAbstractItemModel public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged FINAL) + explicit Tree(bool owned, QObject *parent); public: explicit Tree(QObject *parent = nullptr); ~Tree(); @@ -36,7 +38,5 @@ signals: void newDataReady(const QModelIndex &parent) const; signals: void pathChanged(); -private: - QString m_path; }; #endif // TREE_H diff --git a/src/cpp.cpp b/src/cpp.cpp index 740df1e..e56efea 100644 --- a/src/cpp.cpp +++ b/src/cpp.cpp @@ -16,6 +16,10 @@ QString upperInitial(const QString& name) { return name.left(1).toUpper() + name.mid(1); } +QString lowerInitial(const QString& name) { + return name.left(1).toLower() + name.mid(1); +} + QString writeProperty(const QString& name) { return "WRITE set" + upperInitial(name) + " "; } @@ -106,7 +110,7 @@ bool %1::hasChildren(const QModelIndex &parent) const int %1::rowCount(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : %2_row_count(d); + return (parent.isValid()) ? 0 : %2_row_count(m_d); } QModelIndex %1::index(int row, int column, const QModelIndex &parent) const @@ -124,13 +128,13 @@ QModelIndex %1::parent(const QModelIndex &) const bool %1::canFetchMore(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : %2_can_fetch_more(d); + return (parent.isValid()) ? 0 : %2_can_fetch_more(m_d); } void %1::fetchMore(const QModelIndex &parent) { if (!parent.isValid()) { - %2_fetch_more(d); + %2_fetch_more(m_d); } } )").arg(o.name, lcname, QString::number(o.columnCount)); @@ -158,7 +162,7 @@ int %1::rowCount(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return 0; } - return %2_row_count(d, parent.internalId(), parent.isValid()); + return %2_row_count(m_d, parent.internalId(), parent.isValid()); } QModelIndex %1::index(int row, int column, const QModelIndex &parent) const @@ -172,7 +176,7 @@ QModelIndex %1::index(int row, int column, const QModelIndex &parent) const if (row >= rowCount(parent)) { return QModelIndex(); } - const quintptr id = %2_index(d, parent.internalId(), parent.isValid(), row); + const quintptr id = %2_index(m_d, parent.internalId(), parent.isValid(), row); return createIndex(row, column, id); } @@ -181,7 +185,7 @@ QModelIndex %1::parent(const QModelIndex &index) const if (!index.isValid()) { return QModelIndex(); } - const qmodelindex_t parent = %2_parent(d, index.internalId()); + const qmodelindex_t parent = %2_parent(m_d, index.internalId()); return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex(); } @@ -190,12 +194,12 @@ bool %1::canFetchMore(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return false; } - return %2_can_fetch_more(d, parent.internalId(), parent.isValid()); + return %2_can_fetch_more(m_d, parent.internalId(), parent.isValid()); } void %1::fetchMore(const QModelIndex &parent) { - %2_fetch_more(d, parent.internalId(), parent.isValid()); + %2_fetch_more(m_d, parent.internalId(), parent.isValid()); } )").arg(o.name, lcname, QString::number(o.columnCount)); } @@ -203,7 +207,7 @@ void %1::fetchMore(const QModelIndex &parent) cpp << QString(R"( void %1::sort(int column, Qt::SortOrder order) { - %2_sort(d, column, order); + %2_sort(m_d, column, order); } Qt::ItemFlags %1::flags(const QModelIndex &i) const { @@ -241,15 +245,15 @@ QVariant %1::data(const QModelIndex &index, int role) const } cpp << QString(" case Qt::UserRole + %1:\n").arg(i); if (ip.type.name == "QString") { - cpp << QString(" %1_data_%2(d%4, &s, set_%3);\n") + cpp << QString(" %1_data_%2(m_d%4, &s, set_%3);\n") .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); cpp << " if (!s.isNull()) v.setValue(s);\n"; } else if (ip.type.name == "QByteArray") { - cpp << QString(" %1_data_%2(d%4, &b, set_%3);\n") + cpp << QString(" %1_data_%2(m_d%4, &b, set_%3);\n") .arg(lcname, snakeCase(ip.name), ip.type.name.toLower(), index); cpp << " if (!b.isNull()) v.setValue(b);\n"; } else { - cpp << QString(" v = %1_data_%2(d%3);\n") + cpp << QString(" v = %1_data_%2(m_d%3);\n") .arg(lcname, snakeCase(ip.name), index); } cpp << " break;\n"; @@ -295,12 +299,12 @@ bool %1::setData(const QModelIndex &index, const QVariant &value, int role) test += " || value.isNull()"; } cpp << " if (" << test << ") {\n"; - cpp << QString(" set = %1_set_data_%2_none(d%3);") + cpp << QString(" set = %1_set_data_%2_none(m_d%3);") .arg(lcname, snakeCase(ip.name), index) << endl; cpp << " } else\n"; } QString val = QString("value.value<%1>()").arg(ip.type.name); - cpp << QString(" set = %1_set_data_%2(d%3, %4);") + cpp << QString(" set = %1_set_data_%2(m_d%3, %4);") .arg(lcname, snakeCase(ip.name), index, val) << endl; cpp << " }\n"; } @@ -314,29 +318,52 @@ bool %1::setData(const QModelIndex &index, const QVariant &value, int role) )"; } -void writeHeaderObject(QTextStream& h, const Object& o) { +void writeHeaderObject(QTextStream& h, const Object& o, const Configuration& conf) { h << QString(R"( class %1 : public %3 { Q_OBJEC%2 -public: +)").arg(o.name, "T", baseType(o)); + for (auto object: conf.objects) { + if (object.containsObject()) { + h << " friend class " << object.name << ";\n"; + } + } + h << R"(public: class Private; private: - Private * const d; -)").arg(o.name, "T", baseType(o)); +)"; for (auto p: o.properties) { - h << QString(" Q_PROPERTY(%1 %2 READ %2 %3NOTIFY %2Changed FINAL)") - .arg(p.type.name, p.name, - p.write ? writeProperty(p.name) :"") << endl; + if (p.type.type == BindingType::Object) { + h << " " << p.type.name << "* const m_" << p.name << ";\n"; + } } - h << QString(R"(public: + h << R"( Private * m_d; + bool m_ownsPrivate; +)"; + for (auto p: o.properties) { + bool obj = p.type.type == BindingType::Object; + h << QString(" Q_PROPERTY(%1 %2 READ %2 %3%4FINAL)") + .arg(p.type.name + (obj ?"*" :""), + p.name, + p.write ? writeProperty(p.name) :"", + obj ?"" :("NOTIFY " +p.name + "Changed ")) + << endl; + } + h << QString(R"( explicit %1(bool owned, QObject *parent); +public: explicit %1(QObject *parent = nullptr); ~%1(); )").arg(o.name); for (auto p: o.properties) { - h << " " << p.type.name << " " << p.name << "() const;" << endl; - if (p.write) { - h << " void set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v);" << endl; + if (p.type.type == BindingType::Object) { + h << " const " << p.type.name << "* " << p.name << "() const;" << endl; + h << " " << p.type.name << "* " << p.name << "();" << endl; + } else { + h << " " << p.type.name << " " << p.name << "() const;" << endl; + if (p.write) { + h << " void set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v);" << endl; + } } } if (baseType(o) == "QAbstractItemModel") { @@ -344,20 +371,22 @@ private: } h << "signals:" << endl; for (auto p: o.properties) { - h << " void " << p.name << "Changed();" << endl; - } - h << "private:" << endl; - for (auto p: o.properties) { - h << " " << p.type.name << " m_" << p.name << ";" << endl; + if (p.type.type != BindingType::Object) { + h << " void " << p.name << "Changed();" << endl; + } } h << "};" << endl; } -void writeObjectCDecl(QTextStream& cpp, const Object& o) { - const QString lcname(snakeCase(o.name)); - cpp << QString(" %1::Private* %2_new(%1*").arg(o.name, lcname); - for (int i = 0; i < o.properties.size(); ++i) { - cpp << QString(", void (*)(%1*)").arg(o.name); +void constructorArgsDecl(QTextStream& cpp, const Object& o, const Configuration& conf) { + cpp << o.name << "*"; + for (auto p: o.properties) { + if (p.type.type == BindingType::Object) { + cpp << QString(", "); + constructorArgsDecl(cpp, conf.findObject(p.type.name), conf); + } else { + cpp << QString(", void (*)(%1*)").arg(o.name); + } } if (o.type == ObjectType::List) { cpp << QString(R"(, @@ -379,37 +408,21 @@ void writeObjectCDecl(QTextStream& cpp, const Object& o) { void (*)(%1*, option, int, int), void (*)(%1*))").arg(o.name); } - cpp << ");" << endl; - cpp << QString(" void %2_free(%1::Private*);").arg(o.name, lcname) - << endl; - for (const Property& p: o.properties) { - const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); - if (p.type.isComplex()) { - cpp << QString(" void %2_get(const %1::Private*, %3);") - .arg(o.name, base, cGetType(p.type)) << endl; - } else { - cpp << QString(" %3 %2_get(const %1::Private*);") - .arg(o.name, base, p.type.name) << endl; - } - if (p.write) { - cpp << QString(" void %2_set(%1::Private*, %3);") - .arg(o.name, base, p.type.cSetType) << endl; - if (p.optional) { - cpp << QString(" void %2_set_none(%1::Private*);") - .arg(o.name, base) << endl; - } - } - } } -void writeCppObject(QTextStream& cpp, const Object& o) { +QString changedF(const Object& o, const Property& p) { + return lowerInitial(o.name) + upperInitial(p.name) + "Changed"; +} + +void constructorArgs(QTextStream& cpp, const Object& o, const Configuration& conf) { const QString lcname(snakeCase(o.name)); - cpp << QString("%1::%1(QObject *parent):\n %2(parent),") - .arg(o.name, baseType(o)) << endl; - cpp << QString(" d(%1_new(this").arg(lcname); for (const Property& p: o.properties) { - cpp << QString(",\n [](%1* o) { emit o->%2Changed(); }") - .arg(o.name, p.name); + if (p.type.type == BindingType::Object) { + cpp << ", m_" << p.name; + constructorArgs(cpp, conf.findObject(p.type.name), conf); + } else { + cpp << ",\n " << changedF(o, p); + } } if (o.type == ObjectType::List) { cpp << QString(R"(, @@ -434,18 +447,13 @@ void writeCppObject(QTextStream& cpp, const Object& o) { [](%1* o) { o->endRemoveRows(); } - )) { - connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} )").arg(o.name); } if (o.type == ObjectType::UniformTree) { cpp << QString(R"(, [](const %1* o, quintptr id, bool valid) { if (valid) { - int row = %2_row(o->d, id); + int row = %2_row(o->m_d, id); emit o->newDataReady(o->createIndex(row, 0, id)); } else { emit o->newDataReady(QModelIndex()); @@ -459,7 +467,7 @@ void writeCppObject(QTextStream& cpp, const Object& o) { }, [](%1* o, option id, int first, int last) { if (id.some) { - int row = %2_row(o->d, id.value); + int row = %2_row(o->m_d, id.value); o->beginInsertRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginInsertRows(QModelIndex(), first, last); @@ -470,7 +478,7 @@ void writeCppObject(QTextStream& cpp, const Object& o) { }, [](%1* o, option id, int first, int last) { if (id.some) { - int row = %2_row(o->d, id.value); + int row = %2_row(o->m_d, id.value); o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginRemoveRows(QModelIndex(), first, last); @@ -479,44 +487,115 @@ void writeCppObject(QTextStream& cpp, const Object& o) { [](%1* o) { o->endRemoveRows(); } - )) { - connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) { - fetchMore(i); - }, Qt::QueuedConnection); -} )").arg(o.name, lcname); } - if (o.type == ObjectType::Object) { - cpp << QString(")) {}"); +} + +void writeObjectCDecl(QTextStream& cpp, const Object& o, const Configuration& conf) { + const QString lcname(snakeCase(o.name)); + cpp << QString(" %1::Private* %2_new(").arg(o.name, lcname); + constructorArgsDecl(cpp, o, conf); + cpp << ");" << endl; + cpp << QString(" void %2_free(%1::Private*);").arg(o.name, lcname) + << endl; + for (const Property& p: o.properties) { + const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); + if (p.type.type == BindingType::Object) { + cpp << QString(" %3::Private* %2_get(const %1::Private*);") + .arg(o.name, base, p.type.name) << endl; + } else if (p.type.isComplex()) { + cpp << QString(" void %2_get(const %1::Private*, %3);") + .arg(o.name, base, cGetType(p.type)) << endl; + } else { + cpp << QString(" %3 %2_get(const %1::Private*);") + .arg(o.name, base, p.type.name) << endl; + } + if (p.write) { + cpp << QString(" void %2_set(%1::Private*, %3);") + .arg(o.name, base, p.type.cSetType) << endl; + if (p.optional) { + cpp << QString(" void %2_set_none(%1::Private*);") + .arg(o.name, base) << endl; + } + } } - cpp << QString(R"( +} + +void writeCppObject(QTextStream& cpp, const Object& o, const Configuration& conf) { + const QString lcname(snakeCase(o.name)); + cpp << QString("%1::%1(bool /*owned*/, QObject *parent):\n %2(parent),") + .arg(o.name, baseType(o)) << endl; + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + cpp << QString(" m_%1(new %2(false, this)),\n") + .arg(p.name, p.type.name); + } + } + cpp << " m_d(0),\n m_ownsPrivate(false) {}\n"; + cpp << QString("%1::%1(QObject *parent):\n %2(parent),") + .arg(o.name, baseType(o)) << endl; + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + cpp << QString(" m_%1(new %2(false, this)),\n") + .arg(p.name, p.type.name); + } + } + cpp << QString(" m_d(%1_new(this").arg(lcname); + constructorArgs(cpp, o, conf); + cpp << ")),\n m_ownsPrivate(true) {\n"; + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + cpp << QString(" m_%1->m_d = %2_%1_get(this->m_d);\n") + .arg(p.name, snakeCase(o.name)); + } + } + if (o.type != ObjectType::Object) { + cpp << QString(R"( connect(this, &%1::newDataReady, this, [this](const QModelIndex& i) { + fetchMore(i); + }, Qt::QueuedConnection); +)").arg(o.name); + } + cpp << QString(R"(} %1::~%1() { - %2_free(d); + if (m_ownsPrivate) { + %2_free(m_d); + } } )").arg(o.name, lcname); for (const Property& p: o.properties) { const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); - cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name); - if (p.type.isComplex()) { + if (p.type.type == BindingType::Object) { + cpp << QString(R"(const %3* %1::%2() const +{ + return m_%4; +} +%3* %1::%2() +{ + return m_%4; +} +)").arg(o.name, p.name, p.type.name, snakeCase(p.name)); + } else if (p.type.isComplex()) { + cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name); cpp << " " << p.type.name << " v;\n"; - cpp << " " << base << "_get(d, &v, set_" << p.type.name.toLower() + cpp << " " << base << "_get(m_d, &v, set_" << p.type.name.toLower() << ");\n"; cpp << " return v;\n}\n"; } else { - cpp << QString(" return %1_get(d);\n}\n").arg(base); + cpp << QString("%3 %1::%2() const\n{\n").arg(o.name, p.name, p.type.name); + cpp << QString(" return %1_get(m_d);\n}\n").arg(base); } if (p.write) { cpp << "void " << o.name << "::set" << upperInitial(p.name) << "(" << p.type.cppSetType << " v) {" << endl; if (p.optional) { cpp << QString(" if (v.isNull()) {") << endl; - cpp << QString(" %1_set_none(d);").arg(base) << endl; + cpp << QString(" %1_set_none(m_d);").arg(base) << endl; cpp << QString(" } else {") << endl; - cpp << QString(" %1_set(d, v);").arg(base) << endl; + cpp << QString(" %1_set(m_d, v);").arg(base) << endl; cpp << QString(" }") << endl; } else { - cpp << QString(" %1_set(d, v);").arg(base) << endl; + cpp << QString(" %1_set(m_d, v);").arg(base) << endl; } cpp << "}" << endl; } @@ -536,7 +615,12 @@ void writeHeader(const Configuration& conf) { )").arg(guard); for (auto object: conf.objects) { - writeHeaderObject(h, object); + if (object.containsObject()) { + h << "class " << object.name << ";\n"; + } + } + for (auto object: conf.objects) { + writeHeaderObject(h, object, conf); } h << QString("#endif // %1\n").arg(guard); @@ -591,6 +675,19 @@ namespace { int row; quintptr id; }; +)").arg(conf.hFile.fileName()); + + for (auto o: conf.objects) { + for (auto p: o.properties) { + if (p.type.type == BindingType::Object) { + continue; + } + cpp << " inline void " << changedF(o, p) << "(" << o.name << "* o)\n"; + cpp << " {\n emit o->" << p.name << "Changed();\n }\n"; + } + } + + cpp << R"( } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -600,8 +697,7 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - -)").arg(conf.hFile.fileName()); +)"; for (auto object: conf.objects) { if (object.type != ObjectType::Object) { @@ -609,11 +705,11 @@ void set_qbytearray(QByteArray* v, qbytearray_t* val) { } cpp << "extern \"C\" {\n"; - writeObjectCDecl(cpp, object); + writeObjectCDecl(cpp, object, conf); cpp << "};" << endl; } for (auto object: conf.objects) { - writeCppObject(cpp, object); + writeCppObject(cpp, object, conf); } } diff --git a/src/parseJson.cpp b/src/parseJson.cpp index 77bb3d7..ca2b87a 100644 --- a/src/parseJson.cpp +++ b/src/parseJson.cpp @@ -16,78 +16,76 @@ BindingTypeProperties simpleType(BindingType type, const char* name, const char* }; } -const QMap& bindingTypeProperties() { - static QMap p; +QList& bindingTypeProperties() { + static QList p; if (p.empty()) { - QMap f; - f.insert(BindingType::Bool, simpleType(BindingType::Bool, "bool", "true")); - f.insert(BindingType::UChar, { - .type = BindingType::UChar, - .name = "quint8", - .cppSetType = "quint8", - .cSetType = "quint8", - .rustType = "u8", - .rustTypeInit = "0", - }); - f.insert(BindingType::Int, { - .type = BindingType::Int, - .name = "qint32", - .cppSetType = "qint32", - .cSetType = "qint32", - .rustType = "i32", - .rustTypeInit = "0", - }); - f.insert(BindingType::UInt, { - .type = BindingType::UInt, - .name = "quint32", - .cppSetType = "uint", - .cSetType = "uint", - .rustType = "u32", - .rustTypeInit = "0" - }); - f.insert(BindingType::ULongLong, { - .type = BindingType::ULongLong, - .name = "quint64", - .cppSetType = "quint64", - .cSetType = "quint64", - .rustType = "u64", - .rustTypeInit = "0" - }); - f.insert(BindingType::Float, { - .type = BindingType::Float, - .name = "float", - .cppSetType = "float", - .cSetType = "float", - .rustType = "f32", - .rustTypeInit = "0.0" - }); - f.insert(BindingType::QString, { - .type = BindingType::QString, - .name = "QString", - .cppSetType = "const QString&", - .cSetType = "qstring_t", - .rustType = "String", - .rustTypeInit = "String::new()" - }); - f.insert(BindingType::QByteArray, { - .type = BindingType::QByteArray, - .name = "QByteArray", - .cppSetType = "const QByteArray&", - .cSetType = "qbytearray_t", - .rustType = "Vec", - .rustTypeInit = "Vec::new()" - }); + QList f; + f.append(simpleType(BindingType::Bool, "bool", "true")); + f.append({ + .type = BindingType::UChar, + .name = "quint8", + .cppSetType = "quint8", + .cSetType = "quint8", + .rustType = "u8", + .rustTypeInit = "0", + }); + f.append({ + .type = BindingType::Int, + .name = "qint32", + .cppSetType = "qint32", + .cSetType = "qint32", + .rustType = "i32", + .rustTypeInit = "0", + }); + f.append({ + .type = BindingType::UInt, + .name = "quint32", + .cppSetType = "uint", + .cSetType = "uint", + .rustType = "u32", + .rustTypeInit = "0" + }); + f.append({ + .type = BindingType::ULongLong, + .name = "quint64", + .cppSetType = "quint64", + .cSetType = "quint64", + .rustType = "u64", + .rustTypeInit = "0" + }); + f.append({ + .type = BindingType::Float, + .name = "float", + .cppSetType = "float", + .cSetType = "float", + .rustType = "f32", + .rustTypeInit = "0.0" + }); + f.append({ + .type = BindingType::QString, + .name = "QString", + .cppSetType = "const QString&", + .cSetType = "qstring_t", + .rustType = "String", + .rustTypeInit = "String::new()" + }); + f.append({ + .type = BindingType::QByteArray, + .name = "QByteArray", + .cppSetType = "const QByteArray&", + .cSetType = "qbytearray_t", + .rustType = "Vec", + .rustTypeInit = "Vec::new()" + }); p = f; } return p; } BindingTypeProperties parseBindingType(const QString& value) { - QMapIterator i(bindingTypeProperties()); - while (i.hasNext()) { - i.next(); - if (value == i.value().name) { - return i.value(); + for (auto type: bindingTypeProperties()) { + if (value == type.name) { + return type; } } QTextStream err(stderr); @@ -206,7 +204,16 @@ parseConfiguration(const QString& path) { c.hFile = QFileInfo(c.cppFile.dir(), c.cppFile.completeBaseName() + ".h"); const QJsonObject& object = o.value("objects").toObject(); for (const QString& key: object.keys()) { - c.objects.append(parseObject(key, object[key].toObject())); + Object o = parseObject(key, object[key].toObject()); + c.objects.append(o); + bindingTypeProperties().append({ + .type = BindingType::Object, + .name = o.name, + .cppSetType = o.name, + .cSetType = o.name, + .rustType = o.name, + .rustTypeInit = "", + }); } const QJsonObject rust = o.value("rust").toObject(); c.rustdir = QDir(base.filePath(rust.value("dir").toString())); diff --git a/src/rust.cpp b/src/rust.cpp index 4a38557..1382529 100644 --- a/src/rust.cpp +++ b/src/rust.cpp @@ -28,7 +28,86 @@ QString rustTypeInit(const T& p) return p.type.rustTypeInit; } -void writeRustInterfaceObject(QTextStream& r, const Object& o) { +void rConstructorArgsDecl(QTextStream& r, const QString& name, const Object& o, const Configuration& conf) { + r << QString("%2: *mut %1QObject").arg(o.name, name); + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + r << QString(", "); + rConstructorArgsDecl(r, p.name, conf.findObject(p.type.name), conf); + } else { + r << QString(",\n %2_changed: fn(*const %1QObject)") + .arg(o.name, snakeCase(p.name)); + } + } + if (o.type == ObjectType::List) { + r << QString(",\n new_data_ready: fn(*const %1QObject)") + .arg(o.name); + } else if (o.type == ObjectType::UniformTree) { + r << QString(",\n new_data_ready: fn(*const %1QObject, item: usize, valid: bool)") + .arg(o.name); + } + if (o.type != ObjectType::Object) { + QString indexDecl; + if (o.type == ObjectType::UniformTree) { + indexDecl = " item: usize, valid: bool,"; + } + r << QString(R"(, + begin_reset_model: fn(*const %1QObject), + end_reset_model: fn(*const %1QObject), + begin_insert_rows: fn(*const %1QObject,%2 + usize, + usize), + end_insert_rows: fn(*const %1QObject), + begin_remove_rows: fn(*const %1QObject,%2 + usize, + usize), + end_remove_rows: fn(*const %1QObject))").arg(o.name, indexDecl); + } +} + +void rConstructorArgs(QTextStream& r, const QString& name, const Object& o, const Configuration& conf) { + const QString lcname(snakeCase(o.name)); + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + rConstructorArgs(r, p.name, conf.findObject(p.type.name), conf); + } + } + r << QString(R"( let %2_emit = %1Emitter { + qobject: Arc::new(Mutex::new(%2)), +)").arg(o.name, name); + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) continue; + r << QString(" %1_changed: %1_changed,\n").arg(snakeCase(p.name)); + } + if (o.type != ObjectType::Object) { + r << QString(" new_data_ready: new_data_ready,\n"); + } + QString model = ""; + if (o.type != ObjectType::Object) { + const QString type = o.type == ObjectType::List ? "List" : "UniformTree"; + model = ", model"; + r << QString(R"( }; + let model = %1%2 { + qobject: %3, + begin_reset_model: begin_reset_model, + end_reset_model: end_reset_model, + begin_insert_rows: begin_insert_rows, + end_insert_rows: end_insert_rows, + begin_remove_rows: begin_remove_rows, + end_remove_rows: end_remove_rows, +)").arg(o.name, type, name); + } + r << QString(" };\n let d_%3 = %1::create(%3_emit%2") + .arg(o.name, model, name); + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + r << ",\n d_" << p.name; + } + } + r << ");\n"; +} + +void writeRustInterfaceObject(QTextStream& r, const Object& o, const Configuration& conf) { const QString lcname(snakeCase(o.name)); r << QString(R"( pub struct %1QObject {} @@ -38,6 +117,9 @@ pub struct %1Emitter { qobject: Arc>, )").arg(o.name); for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + continue; + } r << QString(" %2_changed: fn(*const %1QObject),\n") .arg(o.name, snakeCase(p.name)); } @@ -58,6 +140,9 @@ impl %1Emitter { } )").arg(o.name); for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + continue; + } r << QString(R"( pub fn %1_changed(&self) { let ptr = *self.qobject.lock().unwrap(); if !ptr.is_null() { @@ -133,14 +218,25 @@ impl %1%2 { r << QString(R"(} pub trait %1Trait { - fn create(emit: %1Emitter%2) -> Self; + fn create(emit: %1Emitter%2)").arg(o.name, modelStruct); + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + r << ",\n " << snakeCase(p.name) << ": " << p.type.name; + } + } + r << QString(R"() -> Self; fn emit(&self) -> &%1Emitter; -)").arg(o.name, modelStruct); +)").arg(o.name); for (const Property& p: o.properties) { const QString lc(snakeCase(p.name)); - r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustType(p)); - if (p.write) { - r << QString(" fn set_%1(&mut self, value: %2);\n").arg(lc, rustType(p)); + if (p.type.type == BindingType::Object) { + r << QString(" fn get_%1(&self) -> &%2;\n").arg(lc, rustType(p)); + r << QString(" fn get_mut_%1(&mut self) -> &mut %2;\n").arg(lc, rustType(p)); + } else { + r << QString(" fn get_%1(&self) -> %2;\n").arg(lc, rustType(p)); + if (p.write) { + r << QString(" fn set_%1(&mut self, value: %2);\n").arg(lc, rustType(p)); + } } } if (o.type == ObjectType::List) { @@ -173,75 +269,30 @@ pub trait %1Trait { r << QString(R"(} #[no_mangle] -pub extern "C" fn %2_new(qobject: *const %1QObject)").arg(o.name, lcname); - for (const Property& p: o.properties) { - r << QString(",\n %2_changed: fn(*const %1QObject)") - .arg(o.name, snakeCase(p.name)); - } - if (o.type == ObjectType::List) { - r << QString(",\n new_data_ready: fn(*const %1QObject)") - .arg(o.name); - } else if (o.type == ObjectType::UniformTree) { - r << QString(",\n new_data_ready: fn(*const %1QObject, item: usize, valid: bool)") - .arg(o.name); - } - if (o.type != ObjectType::Object) { - QString indexDecl; - if (o.type == ObjectType::UniformTree) { - indexDecl = " item: usize, valid: bool,"; - } - r << QString(R"(, - begin_reset_model: fn(*const %1QObject), - end_reset_model: fn(*const %1QObject), - begin_insert_rows: fn(*const %1QObject,%2 - usize, - usize), - end_insert_rows: fn(*const %1QObject), - begin_remove_rows: fn(*const %1QObject,%2 - usize, - usize), - end_remove_rows: fn(*const %1QObject))").arg(o.name, indexDecl); - } - r << QString(R"() - -> *mut %1 { - let emit = %1Emitter { - qobject: Arc::new(Mutex::new(qobject)), -)").arg(o.name); - for (const Property& p: o.properties) { - r << QString(" %1_changed: %1_changed,\n").arg(snakeCase(p.name)); - } - if (o.type != ObjectType::Object) { - r << QString(" new_data_ready: new_data_ready,\n"); - } - QString model = ""; - if (o.type != ObjectType::Object) { - const QString type = o.type == ObjectType::List ? "List" : "UniformTree"; - model = ", model"; - r << QString(R"( }; - let model = %1%2 { - qobject: qobject, - begin_reset_model: begin_reset_model, - end_reset_model: end_reset_model, - begin_insert_rows: begin_insert_rows, - end_insert_rows: end_insert_rows, - begin_remove_rows: begin_remove_rows, - end_remove_rows: end_remove_rows, -)").arg(o.name, type); - } - r << QString(R"( }; - let d = %1::create(emit%3); - Box::into_raw(Box::new(d)) +pub extern "C" fn %1_new()").arg(lcname); + rConstructorArgsDecl(r, lcname, o, conf); + r << QString(")\n -> *mut %1 {\n").arg(o.name); + rConstructorArgs(r, lcname, o, conf); + r << QString(R"( Box::into_raw(Box::new(d_%2)) } #[no_mangle] pub unsafe extern "C" fn %2_free(ptr: *mut %1) { Box::from_raw(ptr).emit().clear(); } -)").arg(o.name, lcname, model); +)").arg(o.name, lcname); for (const Property& p: o.properties) { const QString base = QString("%1_%2").arg(lcname, snakeCase(p.name)); QString ret = ") -> " + rustType(p); - if (p.type.isComplex() && !p.optional) { + if (p.type.type == BindingType::Object) { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %2_get(ptr: *mut %1) -> *mut %4 { + (&mut *ptr).get_mut_%3() +} +)").arg(o.name, base, snakeCase(p.name), rustType(p)); + + } else if (p.type.isComplex() && !p.optional) { r << QString(R"( #[no_mangle] pub unsafe extern "C" fn %2_get(ptr: *const %1, @@ -589,7 +640,7 @@ use %1::*; writeRustTypes(conf, r); for (auto object: conf.objects) { - writeRustInterfaceObject(r, object); + writeRustInterfaceObject(r, object, conf); } } @@ -621,6 +672,11 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) { r << QString(" list: Vec<%1Item>,\n").arg(o.name); } r << "}\n\n"; + for (const Property& p: o.properties) { + if (p.type.type == BindingType::Object) { + modelStruct += ", " + p.name + ": " + p.type.name; + } + } r << QString(R"(impl %1Trait for %1 { fn create(emit: %1Emitter%2) -> %1 { %1 { @@ -631,7 +687,11 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) { } for (const Property& p: o.properties) { const QString lc(snakeCase(p.name)); - r << QString(" %1: %2,\n").arg(lc, rustTypeInit(p)); + if (p.type.type == BindingType::Object) { + r << QString(" %1: %1,\n").arg(lc); + } else { + r << QString(" %1: %2,\n").arg(lc, rustTypeInit(p)); + } } if (o.type != ObjectType::Object) { r << QString(" list: vec![%1Item::default(); 10],\n") @@ -645,19 +705,29 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) { )").arg(o.name); for (const Property& p: o.properties) { const QString lc(snakeCase(p.name)); - r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustType(p)); - if (p.type.isComplex()) { - r << QString(" self.%1.clone()\n").arg(lc); + if (p.type.type == BindingType::Object) { + r << QString(R"( fn get_%1(&self) -> &%2 { + &self.%1 + } + fn get_mut_%1(&mut self) -> &mut %2 { + &mut self.%1 + } +)").arg(lc, rustType(p)); } else { - r << QString(" self.%1\n").arg(lc); - } - r << " }\n"; - if (p.write) { - r << QString(R"( fn set_%1(&mut self, value: %2) { + r << QString(" fn get_%1(&self) -> %2 {\n").arg(lc, rustType(p)); + if (p.type.isComplex()) { + r << QString(" self.%1.clone()\n").arg(lc); + } else { + r << QString(" self.%1\n").arg(lc); + } + r << " }\n"; + if (p.write) { + r << QString(R"( fn set_%1(&mut self, value: %2) { self.%1 = value; self.emit.%1_changed(); } -)").arg(lc, rustType(p)); + )").arg(lc, rustType(p)); + } } } if (o.type == ObjectType::List) { diff --git a/src/structs.h b/src/structs.h index cc14e76..ded3783 100644 --- a/src/structs.h +++ b/src/structs.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include enum class ObjectType { Object, @@ -18,7 +20,8 @@ enum class BindingType { ULongLong, Float, QString, - QByteArray + QByteArray, + Object, }; struct BindingTypeProperties { @@ -54,6 +57,14 @@ struct Object { QList properties; QList itemProperties; int columnCount; + bool containsObject() { + for (auto p: properties) { + if (p.type.type == BindingType::Object) { + return true; + } + } + return false; + } }; struct Configuration { @@ -64,5 +75,17 @@ struct Configuration { QString implementationModule; QList objects; bool overwriteImplementation; + const Object& findObject(const QString& name) const { + for (auto& o: objects) { + if (o.name == name) { + return o; + } + } + QTextStream err(stderr); + err << QCoreApplication::translate("main", + "Cannot find type %1.\n").arg(name); + err.flush(); + exit(1); + } }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cc3fad3..9c66041 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -65,3 +65,4 @@ rust_test(test_object rust_object) rust_test(test_object_types rust_object_types) rust_test(test_list rust_list) rust_test(test_tree rust_tree) +rust_test(test_objects rust_objects) diff --git a/tests/rust_list/src/interface.rs b/tests/rust_list/src/interface.rs index 4b813df..b5f7943 100644 --- a/tests/rust_list/src/interface.rs +++ b/tests/rust_list/src/interface.rs @@ -139,7 +139,7 @@ pub trait PersonsTrait { } #[no_mangle] -pub extern "C" fn persons_new(qobject: *const PersonsQObject, +pub extern "C" fn persons_new(persons: *mut PersonsQObject, new_data_ready: fn(*const PersonsQObject), begin_reset_model: fn(*const PersonsQObject), end_reset_model: fn(*const PersonsQObject), @@ -152,12 +152,12 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject, usize), end_remove_rows: fn(*const PersonsQObject)) -> *mut Persons { - let emit = PersonsEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let persons_emit = PersonsEmitter { + qobject: Arc::new(Mutex::new(persons)), new_data_ready: new_data_ready, }; let model = PersonsList { - qobject: qobject, + qobject: persons, begin_reset_model: begin_reset_model, end_reset_model: end_reset_model, begin_insert_rows: begin_insert_rows, @@ -165,8 +165,8 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject, begin_remove_rows: begin_remove_rows, end_remove_rows: end_remove_rows, }; - let d = Persons::create(emit, model); - Box::into_raw(Box::new(d)) + let d_persons = Persons::create(persons_emit, model); + Box::into_raw(Box::new(d_persons)) } #[no_mangle] diff --git a/tests/rust_object/src/implementation.rs b/tests/rust_object/src/implementation.rs index f3c1143..44c0081 100644 --- a/tests/rust_object/src/implementation.rs +++ b/tests/rust_object/src/implementation.rs @@ -25,4 +25,4 @@ impl PersonTrait for Person { self.user_name = value; self.emit.user_name_changed(); } -} + } diff --git a/tests/rust_object/src/interface.rs b/tests/rust_object/src/interface.rs index 400cc59..be24695 100644 --- a/tests/rust_object/src/interface.rs +++ b/tests/rust_object/src/interface.rs @@ -68,15 +68,15 @@ pub trait PersonTrait { } #[no_mangle] -pub extern "C" fn person_new(qobject: *const PersonQObject, +pub extern "C" fn person_new(person: *mut PersonQObject, user_name_changed: fn(*const PersonQObject)) -> *mut Person { - let emit = PersonEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let person_emit = PersonEmitter { + qobject: Arc::new(Mutex::new(person)), user_name_changed: user_name_changed, }; - let d = Person::create(emit); - Box::into_raw(Box::new(d)) + let d_person = Person::create(person_emit); + Box::into_raw(Box::new(d_person)) } #[no_mangle] diff --git a/tests/rust_object_types/src/implementation.rs b/tests/rust_object_types/src/implementation.rs index 55afc7e..b36c5d8 100644 --- a/tests/rust_object_types/src/implementation.rs +++ b/tests/rust_object_types/src/implementation.rs @@ -39,53 +39,53 @@ impl ObjectTrait for Object { self.boolean = value; self.emit.boolean_changed(); } - fn get_bytearray(&self) -> Vec { + fn get_bytearray(&self) -> Vec { self.bytearray.clone() } fn set_bytearray(&mut self, value: Vec) { self.bytearray = value; self.emit.bytearray_changed(); } - fn get_integer(&self) -> i32 { + fn get_integer(&self) -> i32 { self.integer } fn set_integer(&mut self, value: i32) { self.integer = value; self.emit.integer_changed(); } - fn get_optional_bytearray(&self) -> Option> { + fn get_optional_bytearray(&self) -> Option> { self.optional_bytearray.clone() } fn set_optional_bytearray(&mut self, value: Option>) { self.optional_bytearray = value; self.emit.optional_bytearray_changed(); } - fn get_optional_string(&self) -> Option { + fn get_optional_string(&self) -> Option { self.optional_string.clone() } fn set_optional_string(&mut self, value: Option) { self.optional_string = value; self.emit.optional_string_changed(); } - fn get_string(&self) -> String { + fn get_string(&self) -> String { self.string.clone() } fn set_string(&mut self, value: String) { self.string = value; self.emit.string_changed(); } - fn get_u64(&self) -> u64 { + fn get_u64(&self) -> u64 { self.u64 } fn set_u64(&mut self, value: u64) { self.u64 = value; self.emit.u64_changed(); } - fn get_uinteger(&self) -> u32 { + fn get_uinteger(&self) -> u32 { self.uinteger } fn set_uinteger(&mut self, value: u32) { self.uinteger = value; self.emit.uinteger_changed(); } -} + } diff --git a/tests/rust_object_types/src/interface.rs b/tests/rust_object_types/src/interface.rs index fdc2a58..6435630 100644 --- a/tests/rust_object_types/src/interface.rs +++ b/tests/rust_object_types/src/interface.rs @@ -177,7 +177,7 @@ pub trait ObjectTrait { } #[no_mangle] -pub extern "C" fn object_new(qobject: *const ObjectQObject, +pub extern "C" fn object_new(object: *mut ObjectQObject, boolean_changed: fn(*const ObjectQObject), bytearray_changed: fn(*const ObjectQObject), integer_changed: fn(*const ObjectQObject), @@ -187,8 +187,8 @@ pub extern "C" fn object_new(qobject: *const ObjectQObject, u64_changed: fn(*const ObjectQObject), uinteger_changed: fn(*const ObjectQObject)) -> *mut Object { - let emit = ObjectEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let object_emit = ObjectEmitter { + qobject: Arc::new(Mutex::new(object)), boolean_changed: boolean_changed, bytearray_changed: bytearray_changed, integer_changed: integer_changed, @@ -198,8 +198,8 @@ pub extern "C" fn object_new(qobject: *const ObjectQObject, u64_changed: u64_changed, uinteger_changed: uinteger_changed, }; - let d = Object::create(emit); - Box::into_raw(Box::new(d)) + let d_object = Object::create(object_emit); + Box::into_raw(Box::new(d_object)) } #[no_mangle] diff --git a/tests/rust_objects/Cargo.toml b/tests/rust_objects/Cargo.toml new file mode 100644 index 0000000..5b335ab --- /dev/null +++ b/tests/rust_objects/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust_objects" +version = "1.0.0" + +[dependencies] +libc = "*" + +[lib] +name = "rust" +crate-type = ["staticlib"] diff --git a/tests/rust_objects/src/implementation.rs b/tests/rust_objects/src/implementation.rs new file mode 100644 index 0000000..a7b2264 --- /dev/null +++ b/tests/rust_objects/src/implementation.rs @@ -0,0 +1,50 @@ +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(dead_code)] +use interface::*; + +pub struct InnerObject { + emit: InnerObjectEmitter, + description: String, +} + +impl InnerObjectTrait for InnerObject { + fn create(emit: InnerObjectEmitter) -> InnerObject { + InnerObject { + emit: emit, + description: String::new(), + } + } + fn emit(&self) -> &InnerObjectEmitter { + &self.emit + } + fn get_description(&self) -> String { + self.description.clone() + } + fn set_description(&mut self, value: String) { + self.description = value; + self.emit.description_changed(); + } + } +pub struct Person { + emit: PersonEmitter, + object: InnerObject, +} + +impl PersonTrait for Person { + fn create(emit: PersonEmitter, object: InnerObject) -> Person { + Person { + emit: emit, + object: object, + } + } + fn emit(&self) -> &PersonEmitter { + &self.emit + } + fn get_object(&self) -> &InnerObject { + &self.object + } + fn get_mut_object(&mut self) -> &mut InnerObject { + &mut self.object + } +} diff --git a/tests/rust_objects/src/interface.rs b/tests/rust_objects/src/interface.rs new file mode 100644 index 0000000..508244f --- /dev/null +++ b/tests/rust_objects/src/interface.rs @@ -0,0 +1,148 @@ +/* generated by rust_qt_binding_generator */ +#![allow(unknown_lints)] +#![allow(mutex_atomic, needless_pass_by_value)] +use libc::{c_int, c_void, uint8_t, uint16_t}; +use std::slice; + +use std::sync::{Arc, Mutex}; +use std::ptr::null; + +use implementation::*; + + +#[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 { + 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(), + } + } +} + +pub struct InnerObjectQObject {} + +#[derive (Clone)] +pub struct InnerObjectEmitter { + qobject: Arc>, + description_changed: fn(*const InnerObjectQObject), +} + +unsafe impl Send for InnerObjectEmitter {} + +impl InnerObjectEmitter { + fn clear(&self) { + *self.qobject.lock().unwrap() = null(); + } + pub fn description_changed(&self) { + let ptr = *self.qobject.lock().unwrap(); + if !ptr.is_null() { + (self.description_changed)(ptr); + } + } +} + +pub trait InnerObjectTrait { + fn create(emit: InnerObjectEmitter) -> Self; + fn emit(&self) -> &InnerObjectEmitter; + fn get_description(&self) -> String; + fn set_description(&mut self, value: String); +} + +#[no_mangle] +pub extern "C" fn inner_object_new(inner_object: *mut InnerObjectQObject, + description_changed: fn(*const InnerObjectQObject)) + -> *mut InnerObject { + let inner_object_emit = InnerObjectEmitter { + qobject: Arc::new(Mutex::new(inner_object)), + description_changed: description_changed, + }; + let d_inner_object = InnerObject::create(inner_object_emit); + Box::into_raw(Box::new(d_inner_object)) +} + +#[no_mangle] +pub unsafe extern "C" fn inner_object_free(ptr: *mut InnerObject) { + Box::from_raw(ptr).emit().clear(); +} + +#[no_mangle] +pub unsafe extern "C" fn inner_object_description_get(ptr: *const InnerObject, + p: *mut c_void, + set: fn(*mut c_void, QString)) { + let data = (&*ptr).get_description(); + set(p, QString::from(&data)); +} + +#[no_mangle] +pub unsafe extern "C" fn inner_object_description_set(ptr: *mut InnerObject, v: QStringIn) { + (&mut *ptr).set_description(v.convert()); +} + +pub struct PersonQObject {} + +#[derive (Clone)] +pub struct PersonEmitter { + qobject: Arc>, +} + +unsafe impl Send for PersonEmitter {} + +impl PersonEmitter { + fn clear(&self) { + *self.qobject.lock().unwrap() = null(); + } +} + +pub trait PersonTrait { + fn create(emit: PersonEmitter, + object: InnerObject) -> Self; + fn emit(&self) -> &PersonEmitter; + fn get_object(&self) -> &InnerObject; + fn get_mut_object(&mut self) -> &mut InnerObject; +} + +#[no_mangle] +pub extern "C" fn person_new(person: *mut PersonQObject, object: *mut InnerObjectQObject, + description_changed: fn(*const InnerObjectQObject)) + -> *mut Person { + let object_emit = InnerObjectEmitter { + qobject: Arc::new(Mutex::new(object)), + description_changed: description_changed, + }; + let d_object = InnerObject::create(object_emit); + let person_emit = PersonEmitter { + qobject: Arc::new(Mutex::new(person)), + }; + let d_person = Person::create(person_emit, + d_object); + Box::into_raw(Box::new(d_person)) +} + +#[no_mangle] +pub unsafe extern "C" fn person_free(ptr: *mut Person) { + Box::from_raw(ptr).emit().clear(); +} + +#[no_mangle] +pub unsafe extern "C" fn person_object_get(ptr: *mut Person) -> *mut InnerObject { + (&mut *ptr).get_mut_object() +} diff --git a/tests/rust_objects/src/lib.rs b/tests/rust_objects/src/lib.rs new file mode 100644 index 0000000..d7eb847 --- /dev/null +++ b/tests/rust_objects/src/lib.rs @@ -0,0 +1,4 @@ +extern crate libc; + +pub mod interface; +mod implementation; diff --git a/tests/rust_tree/src/interface.rs b/tests/rust_tree/src/interface.rs index 6f812fb..5e4401e 100644 --- a/tests/rust_tree/src/interface.rs +++ b/tests/rust_tree/src/interface.rs @@ -142,7 +142,7 @@ pub trait PersonsTrait { } #[no_mangle] -pub extern "C" fn persons_new(qobject: *const PersonsQObject, +pub extern "C" fn persons_new(persons: *mut PersonsQObject, new_data_ready: fn(*const PersonsQObject, item: usize, valid: bool), begin_reset_model: fn(*const PersonsQObject), end_reset_model: fn(*const PersonsQObject), @@ -155,12 +155,12 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject, usize), end_remove_rows: fn(*const PersonsQObject)) -> *mut Persons { - let emit = PersonsEmitter { - qobject: Arc::new(Mutex::new(qobject)), + let persons_emit = PersonsEmitter { + qobject: Arc::new(Mutex::new(persons)), new_data_ready: new_data_ready, }; let model = PersonsUniformTree { - qobject: qobject, + qobject: persons, begin_reset_model: begin_reset_model, end_reset_model: end_reset_model, begin_insert_rows: begin_insert_rows, @@ -168,8 +168,8 @@ pub extern "C" fn persons_new(qobject: *const PersonsQObject, begin_remove_rows: begin_remove_rows, end_remove_rows: end_remove_rows, }; - let d = Persons::create(emit, model); - Box::into_raw(Box::new(d)) + let d_persons = Persons::create(persons_emit, model); + Box::into_raw(Box::new(d_persons)) } #[no_mangle] diff --git a/tests/test_list_rust.cpp b/tests/test_list_rust.cpp index 0995e57..4297a03 100644 --- a/tests/test_list_rust.cpp +++ b/tests/test_list_rust.cpp @@ -44,6 +44,7 @@ namespace { int row; quintptr id; }; + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { void persons_data_user_name(const Persons::Private*, int, QString*, qstring_set); bool persons_set_data_user_name(Persons::Private*, int, qstring_t); @@ -75,7 +75,7 @@ bool Persons::hasChildren(const QModelIndex &parent) const int Persons::rowCount(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : persons_row_count(d); + return (parent.isValid()) ? 0 : persons_row_count(m_d); } QModelIndex Persons::index(int row, int column, const QModelIndex &parent) const @@ -93,19 +93,19 @@ QModelIndex Persons::parent(const QModelIndex &) const bool Persons::canFetchMore(const QModelIndex &parent) const { - return (parent.isValid()) ? 0 : persons_can_fetch_more(d); + return (parent.isValid()) ? 0 : persons_can_fetch_more(m_d); } void Persons::fetchMore(const QModelIndex &parent) { if (!parent.isValid()) { - persons_fetch_more(d); + persons_fetch_more(m_d); } } void Persons::sort(int column, Qt::SortOrder order) { - persons_sort(d, column, order); + persons_sort(m_d, column, order); } Qt::ItemFlags Persons::flags(const QModelIndex &i) const { @@ -127,7 +127,7 @@ QVariant Persons::data(const QModelIndex &index, int role) const case Qt::DisplayRole: case Qt::EditRole: case Qt::UserRole + 0: - persons_data_user_name(d, index.row(), &s, set_qstring); + persons_data_user_name(m_d, index.row(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; } @@ -145,7 +145,7 @@ bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) bool set = false; if (index.column() == 0) { if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) { - set = persons_set_data_user_name(d, index.row(), value.value()); + set = persons_set_data_user_name(m_d, index.row(), value.value()); } } if (set) { @@ -164,9 +164,13 @@ extern "C" { void (*)(Persons*)); void persons_free(Persons::Private*); }; +Persons::Persons(bool /*owned*/, QObject *parent): + QAbstractItemModel(parent), + m_d(0), + m_ownsPrivate(false) {} Persons::Persons(QObject *parent): QAbstractItemModel(parent), - d(persons_new(this, + m_d(persons_new(this, [](const Persons* o) { emit o->newDataReady(QModelIndex()); }, @@ -188,13 +192,15 @@ Persons::Persons(QObject *parent): [](Persons* o) { o->endRemoveRows(); } - )) { +)), + m_ownsPrivate(true) { connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) { fetchMore(i); }, Qt::QueuedConnection); } - Persons::~Persons() { - persons_free(d); + if (m_ownsPrivate) { + persons_free(m_d); + } } diff --git a/tests/test_list_rust.h b/tests/test_list_rust.h index 5e568ce..bcd1448 100644 --- a/tests/test_list_rust.h +++ b/tests/test_list_rust.h @@ -11,7 +11,9 @@ class Persons : public QAbstractItemModel public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; + explicit Persons(bool owned, QObject *parent); public: explicit Persons(QObject *parent = nullptr); ~Persons(); @@ -32,6 +34,5 @@ signals: // new data is ready to be made available to the model with fetchMore() void newDataReady(const QModelIndex &parent) const; signals: -private: }; #endif // TEST_LIST_RUST_H diff --git a/tests/test_object_rust.cpp b/tests/test_object_rust.cpp index 9bc26d4..127304f 100644 --- a/tests/test_object_rust.cpp +++ b/tests/test_object_rust.cpp @@ -44,6 +44,11 @@ namespace { int row; quintptr id; }; + inline void personUserNameChanged(Person* o) + { + emit o->userNameChanged(); + } + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,27 +58,34 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { Person::Private* person_new(Person*, void (*)(Person*)); void person_free(Person::Private*); void person_user_name_get(const Person::Private*, QString*, qstring_set); void person_user_name_set(Person::Private*, qstring_t); }; +Person::Person(bool /*owned*/, QObject *parent): + QObject(parent), + m_d(0), + m_ownsPrivate(false) {} Person::Person(QObject *parent): QObject(parent), - d(person_new(this, - [](Person* o) { emit o->userNameChanged(); })) {} + m_d(person_new(this, + personUserNameChanged)), + m_ownsPrivate(true) { +} Person::~Person() { - person_free(d); + if (m_ownsPrivate) { + person_free(m_d); + } } QString Person::userName() const { QString v; - person_user_name_get(d, &v, set_qstring); + person_user_name_get(m_d, &v, set_qstring); return v; } void Person::setUserName(const QString& v) { - person_user_name_set(d, v); + person_user_name_set(m_d, v); } diff --git a/tests/test_object_rust.h b/tests/test_object_rust.h index 9463926..e6c378d 100644 --- a/tests/test_object_rust.h +++ b/tests/test_object_rust.h @@ -11,8 +11,10 @@ class Person : public QObject public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged FINAL) + explicit Person(bool owned, QObject *parent); public: explicit Person(QObject *parent = nullptr); ~Person(); @@ -20,7 +22,5 @@ public: void setUserName(const QString& v); signals: void userNameChanged(); -private: - QString m_userName; }; #endif // TEST_OBJECT_RUST_H diff --git a/tests/test_object_types_rust.cpp b/tests/test_object_types_rust.cpp index ded24c6..faac038 100644 --- a/tests/test_object_types_rust.cpp +++ b/tests/test_object_types_rust.cpp @@ -44,6 +44,39 @@ namespace { int row; quintptr id; }; + inline void objectBooleanChanged(Object* o) + { + emit o->booleanChanged(); + } + inline void objectBytearrayChanged(Object* o) + { + emit o->bytearrayChanged(); + } + inline void objectIntegerChanged(Object* o) + { + emit o->integerChanged(); + } + inline void objectOptionalBytearrayChanged(Object* o) + { + emit o->optionalBytearrayChanged(); + } + inline void objectOptionalStringChanged(Object* o) + { + emit o->optionalStringChanged(); + } + inline void objectStringChanged(Object* o) + { + emit o->stringChanged(); + } + inline void objectU64Changed(Object* o) + { + emit o->u64Changed(); + } + inline void objectUintegerChanged(Object* o) + { + emit o->uintegerChanged(); + } + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,7 +86,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { Object::Private* object_new(Object*, void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*), void (*)(Object*)); void object_free(Object::Private*); @@ -76,90 +108,98 @@ extern "C" { quint32 object_uinteger_get(const Object::Private*); void object_uinteger_set(Object::Private*, uint); }; +Object::Object(bool /*owned*/, QObject *parent): + QObject(parent), + m_d(0), + m_ownsPrivate(false) {} Object::Object(QObject *parent): QObject(parent), - d(object_new(this, - [](Object* o) { emit o->booleanChanged(); }, - [](Object* o) { emit o->bytearrayChanged(); }, - [](Object* o) { emit o->integerChanged(); }, - [](Object* o) { emit o->optionalBytearrayChanged(); }, - [](Object* o) { emit o->optionalStringChanged(); }, - [](Object* o) { emit o->stringChanged(); }, - [](Object* o) { emit o->u64Changed(); }, - [](Object* o) { emit o->uintegerChanged(); })) {} + m_d(object_new(this, + objectBooleanChanged, + objectBytearrayChanged, + objectIntegerChanged, + objectOptionalBytearrayChanged, + objectOptionalStringChanged, + objectStringChanged, + objectU64Changed, + objectUintegerChanged)), + m_ownsPrivate(true) { +} Object::~Object() { - object_free(d); + if (m_ownsPrivate) { + object_free(m_d); + } } bool Object::boolean() const { - return object_boolean_get(d); + return object_boolean_get(m_d); } void Object::setBoolean(bool v) { - object_boolean_set(d, v); + object_boolean_set(m_d, v); } QByteArray Object::bytearray() const { QByteArray v; - object_bytearray_get(d, &v, set_qbytearray); + object_bytearray_get(m_d, &v, set_qbytearray); return v; } void Object::setBytearray(const QByteArray& v) { - object_bytearray_set(d, v); + object_bytearray_set(m_d, v); } qint32 Object::integer() const { - return object_integer_get(d); + return object_integer_get(m_d); } void Object::setInteger(qint32 v) { - object_integer_set(d, v); + object_integer_set(m_d, v); } QByteArray Object::optionalBytearray() const { QByteArray v; - object_optional_bytearray_get(d, &v, set_qbytearray); + object_optional_bytearray_get(m_d, &v, set_qbytearray); return v; } void Object::setOptionalBytearray(const QByteArray& v) { if (v.isNull()) { - object_optional_bytearray_set_none(d); + object_optional_bytearray_set_none(m_d); } else { - object_optional_bytearray_set(d, v); + object_optional_bytearray_set(m_d, v); } } QString Object::optionalString() const { QString v; - object_optional_string_get(d, &v, set_qstring); + object_optional_string_get(m_d, &v, set_qstring); return v; } void Object::setOptionalString(const QString& v) { if (v.isNull()) { - object_optional_string_set_none(d); + object_optional_string_set_none(m_d); } else { - object_optional_string_set(d, v); + object_optional_string_set(m_d, v); } } QString Object::string() const { QString v; - object_string_get(d, &v, set_qstring); + object_string_get(m_d, &v, set_qstring); return v; } void Object::setString(const QString& v) { - object_string_set(d, v); + object_string_set(m_d, v); } quint64 Object::u64() const { - return object_u64_get(d); + return object_u64_get(m_d); } void Object::setU64(quint64 v) { - object_u64_set(d, v); + object_u64_set(m_d, v); } quint32 Object::uinteger() const { - return object_uinteger_get(d); + return object_uinteger_get(m_d); } void Object::setUinteger(uint v) { - object_uinteger_set(d, v); + object_uinteger_set(m_d, v); } diff --git a/tests/test_object_types_rust.h b/tests/test_object_types_rust.h index a6ad932..8252cce 100644 --- a/tests/test_object_types_rust.h +++ b/tests/test_object_types_rust.h @@ -11,7 +11,8 @@ class Object : public QObject public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; Q_PROPERTY(bool boolean READ boolean WRITE setBoolean NOTIFY booleanChanged FINAL) Q_PROPERTY(QByteArray bytearray READ bytearray WRITE setBytearray NOTIFY bytearrayChanged FINAL) Q_PROPERTY(qint32 integer READ integer WRITE setInteger NOTIFY integerChanged FINAL) @@ -20,6 +21,7 @@ private: Q_PROPERTY(QString string READ string WRITE setString NOTIFY stringChanged FINAL) Q_PROPERTY(quint64 u64 READ u64 WRITE setU64 NOTIFY u64Changed FINAL) Q_PROPERTY(quint32 uinteger READ uinteger WRITE setUinteger NOTIFY uintegerChanged FINAL) + explicit Object(bool owned, QObject *parent); public: explicit Object(QObject *parent = nullptr); ~Object(); @@ -48,14 +50,5 @@ signals: void stringChanged(); void u64Changed(); void uintegerChanged(); -private: - bool m_boolean; - QByteArray m_bytearray; - qint32 m_integer; - QByteArray m_optionalBytearray; - QString m_optionalString; - QString m_string; - quint64 m_u64; - quint32 m_uinteger; }; #endif // TEST_OBJECT_TYPES_RUST_H diff --git a/tests/test_objects.cpp b/tests/test_objects.cpp new file mode 100644 index 0000000..a0eb95e --- /dev/null +++ b/tests/test_objects.cpp @@ -0,0 +1,41 @@ +#include "test_objects_rust.h" +#include +#include + +class TestRustObjects : public QObject +{ + Q_OBJECT +private slots: + void testConstructor(); + void testStringGetter(); + void testStringSetter(); +}; + +void TestRustObjects::testConstructor() +{ + Person person; +} + +void TestRustObjects::testStringGetter() +{ + Person person; + person.object()->setDescription("Konqi"); +} + +void TestRustObjects::testStringSetter() +{ + // GIVEN + Person person; + QSignalSpy spy(person.object(), &InnerObject::descriptionChanged); + + // WHEN + person.object()->setDescription("Konqi"); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + QCOMPARE(person.object()->description(), QString("Konqi")); +} + +QTEST_MAIN(TestRustObjects) +#include "test_objects.moc" diff --git a/tests/test_objects.json b/tests/test_objects.json new file mode 100644 index 0000000..1daac94 --- /dev/null +++ b/tests/test_objects.json @@ -0,0 +1,28 @@ +{ + "cppFile": "test_objects_rust.cpp", + "rust": { + "dir": "rust_objects", + "interfaceModule": "interface", + "implementationModule": "implementation", + "typesModule": "types" + }, + "objects": { + "InnerObject": { + "type": "Object", + "properties": { + "description": { + "type": "QString", + "write": true + } + } + }, + "Person": { + "type": "Object", + "properties": { + "object": { + "type": "InnerObject" + } + } + } + } +} diff --git a/tests/test_objects_rust.cpp b/tests/test_objects_rust.cpp new file mode 100644 index 0000000..9abefc9 --- /dev/null +++ b/tests/test_objects_rust.cpp @@ -0,0 +1,123 @@ +/* generated by rust_qt_binding_generator */ +#include "test_objects_rust.h" + +namespace { + template + struct option { + public: + T value; + bool some; + operator QVariant() const { + if (some) { + return QVariant(value); + } + return QVariant(); + } + }; + 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; + quintptr id; + }; + inline void innerObjectDescriptionChanged(InnerObject* o) + { + emit o->descriptionChanged(); + } + +} +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; +} +extern "C" { + InnerObject::Private* inner_object_new(InnerObject*, void (*)(InnerObject*)); + void inner_object_free(InnerObject::Private*); + void inner_object_description_get(const InnerObject::Private*, QString*, qstring_set); + void inner_object_description_set(InnerObject::Private*, qstring_t); +}; +extern "C" { + Person::Private* person_new(Person*, InnerObject*, void (*)(InnerObject*)); + void person_free(Person::Private*); + InnerObject::Private* person_object_get(const Person::Private*); +}; +InnerObject::InnerObject(bool /*owned*/, QObject *parent): + QObject(parent), + m_d(0), + m_ownsPrivate(false) {} +InnerObject::InnerObject(QObject *parent): + QObject(parent), + m_d(inner_object_new(this, + innerObjectDescriptionChanged)), + m_ownsPrivate(true) { +} + +InnerObject::~InnerObject() { + if (m_ownsPrivate) { + inner_object_free(m_d); + } +} +QString InnerObject::description() const +{ + QString v; + inner_object_description_get(m_d, &v, set_qstring); + return v; +} +void InnerObject::setDescription(const QString& v) { + inner_object_description_set(m_d, v); +} +Person::Person(bool /*owned*/, QObject *parent): + QObject(parent), + m_object(new InnerObject(false, this)), + m_d(0), + m_ownsPrivate(false) {} +Person::Person(QObject *parent): + QObject(parent), + m_object(new InnerObject(false, this)), + m_d(person_new(this, m_object, + innerObjectDescriptionChanged)), + m_ownsPrivate(true) { + m_object->m_d = person_object_get(this->m_d); +} + +Person::~Person() { + if (m_ownsPrivate) { + person_free(m_d); + } +} +const InnerObject* Person::object() const +{ + return m_object; +} +InnerObject* Person::object() +{ + return m_object; +} diff --git a/tests/test_objects_rust.h b/tests/test_objects_rust.h new file mode 100644 index 0000000..2de6252 --- /dev/null +++ b/tests/test_objects_rust.h @@ -0,0 +1,48 @@ +/* generated by rust_qt_binding_generator */ +#ifndef TEST_OBJECTS_RUST_H +#define TEST_OBJECTS_RUST_H + +#include +#include +class Person; + +class InnerObject : public QObject +{ + Q_OBJECT + friend class Person; +public: + class Private; +private: + Private * m_d; + bool m_ownsPrivate; + Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL) + explicit InnerObject(bool owned, QObject *parent); +public: + explicit InnerObject(QObject *parent = nullptr); + ~InnerObject(); + QString description() const; + void setDescription(const QString& v); +signals: + void descriptionChanged(); +}; + +class Person : public QObject +{ + Q_OBJECT + friend class Person; +public: + class Private; +private: + InnerObject* const m_object; + Private * m_d; + bool m_ownsPrivate; + Q_PROPERTY(InnerObject* object READ object FINAL) + explicit Person(bool owned, QObject *parent); +public: + explicit Person(QObject *parent = nullptr); + ~Person(); + const InnerObject* object() const; + InnerObject* object(); +signals: +}; +#endif // TEST_OBJECTS_RUST_H diff --git a/tests/test_tree_rust.cpp b/tests/test_tree_rust.cpp index 9ab1607..aaff5e4 100644 --- a/tests/test_tree_rust.cpp +++ b/tests/test_tree_rust.cpp @@ -44,6 +44,7 @@ namespace { int row; quintptr id; }; + } typedef void (*qstring_set)(QString*, qstring_t*); void set_qstring(QString* v, qstring_t* val) { @@ -53,7 +54,6 @@ typedef void (*qbytearray_set)(QByteArray*, qbytearray_t*); void set_qbytearray(QByteArray* v, qbytearray_t* val) { *v = *val; } - extern "C" { void persons_data_user_name(const Persons::Private*, quintptr, QString*, qstring_set); bool persons_set_data_user_name(Persons::Private*, quintptr, qstring_t); @@ -81,7 +81,7 @@ int Persons::rowCount(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return 0; } - return persons_row_count(d, parent.internalId(), parent.isValid()); + return persons_row_count(m_d, parent.internalId(), parent.isValid()); } QModelIndex Persons::index(int row, int column, const QModelIndex &parent) const @@ -95,7 +95,7 @@ QModelIndex Persons::index(int row, int column, const QModelIndex &parent) const if (row >= rowCount(parent)) { return QModelIndex(); } - const quintptr id = persons_index(d, parent.internalId(), parent.isValid(), row); + const quintptr id = persons_index(m_d, parent.internalId(), parent.isValid(), row); return createIndex(row, column, id); } @@ -104,7 +104,7 @@ QModelIndex Persons::parent(const QModelIndex &index) const if (!index.isValid()) { return QModelIndex(); } - const qmodelindex_t parent = persons_parent(d, index.internalId()); + const qmodelindex_t parent = persons_parent(m_d, index.internalId()); return parent.row >= 0 ?createIndex(parent.row, 0, parent.id) :QModelIndex(); } @@ -113,17 +113,17 @@ bool Persons::canFetchMore(const QModelIndex &parent) const if (parent.isValid() && parent.column() != 0) { return false; } - return persons_can_fetch_more(d, parent.internalId(), parent.isValid()); + return persons_can_fetch_more(m_d, parent.internalId(), parent.isValid()); } void Persons::fetchMore(const QModelIndex &parent) { - persons_fetch_more(d, parent.internalId(), parent.isValid()); + persons_fetch_more(m_d, parent.internalId(), parent.isValid()); } void Persons::sort(int column, Qt::SortOrder order) { - persons_sort(d, column, order); + persons_sort(m_d, column, order); } Qt::ItemFlags Persons::flags(const QModelIndex &i) const { @@ -145,7 +145,7 @@ QVariant Persons::data(const QModelIndex &index, int role) const case Qt::DisplayRole: case Qt::EditRole: case Qt::UserRole + 0: - persons_data_user_name(d, index.internalId(), &s, set_qstring); + persons_data_user_name(m_d, index.internalId(), &s, set_qstring); if (!s.isNull()) v.setValue(s); break; } @@ -163,7 +163,7 @@ bool Persons::setData(const QModelIndex &index, const QVariant &value, int role) bool set = false; if (index.column() == 0) { if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) { - set = persons_set_data_user_name(d, index.internalId(), value.value()); + set = persons_set_data_user_name(m_d, index.internalId(), value.value()); } } if (set) { @@ -182,12 +182,16 @@ extern "C" { void (*)(Persons*)); void persons_free(Persons::Private*); }; +Persons::Persons(bool /*owned*/, QObject *parent): + QAbstractItemModel(parent), + m_d(0), + m_ownsPrivate(false) {} Persons::Persons(QObject *parent): QAbstractItemModel(parent), - d(persons_new(this, + m_d(persons_new(this, [](const Persons* o, quintptr id, bool valid) { if (valid) { - int row = persons_row(o->d, id); + int row = persons_row(o->m_d, id); emit o->newDataReady(o->createIndex(row, 0, id)); } else { emit o->newDataReady(QModelIndex()); @@ -201,7 +205,7 @@ Persons::Persons(QObject *parent): }, [](Persons* o, option id, int first, int last) { if (id.some) { - int row = persons_row(o->d, id.value); + int row = persons_row(o->m_d, id.value); o->beginInsertRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginInsertRows(QModelIndex(), first, last); @@ -212,7 +216,7 @@ Persons::Persons(QObject *parent): }, [](Persons* o, option id, int first, int last) { if (id.some) { - int row = persons_row(o->d, id.value); + int row = persons_row(o->m_d, id.value); o->beginRemoveRows(o->createIndex(row, 0, id.value), first, last); } else { o->beginRemoveRows(QModelIndex(), first, last); @@ -221,13 +225,15 @@ Persons::Persons(QObject *parent): [](Persons* o) { o->endRemoveRows(); } - )) { +)), + m_ownsPrivate(true) { connect(this, &Persons::newDataReady, this, [this](const QModelIndex& i) { fetchMore(i); }, Qt::QueuedConnection); } - Persons::~Persons() { - persons_free(d); + if (m_ownsPrivate) { + persons_free(m_d); + } } diff --git a/tests/test_tree_rust.h b/tests/test_tree_rust.h index 8bbc391..1beeb5a 100644 --- a/tests/test_tree_rust.h +++ b/tests/test_tree_rust.h @@ -11,7 +11,9 @@ class Persons : public QAbstractItemModel public: class Private; private: - Private * const d; + Private * m_d; + bool m_ownsPrivate; + explicit Persons(bool owned, QObject *parent); public: explicit Persons(QObject *parent = nullptr); ~Persons(); @@ -32,6 +34,5 @@ signals: // new data is ready to be made available to the model with fetchMore() void newDataReady(const QModelIndex &parent) const; signals: -private: }; #endif // TEST_TREE_RUST_H