Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cxx-qt-lib: add support for QModelIndex #391

Merged
merged 1 commit into from
Dec 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Added

- Support for container types: `QSet<T>`, `QHash<K, V>`
- Support for further types: `QModelIndex`

### Fixed

Expand Down
9 changes: 9 additions & 0 deletions crates/cxx-qt-lib-headers/include/qmodelindex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// clang-format off
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QModelIndex>
3 changes: 2 additions & 1 deletion crates/cxx-qt-lib-headers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@

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"),
(include_str!("../include/qcolor.h"), "qcolor.h"),
(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"),
Expand Down
2 changes: 2 additions & 0 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ fn main() {
"qdate",
"qdatetime",
"qhash/qhash_qstring_qvariant",
"qmodelindex",
"qpoint",
"qpointf",
"qrect",
Expand Down Expand Up @@ -69,6 +70,7 @@ fn main() {
"qdate",
"qdatetime",
"qhash/qhash",
"qmodelindex",
"qpoint",
"qpointf",
"qrect",
Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
20 changes: 20 additions & 0 deletions crates/cxx-qt-lib/src/types/qmodelindex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// clang-format off
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// 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<QModelIndex>::value);
66 changes: 66 additions & 0 deletions crates/cxx-qt-lib/src/types/qmodelindex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// 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;
}
13 changes: 0 additions & 13 deletions examples/qml_features/cpp/qabstractlistmodelcxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<QModelIndex> : std::true_type
{
};
static_assert(QTypeInfo<QModelIndex>::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");
24 changes: 2 additions & 22 deletions examples/qml_features/rust/src/custom_base_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,6 @@
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// 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")]
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions tests/qt_types_standalone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/qt_types_standalone/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -41,6 +42,7 @@ main(int argc, char* argv[])
runTest(QScopedPointer<QObject>(new QDateTest));
runTest(QScopedPointer<QObject>(new QDateTimeTest));
runTest(QScopedPointer<QObject>(new QHashTest));
runTest(QScopedPointer<QObject>(new QModelIndexTest));
runTest(QScopedPointer<QObject>(new QPointTest));
runTest(QScopedPointer<QObject>(new QPointFTest));
runTest(QScopedPointer<QObject>(new QRectTest));
Expand Down
41 changes: 41 additions & 0 deletions tests/qt_types_standalone/cpp/qmodelindex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// clang-format off
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtCore/QModelIndex>
#include <QtCore/QStringListModel>
#include <QtTest/QTest>

#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);
}
};
1 change: 1 addition & 0 deletions tests/qt_types_standalone/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
1 change: 1 addition & 0 deletions tests/qt_types_standalone/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod qcolor;
mod qdate;
mod qdatetime;
mod qhash;
mod qmodelindex;
mod qpoint;
mod qpointf;
mod qrect;
Expand Down
32 changes: 32 additions & 0 deletions tests/qt_types_standalone/rust/src/qmodelindex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// 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()
}