Skip to content

Implement QAnyStringView #995

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

Merged
merged 1 commit into from
Oct 4, 2024
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Support for further types: `QLine`, `QLineF`, `QImage`, `QPainter`, `QFont`, `QPen`, `QPolygon`, `QPolygonF`, `QRegion`
- Support for further types: `QLine`, `QLineF`, `QImage`, `QPainter`, `QFont`, `QPen`, `QPolygon`, `QPolygonF`, `QRegion`, `QAnyStringView`
- `internal_pointer_mut()` function on `QModelIndex`
- `c_void` in CXX-Qt-lib for easy access to `void *`
- `CxxQtThread` is now marked as `Sync` so that it can be used by reference
Expand Down
1 change: 1 addition & 0 deletions crates/cxx-qt-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ serde = { version = "1", features=["derive"], optional = true }

[build-dependencies]
cxx-qt-build.workspace = true
qt-build-utils.workspace = true

[features]
full_qt = ["qt_gui", "qt_qml", "qt_quickcontrols"]
Expand Down
11 changes: 11 additions & 0 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ fn write_headers() {
}

fn main() {
let qtbuild = qt_build_utils::QtBuild::new(vec!["Core".to_owned()])
.expect("Could not find Qt installation");

write_headers();

let emscripten_targeted = match std::env::var("CARGO_CFG_TARGET_OS") {
Expand Down Expand Up @@ -201,6 +204,10 @@ fn main() {
"core/qvector/qvector_u64",
];

if qtbuild.version().major > 5 {
rust_bridges.extend(["core/qanystringview"]);
}

if qt_gui_enabled() {
rust_bridges.extend([
"core/qlist/qlist_qcolor",
Expand Down Expand Up @@ -269,6 +276,10 @@ fn main() {
"core/qvector/qvector",
];

if qtbuild.version().major > 5 {
cpp_files.extend(["core/qanystringview"]);
}

if qt_gui_enabled() {
cpp_files.extend([
"gui/qcolor",
Expand Down
39 changes: 39 additions & 0 deletions crates/cxx-qt-lib/include/core/qanystringview.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// clang-format off
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Joshua Goins <joshua.goins@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtCore/QAnyStringView>
#include <QtCore/QByteArray>
#include <QtCore/QString>

#include "rust/cxx.h"

// Define namespace otherwise we hit a GCC bug
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
namespace rust {

template<>
struct IsRelocatable<QAnyStringView> : ::std::true_type
{};

} // namespace rust

namespace rust {
namespace cxxqtlib1 {

QAnyStringView
qanystringviewInitFromRustString(::rust::Str string);
QAnyStringView
qanystringviewInitFromQString(const QString& string);
::rust::String
qanystringviewToRustString(const QAnyStringView& string);

::rust::isize
qanystringviewLen(const QAnyStringView& string);

}
}
5 changes: 5 additions & 0 deletions crates/cxx-qt-lib/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ pub use qsizef::QSizeF;
mod qstring;
pub use qstring::QString;

#[cfg(cxxqt_qt_version_major = "6")]
mod qanystringview;
#[cfg(cxxqt_qt_version_major = "6")]
pub use qanystringview::QAnyStringView;

mod qstringlist;
pub use qstringlist::QStringList;

Expand Down
48 changes: 48 additions & 0 deletions crates/cxx-qt-lib/src/core/qanystringview.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// clang-format off
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Joshua Goins <joshua.goins@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#include "cxx-qt-lib/qanystringview.h"

#include <cxx-qt-lib/assertion_utils.h>

// QAnyStringView has two members.
// A union of (void*, char*, char_16*) and a size_t.
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/text/qanystringview.h
assert_alignment_and_size(QAnyStringView, {
::std::size_t a0;
void* a1;
});

static_assert(::std::is_trivially_copy_assignable<QAnyStringView>::value);
static_assert(::std::is_trivially_copy_constructible<QAnyStringView>::value);

static_assert(::std::is_trivially_destructible<QAnyStringView>::value);

static_assert(QTypeInfo<QAnyStringView>::isRelocatable);

namespace rust {
namespace cxxqtlib1 {

QAnyStringView
qanystringviewInitFromRustString(::rust::Str string)
{
return QAnyStringView(string.data(), string.size());
}

QAnyStringView
qanystringviewInitFromQString(const QString& string)
{
return QAnyStringView(string);
}

::rust::isize
qanystringviewLen(const QAnyStringView& string)
{
return static_cast<::rust::isize>(string.size());
}

}
}
118 changes: 118 additions & 0 deletions crates/cxx-qt-lib/src/core/qanystringview.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Joshua Goins <josh@redstrate.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::QString;
use core::ffi::c_void;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use cxx::{type_id, ExternType};

#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("cxx-qt-lib/qanystringview.h");
type QAnyStringView<'a> = super::QAnyStringView<'a>;

include!("cxx-qt-lib/qstring.h");
type QString = crate::QString;

/// Returns true if the string has no characters; otherwise returns false.
#[rust_name = "is_empty"]
fn isEmpty(self: &QAnyStringView) -> bool;

/// Returns true if this string is null; otherwise returns false.
#[rust_name = "is_null"]
fn isNull(self: &QAnyStringView) -> bool;
}

#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
include!("cxx-qt-lib/common.h");

#[doc(hidden)]
#[rust_name = "QAnyStringView_init_default"]
fn construct() -> QAnyStringView<'static>;
#[doc(hidden)]
#[rust_name = "QAnyStringView_init_from_rust_string"]
fn qanystringviewInitFromRustString<'a>(string: &str) -> QAnyStringView<'a>;
#[doc(hidden)]
#[rust_name = "QAnyStringView_init_from_qstring"]
fn qanystringviewInitFromQString<'a>(string: &QString) -> QAnyStringView<'a>;
#[doc(hidden)]
#[rust_name = "QAnyStringView_init_from_QAnyStringView"]
fn construct<'a>(string: &QAnyStringView) -> QAnyStringView<'a>;

#[doc(hidden)]
#[rust_name = "QAnyStringView_eq"]
fn operatorEq(a: &QAnyStringView, b: &QAnyStringView) -> bool;

#[doc(hidden)]
#[rust_name = "QAnyStringView_len"]
fn qanystringviewLen(string: &QAnyStringView) -> isize;
}
}

/// The QAnyStringView class provides a unified view of a Latin-1, UTF-8, or UTF-16 string.
#[repr(C)]
pub struct QAnyStringView<'a> {
/// QAnyStringView has two members, a pointer and a size_t
_space: MaybeUninit<[usize; 1]>,
_space2: MaybeUninit<[c_void; 1]>,

/// Needed to keep the lifetime in check
_phantom: PhantomData<&'a usize>,
}

impl<'a> Clone for QAnyStringView<'a> {
/// Constructs a copy of other.
///
/// This operation takes constant time, because QAnyStringView is a view-only string.
fn clone(&self) -> QAnyStringView<'a> {
ffi::QAnyStringView_init_from_QAnyStringView(self)
}
}

impl Default for QAnyStringView<'_> {
/// Constructs a null string. Null strings are also empty.
fn default() -> Self {
ffi::QAnyStringView_init_default()
}
}

impl PartialEq for QAnyStringView<'_> {
fn eq(&self, other: &Self) -> bool {
ffi::QAnyStringView_eq(self, other)
}
}

impl Eq for QAnyStringView<'_> {}

impl<'a> From<&'a str> for QAnyStringView<'a> {
/// Constructs a QAnyStringView from a Rust string
fn from(str: &str) -> Self {
ffi::QAnyStringView_init_from_rust_string(str)
}
}

impl From<&QString> for QAnyStringView<'_> {
/// Constructs a QAnyStringView from a QString
fn from(string: &QString) -> Self {
ffi::QAnyStringView_init_from_qstring(string)
}
}

impl QAnyStringView<'_> {
/// Returns the number of characters in this string.
pub fn len(&self) -> isize {
ffi::QAnyStringView_len(self)
}
}

// Safety:
//
// Static checks on the C++ side to ensure the size is the same.
unsafe impl ExternType for QAnyStringView<'_> {
type Id = type_id!("QAnyStringView");
type Kind = cxx::kind::Trivial;
}
4 changes: 4 additions & 0 deletions tests/qt_types_standalone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ add_executable(${APP_NAME}
cpp/qvector3d.h
cpp/qvector4d.h
)
if(NOT USE_QT5)
target_sources(${APP_NAME} PRIVATE
cpp/qanystringview.h)
endif()
target_include_directories(${APP_NAME} PRIVATE cpp)

target_link_libraries(${APP_NAME} PRIVATE
Expand Down
7 changes: 7 additions & 0 deletions tests/qt_types_standalone/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include <QtCore/QScopedPointer>
#include <QtTest/QTest>

#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
#include "qanystringview.h"
#endif

#include "qbytearray.h"
#include "qcolor.h"
#include "qcoreapplication.h"
Expand Down Expand Up @@ -59,6 +63,9 @@ main(int argc, char* argv[])
}
};

#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
runTest(QScopedPointer<QObject>(new QAnyStringViewTest));
#endif
runTest(QScopedPointer<QObject>(new QByteArrayTest));
runTest(QScopedPointer<QObject>(new QColorTest));
runTest(QScopedPointer<QObject>(new QCoreApplicationTest));
Expand Down
38 changes: 38 additions & 0 deletions tests/qt_types_standalone/cpp/qanystringview.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// clang-format off
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Joshua Goins <joshua.goins@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtCore/QAnyStringView>
#include <QtTest/QTest>

#include "qt_types_standalone/src/qanystringview.cxx.h"

class QAnyStringViewTest : public QObject
{
Q_OBJECT

private Q_SLOTS:
void construct()
{
const auto s = construct_qanystringview("String constructed by Rust");
QCOMPARE(s, QByteArrayLiteral("String constructed by Rust"));
}

void construct_qstring()
{
const auto s = construct_qanystringview_qstring(
QStringLiteral("String constructed by Rust"));
QCOMPARE(s, QByteArrayLiteral("String constructed by Rust"));
}

void clone()
{
const auto l = QAnyStringView("Test");
const auto c = clone_qanystringview(l);
QCOMPARE(c, l);
}
};
1 change: 1 addition & 0 deletions tests/qt_types_standalone/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ cxx-qt-lib = { workspace = true, features = ["full"] }

[build-dependencies]
cxx-qt-build.workspace = true
qt-build-utils.workspace = true
14 changes: 11 additions & 3 deletions tests/qt_types_standalone/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
use cxx_qt_build::CxxQtBuilder;

fn main() {
CxxQtBuilder::new()
let qtbuild = qt_build_utils::QtBuild::new(vec!["Core".to_owned()])
.expect("Could not find Qt installation");

let mut builder = CxxQtBuilder::new()
.file("src/qbytearray.rs")
.file("src/qcolor.rs")
.file("src/qcoreapplication.rs")
Expand Down Expand Up @@ -45,6 +48,11 @@ fn main() {
.file("src/qvector.rs")
.file("src/qvector2d.rs")
.file("src/qvector3d.rs")
.file("src/qvector4d.rs")
.build();
.file("src/qvector4d.rs");

if qtbuild.version().major > 5 {
builder = builder.file("src/qanystringview.rs");
}

builder.build();
}
3 changes: 3 additions & 0 deletions tests/qt_types_standalone/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cfg(cxxqt_qt_version_major = "6")]
mod qanystringview;

mod qbytearray;
mod qcolor;
mod qcoreapplication;
Expand Down
Loading
Loading