forked from KDAB/cxx-qt
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cxx-qt-lib: add support for QByteArray
Related to KDAB#291
- Loading branch information
1 parent
79190d2
commit 7ec4540
Showing
13 changed files
with
322 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// 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 <QByteArray> | ||
|
||
#include "rust/cxx.h" | ||
|
||
template<> | ||
struct rust::IsRelocatable<QByteArray> : std::true_type | ||
{ | ||
}; | ||
|
||
namespace rust { | ||
namespace cxxqtlib1 { | ||
|
||
QByteArray | ||
qbytearrayFromRustString(rust::Str string); | ||
rust::String | ||
qbytearrayToRustString(const QByteArray& string); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// 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/qbytearray.h" | ||
|
||
#include "assertion_utils.h" | ||
|
||
// The layout has changed between Qt 5 and Qt 6 | ||
// | ||
// Qt5 QByteArray has one pointer as a member | ||
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/text/qbytearray.h?h=v5.15.6-lts-lgpl#n470 | ||
// | ||
// Qt6 QByteArray has one member, which contains two pointers and a size_t | ||
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/text/qbytearray.h?h=v6.2.4#n91 | ||
// DataPointer is then a QByteArrayData, which is a QArrayDataPointer<char> | ||
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qarraydatapointer.h?h=v6.2.4#n390 | ||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) | ||
assert_alignment_and_size(QByteArray, | ||
alignof(std::size_t), | ||
sizeof(std::size_t[3])); | ||
#else | ||
assert_alignment_and_size(QByteArray, | ||
alignof(std::size_t), | ||
sizeof(std::size_t)); | ||
#endif | ||
|
||
static_assert(!std::is_trivially_copy_assignable<QByteArray>::value); | ||
static_assert(!std::is_trivially_copy_constructible<QByteArray>::value); | ||
|
||
static_assert(!std::is_trivially_destructible<QByteArray>::value); | ||
|
||
static_assert(QTypeInfo<QByteArray>::isRelocatable); | ||
|
||
namespace rust { | ||
namespace cxxqtlib1 { | ||
|
||
QByteArray | ||
qbytearrayFromRustString(rust::Str string) | ||
{ | ||
// Note that rust::Str here is borrowed | ||
return QByteArray(string.data(), string.size()); | ||
} | ||
|
||
rust::String | ||
qbytearrayToRustString(const QByteArray& byteArray) | ||
{ | ||
return rust::String(byteArray.constData(), byteArray.size()); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// 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/qbytearray.h"); | ||
|
||
type QByteArray = super::QByteArray; | ||
} | ||
|
||
#[namespace = "rust::cxxqtlib1"] | ||
unsafe extern "C++" { | ||
include!("cxx-qt-lib/common.h"); | ||
|
||
#[doc(hidden)] | ||
#[rust_name = "qbytearray_drop"] | ||
fn drop(string: &mut QByteArray); | ||
|
||
#[doc(hidden)] | ||
#[rust_name = "qbytearray_default"] | ||
fn construct() -> QByteArray; | ||
#[doc(hidden)] | ||
#[rust_name = "qbytearray_from_rust_string"] | ||
fn qbytearrayFromRustString(string: &str) -> QByteArray; | ||
#[doc(hidden)] | ||
#[rust_name = "qbytearray_clone"] | ||
fn construct(string: &QByteArray) -> QByteArray; | ||
|
||
#[doc(hidden)] | ||
#[rust_name = "qbytearray_to_rust_string"] | ||
fn qbytearrayToRustString(string: &QByteArray) -> String; | ||
} | ||
} | ||
|
||
/// The QByteArray class provides an array of bytes. | ||
pub struct QByteArray { | ||
/// The layout has changed between Qt 5 and Qt 6 | ||
/// | ||
/// Qt5 QByteArray has one pointer as a member | ||
/// Qt6 QByteArray has one member, which contains two pointers and a size_t | ||
#[cfg(qt_version_major = "5")] | ||
_space: MaybeUninit<usize>, | ||
#[cfg(qt_version_major = "6")] | ||
_space: MaybeUninit<[usize; 3]>, | ||
} | ||
|
||
impl Clone for QByteArray { | ||
/// Constructs a copy of other. | ||
/// | ||
/// This operation takes constant time, because QByteArray is implicitly shared. | ||
/// This makes returning a QByteArray from a function very fast. | ||
/// If a shared instance is modified, it will be copied (copy-on-write), and that takes linear time. | ||
fn clone(&self) -> Self { | ||
ffi::qbytearray_clone(self) | ||
} | ||
} | ||
|
||
impl Default for QByteArray { | ||
/// Constructs an empty byte array. | ||
fn default() -> Self { | ||
ffi::qbytearray_default() | ||
} | ||
} | ||
|
||
impl std::fmt::Display for QByteArray { | ||
/// Convert the QByteArray to a Rust string | ||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
write!(f, "{}", <&QByteArray as Into<String>>::into(self)) | ||
} | ||
} | ||
|
||
impl Drop for QByteArray { | ||
/// Destroys the byte array. | ||
fn drop(&mut self) { | ||
ffi::qbytearray_drop(self) | ||
} | ||
} | ||
|
||
impl From<&str> for QByteArray { | ||
/// Constructs a QByteArray from a Rust string | ||
fn from(str: &str) -> Self { | ||
ffi::qbytearray_from_rust_string(str) | ||
} | ||
} | ||
|
||
impl From<&String> for QByteArray { | ||
/// Constructs a QByteArray from a Rust string | ||
fn from(str: &String) -> Self { | ||
ffi::qbytearray_from_rust_string(str) | ||
} | ||
} | ||
|
||
impl From<&QByteArray> for String { | ||
/// Convert the QByteArray to a Rust string | ||
fn from(qbytearray: &QByteArray) -> Self { | ||
ffi::qbytearray_to_rust_string(qbytearray) | ||
} | ||
} | ||
|
||
// Safety: | ||
// | ||
// Static checks on the C++ side to ensure the size is the same. | ||
unsafe impl ExternType for QByteArray { | ||
type Id = type_id!("QByteArray"); | ||
type Kind = cxx::kind::Trivial; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// 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/QByteArray> | ||
#include <QtTest/QTest> | ||
|
||
#include "cxx-qt-gen/qbytearray_cxx.cxx.h" | ||
|
||
class QByteArrayTest : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
private Q_SLOTS: | ||
void construct() | ||
{ | ||
QFETCH(bool, slice); | ||
const auto s = construct_qbytearray(slice); | ||
QCOMPARE(s, QByteArrayLiteral("String constructed by Rust")); | ||
} | ||
|
||
void construct_data() | ||
{ | ||
QTest::addColumn<bool>("slice"); | ||
|
||
QTest::newRow("From &str") << true; | ||
QTest::newRow("From String") << false; | ||
} | ||
|
||
void read() | ||
{ | ||
const auto s = QByteArrayLiteral("String constructed by C++"); | ||
QVERIFY(read_qbytearray(s)); | ||
} | ||
|
||
void clone() | ||
{ | ||
auto s = QByteArrayLiteral("String constructed by C++"); | ||
const auto c = clone_qbytearray(s); | ||
QCOMPARE(c, QByteArrayLiteral("String constructed by C++")); | ||
} | ||
|
||
void modify_rust() { QVERIFY(can_handle_qbytearray_change()); } | ||
|
||
void modify_updates_cpp() | ||
{ | ||
auto s = QByteArrayLiteral("String constructed by C++"); | ||
modify_qbytearray(s); | ||
QCOMPARE(s, QByteArrayLiteral("Updated string value")); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]> | ||
// SPDX-FileContributor: Andrew Hayzen <[email protected]> | ||
// SPDX-FileContributor: Gerhard de Clercq <[email protected]> | ||
// | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
|
||
use cxx_qt_lib::QByteArray; | ||
|
||
#[cxx::bridge] | ||
mod qbytearray_cxx { | ||
unsafe extern "C++" { | ||
include!("cxx-qt-lib/qbytearray.h"); | ||
|
||
type QByteArray = cxx_qt_lib::QByteArray; | ||
} | ||
|
||
extern "Rust" { | ||
fn construct_qbytearray(slice: bool) -> QByteArray; | ||
fn read_qbytearray(s: &QByteArray) -> bool; | ||
fn modify_qbytearray(s: Pin<&mut QByteArray>); | ||
fn can_handle_qbytearray_change() -> bool; | ||
fn clone_qbytearray(s: &QByteArray) -> QByteArray; | ||
} | ||
} | ||
|
||
fn construct_qbytearray(slice: bool) -> QByteArray { | ||
if slice { | ||
QByteArray::from("String constructed by Rust") | ||
} else { | ||
let rs_string = "String constructed by Rust".to_owned(); | ||
QByteArray::from(&rs_string) | ||
} | ||
} | ||
|
||
fn read_qbytearray(s: &cxx_qt_lib::QByteArray) -> bool { | ||
let rs = s.to_string(); | ||
rs == "String constructed by C++" | ||
} | ||
|
||
fn modify_qbytearray(mut s: std::pin::Pin<&mut cxx_qt_lib::QByteArray>) { | ||
*s = QByteArray::from("Updated string value"); | ||
} | ||
|
||
fn can_handle_qbytearray_change() -> bool { | ||
let long_s = "Very very long string that is hopefully long enough to allocate and get Valgrind's attention :)"; | ||
let long_s_ptr = QByteArray::from(long_s); | ||
|
||
let short_s = "Short string"; | ||
let mut short_s_ptr = QByteArray::from(short_s); | ||
assert!(short_s_ptr.to_string() == short_s); | ||
|
||
short_s_ptr = long_s_ptr; | ||
|
||
short_s_ptr.to_string() == long_s | ||
} | ||
|
||
fn clone_qbytearray(s: &QByteArray) -> QByteArray { | ||
s.clone() | ||
} |