Skip to content

Commit

Permalink
cxx-qt-lib: add support for QModelIndex
Browse files Browse the repository at this point in the history
Related to KDAB#291
  • Loading branch information
ahayzen-kdab committed Dec 15, 2022
1 parent 79190d2 commit 9faecdd
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 36 deletions.
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
39 changes: 39 additions & 0 deletions tests/qt_types_standalone/cpp/qmodelindex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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()
}

0 comments on commit 9faecdd

Please sign in to comment.