From dcf08c65f72d0302769ec7c3953653f0fb48368d Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Thu, 15 Dec 2022 16:35:39 +0000 Subject: [PATCH] cxx-qt-lib: add support for QModelIndex Related to #291 --- CHANGELOG.md | 1 + .../cxx-qt-lib-headers/include/qmodelindex.h | 9 +++ crates/cxx-qt-lib-headers/src/lib.rs | 3 +- crates/cxx-qt-lib/build.rs | 2 + crates/cxx-qt-lib/src/types/mod.rs | 3 + crates/cxx-qt-lib/src/types/qmodelindex.cpp | 20 ++++++ crates/cxx-qt-lib/src/types/qmodelindex.rs | 66 +++++++++++++++++++ .../qml_features/cpp/qabstractlistmodelcxx.h | 13 ---- .../rust/src/custom_base_class.rs | 24 +------ tests/qt_types_standalone/CMakeLists.txt | 1 + tests/qt_types_standalone/cpp/main.cpp | 2 + tests/qt_types_standalone/cpp/qmodelindex.h | 39 +++++++++++ tests/qt_types_standalone/rust/build.rs | 1 + tests/qt_types_standalone/rust/src/lib.rs | 1 + .../rust/src/qmodelindex.rs | 32 +++++++++ 15 files changed, 181 insertions(+), 36 deletions(-) create mode 100644 crates/cxx-qt-lib-headers/include/qmodelindex.h create mode 100644 crates/cxx-qt-lib/src/types/qmodelindex.cpp create mode 100644 crates/cxx-qt-lib/src/types/qmodelindex.rs create mode 100644 tests/qt_types_standalone/cpp/qmodelindex.h create mode 100644 tests/qt_types_standalone/rust/src/qmodelindex.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 6198515c0..995903858 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Multiple QObjects can be defined in one bridge - Support for container types: `QSet`, `QHash` +- Support for futher types: `QModelIndex` ### Fixed diff --git a/crates/cxx-qt-lib-headers/include/qmodelindex.h b/crates/cxx-qt-lib-headers/include/qmodelindex.h new file mode 100644 index 000000000..6b3cf1f2d --- /dev/null +++ b/crates/cxx-qt-lib-headers/include/qmodelindex.h @@ -0,0 +1,9 @@ +// clang-format off +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#pragma once + +#include diff --git a/crates/cxx-qt-lib-headers/src/lib.rs b/crates/cxx-qt-lib-headers/src/lib.rs index 76237b3a1..e53c43f0d 100644 --- a/crates/cxx-qt-lib-headers/src/lib.rs +++ b/crates/cxx-qt-lib-headers/src/lib.rs @@ -10,7 +10,7 @@ use std::{fs::File, io::Write, path::Path}; -static HEADERS: [(&str, &str); 18] = [ +static HEADERS: [(&str, &str); 19] = [ (include_str!("../include/common.h"), "common.h"), (include_str!("../include/convert.h"), "convert.h"), (include_str!("../include/cxxqt_thread.h"), "cxxqt_thread.h"), @@ -18,6 +18,7 @@ static HEADERS: [(&str, &str); 18] = [ (include_str!("../include/qdate.h"), "qdate.h"), (include_str!("../include/qdatetime.h"), "qdatetime.h"), (include_str!("../include/qhash.h"), "qhash.h"), + (include_str!("../include/qmodelindex.h"), "qmodelindex.h"), (include_str!("../include/qpoint.h"), "qpoint.h"), (include_str!("../include/qpointf.h"), "qpointf.h"), (include_str!("../include/qrect.h"), "qrect.h"), diff --git a/crates/cxx-qt-lib/build.rs b/crates/cxx-qt-lib/build.rs index de3a89cf0..e88451a41 100644 --- a/crates/cxx-qt-lib/build.rs +++ b/crates/cxx-qt-lib/build.rs @@ -23,6 +23,7 @@ fn main() { "qdate", "qdatetime", "qhash/qhash_qstring_qvariant", + "qmodelindex", "qpoint", "qpointf", "qrect", @@ -69,6 +70,7 @@ fn main() { "qdate", "qdatetime", "qhash/qhash", + "qmodelindex", "qpoint", "qpointf", "qrect", diff --git a/crates/cxx-qt-lib/src/types/mod.rs b/crates/cxx-qt-lib/src/types/mod.rs index 2884ece42..c1a9207df 100644 --- a/crates/cxx-qt-lib/src/types/mod.rs +++ b/crates/cxx-qt-lib/src/types/mod.rs @@ -15,6 +15,9 @@ pub use qdatetime::QDateTime; mod qhash; pub use qhash::{QHash, QHashPair, QHashPair_QString_QVariant}; +mod qmodelindex; +pub use qmodelindex::QModelIndex; + mod qrect; pub use qrect::QRect; diff --git a/crates/cxx-qt-lib/src/types/qmodelindex.cpp b/crates/cxx-qt-lib/src/types/qmodelindex.cpp new file mode 100644 index 000000000..3624868da --- /dev/null +++ b/crates/cxx-qt-lib/src/types/qmodelindex.cpp @@ -0,0 +1,20 @@ +// clang-format off +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#include "cxx-qt-lib/qmodelindex.h" + +#include "assertion_utils.h" + +// QModelIndex has two ints, a uint pointer, and a pointer. +// This results in 4 + 4 + 4 + 8 = 20, then due to compiler padding this results in +// size of 24 or three pointers. +// https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/itemmodels/qabstractitemmodel.h?h=v5.15.6-lts-lgpl#n93 +// https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/itemmodels/qabstractitemmodel.h?h=v6.2.4#n195 +assert_alignment_and_size(QModelIndex, + alignof(std::size_t), + sizeof(std::size_t[3])); + +static_assert(std::is_trivially_copyable::value); diff --git a/crates/cxx-qt-lib/src/types/qmodelindex.rs b/crates/cxx-qt-lib/src/types/qmodelindex.rs new file mode 100644 index 000000000..1da96a000 --- /dev/null +++ b/crates/cxx-qt-lib/src/types/qmodelindex.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +use cxx::{type_id, ExternType}; +use std::mem::MaybeUninit; + +#[cxx::bridge] +mod ffi { + unsafe extern "C++" { + include!("cxx-qt-lib/qmodelindex.h"); + + type QModelIndex = super::QModelIndex; + + /// Returns the column this model index refers to. + fn column(self: &QModelIndex) -> i32; + /// Returns true if this model index is valid; otherwise returns false. + /// + /// A valid index belongs to a model, and has non-negative row and column numbers. + #[rust_name = "is_valid"] + fn isValid(self: &QModelIndex) -> bool; + /// Returns the parent of the model index, or QModelIndex() if it has no parent. + fn parent(self: &QModelIndex) -> QModelIndex; + /// Returns the row this model index refers to. + fn row(self: &QModelIndex) -> i32; + /// Returns the sibling at row and column. If there is no sibling at this position, an invalid QModelIndex is returned. + fn sibling(self: &QModelIndex, row: i32, column: i32) -> QModelIndex; + /// Returns the sibling at column for the current row. If there is no sibling at this position, an invalid QModelIndex is returned. + #[rust_name = "sibling_at_column"] + fn siblingAtColumn(self: &QModelIndex, column: i32) -> QModelIndex; + /// Returns the sibling at row for the current column. If there is no sibling at this position, an invalid QModelIndex is returned. + #[rust_name = "sibling_at_row"] + fn siblingAtRow(self: &QModelIndex, row: i32) -> QModelIndex; + } + + #[namespace = "rust::cxxqtlib1"] + unsafe extern "C++" { + include!("cxx-qt-lib/common.h"); + + #[doc(hidden)] + #[rust_name = "qmodelindex_init_default"] + fn construct() -> QModelIndex; + } +} + +/// The QModelIndex class is used to locate data in a data model. +#[derive(Clone)] +#[repr(C)] +pub struct QModelIndex { + _space: MaybeUninit<[usize; 3]>, +} + +impl Default for QModelIndex { + /// Creates a new empty model index. This type of model index is used to indicate that the position in the model is invalid. + fn default() -> Self { + ffi::qmodelindex_init_default() + } +} + +// Safety: +// +// Static checks on the C++ side to ensure the size is the same. +unsafe impl ExternType for QModelIndex { + type Id = type_id!("QModelIndex"); + type Kind = cxx::kind::Trivial; +} diff --git a/examples/qml_features/cpp/qabstractlistmodelcxx.h b/examples/qml_features/cpp/qabstractlistmodelcxx.h index 475415bc8..e71d8d1ee 100644 --- a/examples/qml_features/cpp/qabstractlistmodelcxx.h +++ b/examples/qml_features/cpp/qabstractlistmodelcxx.h @@ -52,16 +52,3 @@ class QAbstractListModelCXX : public QAbstractListModel void endResetModel() { QAbstractItemModel::endResetModel(); } }; - -// Define that a QModelIndex is relocatable and check the size -// -// TODO: later this will likely be in cxx-qt-lib -template<> -struct rust::IsRelocatable : std::true_type -{ -}; -static_assert(QTypeInfo::isRelocatable); -static_assert(alignof(QModelIndex) <= alignof(std::size_t[3]), - "unexpectedly large QModelIndex alignment"); -static_assert(sizeof(QModelIndex) == sizeof(std::size_t[3]), - "unexpected QModelIndex size"); diff --git a/examples/qml_features/rust/src/custom_base_class.rs b/examples/qml_features/rust/src/custom_base_class.rs index 270626e8b..bc81bce87 100644 --- a/examples/qml_features/rust/src/custom_base_class.rs +++ b/examples/qml_features/rust/src/custom_base_class.rs @@ -2,25 +2,6 @@ // SPDX-FileContributor: Andrew Hayzen // // SPDX-License-Identifier: MIT OR Apache-2.0 -use cxx::{type_id, ExternType}; -use std::mem::MaybeUninit; - -/// Define a QModelIndex that is trivial for CXX -/// -/// TODO: later this will likely be in cxx-qt-lib -#[repr(C)] -pub struct QModelIndex { - _space: MaybeUninit<[usize; 3]>, -} - -// Safety: -// -// Static checks on the C++ side to ensure the size is the same. -// TODO: later this will likely be in cxx-qt-lib -unsafe impl ExternType for QModelIndex { - type Id = type_id!("QModelIndex"); - type Kind = cxx::kind::Trivial; -} // ANCHOR: book_macro_code #[cxx_qt::bridge(cxx_file_stem = "custom_base_class")] @@ -33,9 +14,8 @@ mod ffi { include!("cxx-qt-lib/qvariant.h"); type QVariant = cxx_qt_lib::QVariant; - // Define the interface of the QModelIndex - type QModelIndex = super::QModelIndex; - fn row(self: &QModelIndex) -> i32; + include!("cxx-qt-lib/qmodelindex.h"); + type QModelIndex = cxx_qt_lib::QModelIndex; #[cxx_name = "beginInsertRows"] fn begin_insert_rows(self: Pin<&mut CustomBaseClassQt>, first: i32, last: i32); diff --git a/tests/qt_types_standalone/CMakeLists.txt b/tests/qt_types_standalone/CMakeLists.txt index 5451d0b23..8fb65b1ba 100644 --- a/tests/qt_types_standalone/CMakeLists.txt +++ b/tests/qt_types_standalone/CMakeLists.txt @@ -45,6 +45,7 @@ add_executable(${APP_NAME} cpp/qdate.h cpp/qdatetime.h cpp/qhash.h + cpp/qmodelindex.h cpp/qpoint.h cpp/qpointf.h cpp/qrect.h diff --git a/tests/qt_types_standalone/cpp/main.cpp b/tests/qt_types_standalone/cpp/main.cpp index 0618202b2..55570a178 100644 --- a/tests/qt_types_standalone/cpp/main.cpp +++ b/tests/qt_types_standalone/cpp/main.cpp @@ -12,6 +12,7 @@ #include "qdate.h" #include "qdatetime.h" #include "qhash.h" +#include "qmodelindex.h" #include "qpoint.h" #include "qpointf.h" #include "qrect.h" @@ -41,6 +42,7 @@ main(int argc, char* argv[]) runTest(QScopedPointer(new QDateTest)); runTest(QScopedPointer(new QDateTimeTest)); runTest(QScopedPointer(new QHashTest)); + runTest(QScopedPointer(new QModelIndexTest)); runTest(QScopedPointer(new QPointTest)); runTest(QScopedPointer(new QPointFTest)); runTest(QScopedPointer(new QRectTest)); diff --git a/tests/qt_types_standalone/cpp/qmodelindex.h b/tests/qt_types_standalone/cpp/qmodelindex.h new file mode 100644 index 000000000..19f1a31ec --- /dev/null +++ b/tests/qt_types_standalone/cpp/qmodelindex.h @@ -0,0 +1,39 @@ +// clang-format off +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#pragma once + +#include +#include +#include + +#include "cxx-qt-gen/qmodelindex_cxx.cxx.h" + +class QModelIndexTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void construct() + { + const auto i = construct_qmodelindex(); + QCOMPARE(i.isValid(), false); + } + + void read() + { + const auto model = QStringListModel(QStringList() << QStringLiteral("kdab")); + QVERIFY(read_qmodelindex(model.index(0))); + } + + void clone() + { + const auto model = QStringListModel(QStringList() << QStringLiteral("kdab")); + const auto c = clone_qmodelindex(model.index(0)); + QCOMPARE(c.isValid(), true); + QCOMPARE(c.row(), 0); + } +}; diff --git a/tests/qt_types_standalone/rust/build.rs b/tests/qt_types_standalone/rust/build.rs index 78d3d1f8a..79f019cf0 100644 --- a/tests/qt_types_standalone/rust/build.rs +++ b/tests/qt_types_standalone/rust/build.rs @@ -11,6 +11,7 @@ fn main() { .file("src/qdate.rs") .file("src/qdatetime.rs") .file("src/qhash.rs") + .file("src/qmodelindex.rs") .file("src/qpoint.rs") .file("src/qpointf.rs") .file("src/qrect.rs") diff --git a/tests/qt_types_standalone/rust/src/lib.rs b/tests/qt_types_standalone/rust/src/lib.rs index a91d0854f..67b24f1c7 100644 --- a/tests/qt_types_standalone/rust/src/lib.rs +++ b/tests/qt_types_standalone/rust/src/lib.rs @@ -8,6 +8,7 @@ mod qcolor; mod qdate; mod qdatetime; mod qhash; +mod qmodelindex; mod qpoint; mod qpointf; mod qrect; diff --git a/tests/qt_types_standalone/rust/src/qmodelindex.rs b/tests/qt_types_standalone/rust/src/qmodelindex.rs new file mode 100644 index 000000000..146ccf5da --- /dev/null +++ b/tests/qt_types_standalone/rust/src/qmodelindex.rs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use cxx_qt_lib::QModelIndex; + +#[cxx::bridge] +mod qmodelindex_cxx { + unsafe extern "C++" { + include!("cxx-qt-lib/qmodelindex.h"); + type QModelIndex = cxx_qt_lib::QModelIndex; + } + + extern "Rust" { + fn construct_qmodelindex() -> QModelIndex; + fn read_qmodelindex(i: &QModelIndex) -> bool; + fn clone_qmodelindex(i: &QModelIndex) -> QModelIndex; + } +} + +fn construct_qmodelindex() -> QModelIndex { + QModelIndex::default() +} + +fn read_qmodelindex(i: &QModelIndex) -> bool { + i.is_valid() && i.row() == 0 +} + +fn clone_qmodelindex(i: &QModelIndex) -> QModelIndex { + i.clone() +}