From d79dd4c39db6fbd5e29cd38caed095c2a7022f91 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Tue, 24 Dec 2024 17:31:13 -0800 Subject: [PATCH 01/18] cxx-qt-lib: add shared type for QUuid --- crates/cxx-qt-lib/Cargo.toml | 4 +- crates/cxx-qt-lib/build.rs | 6 + crates/cxx-qt-lib/include/core/qlist.h | 2 + crates/cxx-qt-lib/include/core/qset.h | 2 + crates/cxx-qt-lib/include/core/quuid.h | 40 ++ crates/cxx-qt-lib/include/core/qvariant.h | 2 + crates/cxx-qt-lib/include/core/qvector.h | 2 + crates/cxx-qt-lib/src/core/mod.rs | 3 + crates/cxx-qt-lib/src/core/qlist/generate.sh | 1 + crates/cxx-qt-lib/src/core/qlist/mod.rs | 3 +- crates/cxx-qt-lib/src/core/qlist/qlist.cpp | 1 + .../cxx-qt-lib/src/core/qlist/qlist_quuid.rs | 92 +++++ crates/cxx-qt-lib/src/core/qset/generate.sh | 1 + crates/cxx-qt-lib/src/core/qset/mod.rs | 3 +- crates/cxx-qt-lib/src/core/qset/qset.cpp | 1 + crates/cxx-qt-lib/src/core/qset/qset_quuid.rs | 70 ++++ crates/cxx-qt-lib/src/core/quuid.cpp | 71 ++++ crates/cxx-qt-lib/src/core/quuid.rs | 386 ++++++++++++++++++ .../cxx-qt-lib/src/core/qvariant/generate.sh | 1 + crates/cxx-qt-lib/src/core/qvariant/mod.rs | 1 + .../cxx-qt-lib/src/core/qvariant/qvariant.cpp | 1 + .../src/core/qvariant/qvariant_quuid.rs | 37 ++ .../cxx-qt-lib/src/core/qvector/generate.sh | 1 + crates/cxx-qt-lib/src/core/qvector/mod.rs | 3 +- .../cxx-qt-lib/src/core/qvector/qvector.cpp | 1 + .../src/core/qvector/qvector_quuid.rs | 92 +++++ 26 files changed, 823 insertions(+), 4 deletions(-) create mode 100644 crates/cxx-qt-lib/include/core/quuid.h create mode 100644 crates/cxx-qt-lib/src/core/qlist/qlist_quuid.rs create mode 100644 crates/cxx-qt-lib/src/core/qset/qset_quuid.rs create mode 100644 crates/cxx-qt-lib/src/core/quuid.cpp create mode 100644 crates/cxx-qt-lib/src/core/quuid.rs create mode 100644 crates/cxx-qt-lib/src/core/qvariant/qvariant_quuid.rs create mode 100644 crates/cxx-qt-lib/src/core/qvector/qvector_quuid.rs diff --git a/crates/cxx-qt-lib/Cargo.toml b/crates/cxx-qt-lib/Cargo.toml index e59bd23fb..d6b534b44 100644 --- a/crates/cxx-qt-lib/Cargo.toml +++ b/crates/cxx-qt-lib/Cargo.toml @@ -29,6 +29,7 @@ http = { version = "1.0", optional = true } rgb = { version = "0.8", optional = true } time = { version = "0.3.20", optional = true } url = { version = "2.3", optional = true } +uuid = { version = "1.1.0", optional = true } serde = { version = "1", features=["derive"], optional = true } [build-dependencies] @@ -36,7 +37,7 @@ cxx-qt-build.workspace = true qt-build-utils.workspace = true [features] -full = ["qt_full", "serde", "url", "time", "rgb", "http", "chrono", "bytes"] +full = ["qt_full", "serde", "url", "uuid", "time", "rgb", "http", "chrono", "bytes"] default = [] qt_full = ["qt_gui", "qt_qml", "qt_quickcontrols"] @@ -51,6 +52,7 @@ rgb = ["dep:rgb"] time = ["dep:time"] url = ["dep:url"] serde = ["dep:serde"] +uuid = ["dep:uuid"] link_qt_object_files = ["cxx-qt-build/link_qt_object_files"] [lints] diff --git a/crates/cxx-qt-lib/build.rs b/crates/cxx-qt-lib/build.rs index bf4132961..2970c8484 100644 --- a/crates/cxx-qt-lib/build.rs +++ b/crates/cxx-qt-lib/build.rs @@ -110,6 +110,7 @@ fn main() { "core/qlist/qlist_qstring", "core/qlist/qlist_qtime", "core/qlist/qlist_qurl", + "core/qlist/qlist_quuid", "core/qlist/qlist_qvariant", "core/qlist/qlist_u8", "core/qlist/qlist_u16", @@ -137,6 +138,7 @@ fn main() { "core/qset/qset_qstring", "core/qset/qset_qtime", "core/qset/qset_qurl", + "core/qset/qset_quuid", "core/qset/qset_u8", "core/qset/qset_u16", "core/qset/qset_u32", @@ -148,6 +150,7 @@ fn main() { "core/qt", "core/qtime", "core/qurl", + "core/quuid", "core/qvariant/mod", "core/qvariant/qvariant_bool", "core/qvariant/qvariant_f32", @@ -170,6 +173,7 @@ fn main() { "core/qvariant/qvariant_qstringlist", "core/qvariant/qvariant_qtime", "core/qvariant/qvariant_qurl", + "core/qvariant/qvariant_quuid", "core/qvariant/qvariant_u8", "core/qvariant/qvariant_u16", "core/qvariant/qvariant_u32", @@ -197,6 +201,7 @@ fn main() { "core/qvector/qvector_qstring", "core/qvector/qvector_qtime", "core/qvector/qvector_qurl", + "core/qvector/qvector_quuid", "core/qvector/qvector_qvariant", "core/qvector/qvector_u8", "core/qvector/qvector_u16", @@ -272,6 +277,7 @@ fn main() { "core/qstringlist", "core/qtime", "core/qurl", + "core/quuid", "core/qvariant/qvariant", "core/qvector/qvector", ]; diff --git a/crates/cxx-qt-lib/include/core/qlist.h b/crates/cxx-qt-lib/include/core/qlist.h index a7227f0c3..b0b86091c 100644 --- a/crates/cxx-qt-lib/include/core/qlist.h +++ b/crates/cxx-qt-lib/include/core/qlist.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef CXX_QT_GUI_FEATURE @@ -170,6 +171,7 @@ using QList_QSizeF = QList<::QSizeF>; using QList_QString = QList<::QString>; using QList_QTime = QList<::QTime>; using QList_QUrl = QList<::QUrl>; +using QList_QUuid = QList<::QUuid>; using QList_QVariant = QList<::QVariant>; using QList_u8 = QList<::std::uint8_t>; using QList_u16 = QList<::std::uint16_t>; diff --git a/crates/cxx-qt-lib/include/core/qset.h b/crates/cxx-qt-lib/include/core/qset.h index d7f041b24..a92d474b1 100644 --- a/crates/cxx-qt-lib/include/core/qset.h +++ b/crates/cxx-qt-lib/include/core/qset.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "rust/cxx.h" @@ -84,6 +85,7 @@ using QSet_QPersistentModelIndex = QSet<::QPersistentModelIndex>; using QSet_QString = QSet<::QString>; using QSet_QTime = QSet<::QTime>; using QSet_QUrl = QSet<::QUrl>; +using QSet_QUuid = QSet<::QUuid>; using QSet_u8 = QSet<::std::uint8_t>; using QSet_u16 = QSet<::std::uint16_t>; using QSet_u32 = QSet<::std::uint32_t>; diff --git a/crates/cxx-qt-lib/include/core/quuid.h b/crates/cxx-qt-lib/include/core/quuid.h new file mode 100644 index 000000000..55f6e4b2d --- /dev/null +++ b/crates/cxx-qt-lib/include/core/quuid.h @@ -0,0 +1,40 @@ +// clang-format off +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// SPDX-FileContributor: Joshua Booth +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#pragma once + +#include + +#include "rust/cxx.h" + +using QUuidVariant = QUuid::Variant; +using QUuidVersion = QUuid::Version; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) +using QUuidFromStringParam = const QString&; +#else +using QUuidFromStringParam = QAnyStringView; +#endif + +namespace rust { +namespace cxxqtlib1 { +QUuid +quuidNewV3(const QUuid& ns, ::rust::Slice slice); + +QUuid +quuidNewV4(); + +QUuid +quuidNewV5(const QUuid& ns, ::rust::Slice slice); + +QString +quuidToString(const QUuid& uuid); + +QUuid +quuidFromString(QAnyStringView string); +} +} diff --git a/crates/cxx-qt-lib/include/core/qvariant.h b/crates/cxx-qt-lib/include/core/qvariant.h index 2b23c466e..52c8e7625 100644 --- a/crates/cxx-qt-lib/include/core/qvariant.h +++ b/crates/cxx-qt-lib/include/core/qvariant.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CXX_QT_GUI_FEATURE #include @@ -91,6 +92,7 @@ CXX_QT_QVARIANT_CAN_CONVERT(QString) CXX_QT_QVARIANT_CAN_CONVERT(QStringList) CXX_QT_QVARIANT_CAN_CONVERT(QTime) CXX_QT_QVARIANT_CAN_CONVERT(QUrl) +CXX_QT_QVARIANT_CAN_CONVERT(QUuid) CXX_QT_QVARIANT_CAN_CONVERT(U8) CXX_QT_QVARIANT_CAN_CONVERT(U16) CXX_QT_QVARIANT_CAN_CONVERT(U32) diff --git a/crates/cxx-qt-lib/include/core/qvector.h b/crates/cxx-qt-lib/include/core/qvector.h index f61b96e94..8a4faa3f4 100644 --- a/crates/cxx-qt-lib/include/core/qvector.h +++ b/crates/cxx-qt-lib/include/core/qvector.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #ifdef CXX_QT_GUI_FEATURE @@ -167,6 +168,7 @@ using QVector_QSizeF = QVector<::QSizeF>; using QVector_QString = QVector<::QString>; using QVector_QTime = QVector<::QTime>; using QVector_QUrl = QVector<::QUrl>; +using QVector_QUuid = QVector<::QUuid>; using QVector_QVariant = QVector<::QVariant>; using QVector_u8 = QVector<::std::uint8_t>; using QVector_u16 = QVector<::std::uint16_t>; diff --git a/crates/cxx-qt-lib/src/core/mod.rs b/crates/cxx-qt-lib/src/core/mod.rs index a2e9bfa33..bf488d2e2 100644 --- a/crates/cxx-qt-lib/src/core/mod.rs +++ b/crates/cxx-qt-lib/src/core/mod.rs @@ -97,6 +97,9 @@ pub use qpointf::QPointF; mod qurl; pub use qurl::QUrl; +mod quuid; +pub use quuid::{QUuid, QUuidVariant, QUuidVersion}; + mod qvariant; pub use qvariant::{QVariant, QVariantValue}; diff --git a/crates/cxx-qt-lib/src/core/qlist/generate.sh b/crates/cxx-qt-lib/src/core/qlist/generate.sh index 037e72e40..70bb43ade 100755 --- a/crates/cxx-qt-lib/src/core/qlist/generate.sh +++ b/crates/cxx-qt-lib/src/core/qlist/generate.sh @@ -227,6 +227,7 @@ generate_bridge_qt "QSizeF" "qsizef" generate_bridge_qt "QString" "qstring" generate_bridge_qt "QTime" "qtime" generate_bridge_qt "QUrl" "qurl" +generate_bridge_qt "QUuid" "quuid" generate_bridge_qt "QVariant" "qvariant" generate_bridge_qt "QLine" "qline" generate_bridge_qt "QLineF" "qlinef" diff --git a/crates/cxx-qt-lib/src/core/qlist/mod.rs b/crates/cxx-qt-lib/src/core/qlist/mod.rs index 59c219256..baa075474 100644 --- a/crates/cxx-qt-lib/src/core/qlist/mod.rs +++ b/crates/cxx-qt-lib/src/core/qlist/mod.rs @@ -9,7 +9,7 @@ use crate::QColor; use crate::QDateTime; use crate::{ QByteArray, QDate, QLine, QLineF, QMargins, QMarginsF, QPersistentModelIndex, QPoint, QPointF, - QRect, QRectF, QSize, QSizeF, QString, QTime, QUrl, QVariant, + QRect, QRectF, QSize, QSizeF, QString, QTime, QUrl, QUuid, QVariant, }; use core::{marker::PhantomData, mem::MaybeUninit}; use cxx::{type_id, ExternType}; @@ -373,6 +373,7 @@ impl_qlist_element!(QSizeF, qlist_qsizef, "QList_QSizeF"); impl_qlist_element!(QString, qlist_qstring, "QList_QString"); impl_qlist_element!(QTime, qlist_qtime, "QList_QTime"); impl_qlist_element!(QUrl, qlist_qurl, "QList_QUrl"); +impl_qlist_element!(QUuid, qlist_quuid, "QList_QUuid"); impl_qlist_element!(QVariant, qlist_qvariant, "QList_QVariant"); impl_qlist_element!(u8, qlist_u8, "QList_u8"); impl_qlist_element!(u16, qlist_u16, "QList_u16"); diff --git a/crates/cxx-qt-lib/src/core/qlist/qlist.cpp b/crates/cxx-qt-lib/src/core/qlist/qlist.cpp index 78819a162..49a0a1c03 100644 --- a/crates/cxx-qt-lib/src/core/qlist/qlist.cpp +++ b/crates/cxx-qt-lib/src/core/qlist/qlist.cpp @@ -57,6 +57,7 @@ CXX_QT_QLIST_ASSERTS(::QSizeF, QSizeF); CXX_QT_QLIST_ASSERTS(::QString, QString); CXX_QT_QLIST_ASSERTS(::QTime, QTime); CXX_QT_QLIST_ASSERTS(::QUrl, QUrl); +CXX_QT_QLIST_ASSERTS(::QUuid, QUuid); CXX_QT_QLIST_ASSERTS(::QVariant, QVariant); CXX_QT_QLIST_ASSERTS(::std::uint8_t, u8); CXX_QT_QLIST_ASSERTS(::std::uint16_t, u16); diff --git a/crates/cxx-qt-lib/src/core/qlist/qlist_quuid.rs b/crates/cxx-qt-lib/src/core/qlist/qlist_quuid.rs new file mode 100644 index 000000000..d99b2b305 --- /dev/null +++ b/crates/cxx-qt-lib/src/core/qlist/qlist_quuid.rs @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#[cxx::bridge] +pub mod ffi { + unsafe extern "C++" { + include!("cxx-qt-lib/quuid.h"); + type QUuid = crate::QUuid; + + include!("cxx-qt-lib/qlist.h"); + type QList_QUuid = crate::QList; + } + + unsafe extern "C++" { + #[rust_name = "cxx_clear"] + fn clear(self: &mut QList_QUuid); + #[rust_name = "cxx_contains"] + fn contains(self: &QList_QUuid, _: &QUuid) -> bool; + } + + #[namespace = "rust::cxxqtlib1"] + unsafe extern "C++" { + include!("cxx-qt-lib/common.h"); + + #[rust_name = "qlist_clone_QUuid"] + fn construct(_: &QList_QUuid) -> QList_QUuid; + #[rust_name = "qlist_default_QUuid"] + fn construct() -> QList_QUuid; + #[rust_name = "qlist_drop_QUuid"] + fn drop(_: &mut QList_QUuid); + } + + #[namespace = "rust::cxxqtlib1::qlist"] + unsafe extern "C++" { + #[rust_name = "reserve_QUuid"] + fn qlistReserve(_: &mut QList_QUuid, size: isize); + #[rust_name = "append_QUuid"] + fn qlistAppend(_: &mut QList_QUuid, _: &QUuid); + #[rust_name = "get_unchecked_QUuid"] + unsafe fn qlistGetUnchecked(set: &QList_QUuid, pos: isize) -> &QUuid; + #[rust_name = "index_of_QUuid"] + fn qlistIndexOf(_: &QList_QUuid, _: &QUuid) -> isize; + #[rust_name = "insert_QUuid"] + fn qlistInsert(_: &mut QList_QUuid, _: isize, _: &QUuid); + #[rust_name = "remove_QUuid"] + fn qlistRemove(_: &mut QList_QUuid, _: isize); + #[rust_name = "len_QUuid"] + fn qlistLen(_: &QList_QUuid) -> isize; + } +} + +pub(crate) fn reserve(v: &mut ffi::QList_QUuid, size: isize) { + ffi::reserve_QUuid(v, size); +} + +pub(crate) fn append(v: &mut ffi::QList_QUuid, value: &ffi::QUuid) { + ffi::append_QUuid(v, value); +} + +pub(crate) fn clone(s: &ffi::QList_QUuid) -> ffi::QList_QUuid { + ffi::qlist_clone_QUuid(s) +} + +pub(crate) fn default() -> ffi::QList_QUuid { + ffi::qlist_default_QUuid() +} + +pub(crate) fn drop(s: &mut ffi::QList_QUuid) { + ffi::qlist_drop_QUuid(s); +} + +pub(crate) unsafe fn get_unchecked(s: &ffi::QList_QUuid, pos: isize) -> &ffi::QUuid { + ffi::get_unchecked_QUuid(s, pos) +} + +pub(crate) fn index_of(v: &ffi::QList_QUuid, value: &ffi::QUuid) -> isize { + ffi::index_of_QUuid(v, value) +} + +pub(crate) fn insert(s: &mut ffi::QList_QUuid, pos: isize, value: &ffi::QUuid) { + ffi::insert_QUuid(s, pos, value); +} + +pub(crate) fn len(s: &ffi::QList_QUuid) -> isize { + ffi::len_QUuid(s) +} + +pub(crate) fn remove(s: &mut ffi::QList_QUuid, pos: isize) { + ffi::remove_QUuid(s, pos); +} diff --git a/crates/cxx-qt-lib/src/core/qset/generate.sh b/crates/cxx-qt-lib/src/core/qset/generate.sh index cc292c352..93b1da84d 100755 --- a/crates/cxx-qt-lib/src/core/qset/generate.sh +++ b/crates/cxx-qt-lib/src/core/qset/generate.sh @@ -174,6 +174,7 @@ generate_bridge_qt "QPersistentModelIndex" "qpersistentmodelindex" generate_bridge_qt "QString" "qstring" generate_bridge_qt "QTime" "qtime" generate_bridge_qt "QUrl" "qurl" +generate_bridge_qt "QUuid" "quuid" generate_bridge_primitive "u8" generate_bridge_primitive "u16" generate_bridge_primitive "u32" diff --git a/crates/cxx-qt-lib/src/core/qset/mod.rs b/crates/cxx-qt-lib/src/core/qset/mod.rs index 45e44ced0..7b76d2a11 100644 --- a/crates/cxx-qt-lib/src/core/qset/mod.rs +++ b/crates/cxx-qt-lib/src/core/qset/mod.rs @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 #[cfg(not(target_os = "emscripten"))] use crate::QDateTime; -use crate::{QByteArray, QDate, QPersistentModelIndex, QString, QTime, QUrl}; +use crate::{QByteArray, QDate, QPersistentModelIndex, QString, QTime, QUrl, QUuid}; use core::{marker::PhantomData, mem::MaybeUninit}; use cxx::{type_id, ExternType}; @@ -262,6 +262,7 @@ impl_qset_element!( impl_qset_element!(QString, qset_qstring, "QSet_QString"); impl_qset_element!(QTime, qset_qtime, "QSet_QTime"); impl_qset_element!(QUrl, qset_qurl, "QSet_QUrl"); +impl_qset_element!(QUuid, qset_quuid, "QSet_QUuid"); impl_qset_element!(u8, qset_u8, "QSet_u8"); impl_qset_element!(u16, qset_u16, "QSet_u16"); impl_qset_element!(u32, qset_u32, "QSet_u32"); diff --git a/crates/cxx-qt-lib/src/core/qset/qset.cpp b/crates/cxx-qt-lib/src/core/qset/qset.cpp index e8bbccf40..f1296f4af 100644 --- a/crates/cxx-qt-lib/src/core/qset/qset.cpp +++ b/crates/cxx-qt-lib/src/core/qset/qset.cpp @@ -34,6 +34,7 @@ CXX_QT_QSET_ASSERTS(::QPersistentModelIndex, QPersistentModelIndex); CXX_QT_QSET_ASSERTS(::QString, QString); CXX_QT_QSET_ASSERTS(::QTime, QTime); CXX_QT_QSET_ASSERTS(::QUrl, QUrl); +CXX_QT_QSET_ASSERTS(::QUuid, QUuid); CXX_QT_QSET_ASSERTS(::std::uint8_t, u8); CXX_QT_QSET_ASSERTS(::std::uint16_t, u16); CXX_QT_QSET_ASSERTS(::std::uint32_t, u32); diff --git a/crates/cxx-qt-lib/src/core/qset/qset_quuid.rs b/crates/cxx-qt-lib/src/core/qset/qset_quuid.rs new file mode 100644 index 000000000..c2a4cddae --- /dev/null +++ b/crates/cxx-qt-lib/src/core/qset/qset_quuid.rs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#[cxx::bridge] +pub mod ffi { + unsafe extern "C++" { + include!("cxx-qt-lib/quuid.h"); + type QUuid = crate::QUuid; + + include!("cxx-qt-lib/qset.h"); + type QSet_QUuid = crate::QSet; + } + + unsafe extern "C++" { + #[rust_name = "cxx_clear"] + fn clear(self: &mut QSet_QUuid); + #[rust_name = "cxx_contains"] + fn contains(self: &QSet_QUuid, _: &QUuid) -> bool; + #[rust_name = "cxx_remove"] + fn remove(self: &mut QSet_QUuid, _: &QUuid) -> bool; + } + + #[namespace = "rust::cxxqtlib1"] + unsafe extern "C++" { + include!("cxx-qt-lib/common.h"); + + #[rust_name = "qset_clone_QUuid"] + fn construct(_: &QSet_QUuid) -> QSet_QUuid; + #[rust_name = "qset_default_QUuid"] + fn construct() -> QSet_QUuid; + #[rust_name = "qset_drop_QUuid"] + fn drop(_: &mut QSet_QUuid); + } + + #[namespace = "rust::cxxqtlib1::qset"] + unsafe extern "C++" { + #[rust_name = "get_unchecked_QUuid"] + unsafe fn qsetGetUnchecked(set: &QSet_QUuid, pos: isize) -> &QUuid; + #[rust_name = "insert_QUuid"] + fn qsetInsert(_: &mut QSet_QUuid, _: &QUuid); + #[rust_name = "len_QUuid"] + fn qsetLen(_: &QSet_QUuid) -> isize; + } +} + +pub(crate) fn clone(s: &ffi::QSet_QUuid) -> ffi::QSet_QUuid { + ffi::qset_clone_QUuid(s) +} + +pub(crate) fn default() -> ffi::QSet_QUuid { + ffi::qset_default_QUuid() +} + +pub(crate) fn drop(s: &mut ffi::QSet_QUuid) { + ffi::qset_drop_QUuid(s); +} + +pub(crate) unsafe fn get_unchecked(s: &ffi::QSet_QUuid, pos: isize) -> &ffi::QUuid { + ffi::get_unchecked_QUuid(s, pos) +} + +pub(crate) fn insert(s: &mut ffi::QSet_QUuid, value: &ffi::QUuid) { + ffi::insert_QUuid(s, value); +} + +pub(crate) fn len(s: &ffi::QSet_QUuid) -> isize { + ffi::len_QUuid(s) +} diff --git a/crates/cxx-qt-lib/src/core/quuid.cpp b/crates/cxx-qt-lib/src/core/quuid.cpp new file mode 100644 index 000000000..a77ccbc64 --- /dev/null +++ b/crates/cxx-qt-lib/src/core/quuid.cpp @@ -0,0 +1,71 @@ +// clang-format off +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// SPDX-FileContributor: Joshua Booth +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#include "cxx-qt-lib/quuid.h" + +#include + +assert_alignment_and_size(QUuid, { + ::std::uint32_t data1; + ::std::uint16_t data2; + ::std::uint16_t data3; + ::std::uint8_t data4[8]; +}); + +static_assert(::std::is_trivially_copyable::value, + "QUuid must be trivially copyable!"); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) +#define byteView(slice) QByteArrayView(slice.data(), slice.length()) +#elif QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#define byteView(slice) \ + QByteArray::fromRawData(reinterpret_cast(slice.data()), \ + static_cast(slice.size())) +#else +#define byteView(slice) \ + QByteArray::fromRawData(reinterpret_cast(slice.data()), \ + static_cast(slice.size())) +#endif + +namespace rust { +namespace cxxqtlib1 { +QUuid +quuidNewV3(const QUuid& ns, ::rust::Slice slice) +{ + return QUuid::createUuidV3(ns, byteView(slice)); +} + +QUuid +quuidNewV4() +{ + return QUuid::createUuid(); +} + +QUuid +quuidNewV5(const QUuid& ns, ::rust::Slice slice) +{ + return QUuid::createUuidV5(ns, byteView(slice)); +} + +QString +quuidToString(const QUuid& uuid) +{ + return uuid.toString(); +} + +QUuid +quuidFromString(QAnyStringView string) +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + return QUuid::fromString(string); // we can use UTF8 strings directly +#else + return QUuid::fromString(QString(string)); +#endif +} + +} +} diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs new file mode 100644 index 000000000..d8bb3210e --- /dev/null +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -0,0 +1,386 @@ +use crate::QString; +use cxx::{type_id, ExternType}; +use std::fmt; +#[cfg(feature = "uuid")] +use uuid::Uuid; + +#[cxx::bridge] +mod ffi { + #[repr(i32)] + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + enum QUuidVariant { + /// Variant is unknown + VarUnknown = -1, + /// Reserved for NCS (Network Computing System) backward compatibility + NCS = 0, + /// Distributed Computing Environment, the scheme used by QUuid + DCE = 2, + /// Reserved for Microsoft backward compatibility (GUID) + Microsoft = 6, + /// Reserved for future definition + Reserved = 7, + } + + #[repr(i32)] + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + enum QUuidVersion { + /// Version is unknown + VerUnknown = -1, + /// Time-based, by using timestamp, clock sequence, and MAC network card address (if + /// available) for the node sections + Time = 1, + /// DCE Security version, with embedded POSIX UUIDs + EmbeddedPOSIX = 2, + /// Name-based, by using values from a name for all sections + Md5 = 3, + /// Random-based, by using random numbers for all sections + Random = 4, + Sha1 = 5, + } + + unsafe extern "C++" { + include!("cxx-qt-lib/qbytearray.h"); + type QByteArray = crate::QByteArray; + } + + unsafe extern "C++" { + include!("cxx-qt-lib/qstring.h"); + type QString = crate::QString; + type QAnyStringView<'a> = crate::QAnyStringView<'a>; + } + + unsafe extern "C++" { + include!("cxx-qt-lib/quuid.h"); + type QUuid = super::QUuid; + type QUuidVariant; + type QUuidVersion; + + /// Returns true if this is the null UUID `{00000000-0000-0000-0000-000000000000}`. + /// otherwise returns false. + #[rust_name = "is_null"] + fn isNull(self: &QUuid) -> bool; + + /// Returns the value in the variant field of the UUID. If the return value is + /// `QUuidVariant::DCE`, call `version()` to see which layout it uses. The null UUID is + /// considered to be of an unknown variant. + fn variant(self: &QUuid) -> QUuidVariant; + + /// Returns the version field of the UUID, if the UUID's variant field is `QUuidVariant::DCE`. + /// Otherwise it returns `QUuidVariant::VerUnknown`. + fn version(self: &QUuid) -> QUuidVersion; + + /// Returns the binary representation of this UUID. The byte array is in big endian format, + /// and formatted according to RFC 4122, section 4.1.2 - "Layout and byte order". + #[rust_name = "to_rfc_122"] + fn toRfc4122(self: &QUuid) -> QByteArray; + } + + #[namespace = "rust::cxxqtlib1"] + unsafe extern "C++" { + #[doc(hidden)] + #[rust_name = "quuid_new_v3"] + fn quuidNewV3(ns: &QUuid, data: &[u8]) -> QUuid; + #[doc(hidden)] + #[rust_name = "quuid_new_v4"] + fn quuidNewV4() -> QUuid; + #[doc(hidden)] + #[rust_name = "quuid_new_v5"] + fn quuidNewV5(ns: &QUuid, data: &[u8]) -> QUuid; + #[doc(hidden)] + #[rust_name = "quuid_to_string"] + fn quuidToString(uuid: &QUuid) -> QString; + #[doc(hidden)] + #[rust_name = "quuid_from_string"] + fn quuidFromString(string: QAnyStringView) -> QUuid; + } +} + +pub use ffi::{QUuidVariant, QUuidVersion}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(C)] +pub struct QUuid { + data1: u32, + data2: u16, + data3: u16, + data4: [u8; 8], +} + +impl Default for QUuid { + /// Creates the null UUID. `to_string()` will output the null UUID as + /// "{00000000-0000-0000-0000-000000000000}". + fn default() -> Self { + Self::null() + } +} + +impl fmt::Display for QUuid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ffi::quuid_to_string(self).fmt(f) + } +} + +impl fmt::Debug for QUuid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ffi::quuid_to_string(self).fmt(f) + } +} + +impl QUuid { + /// Creates the null UUID. `to_string()` will output the null UUID as + /// "{00000000-0000-0000-0000-000000000000}". + pub const fn null() -> Self { + Self { + data1: 0, + data2: 0, + data3: 0, + data4: [0; 8], + } + } + + /// This function returns a new UUID with variant `QUuidVariant::DCE` and version + /// `QUuidVersion::Md5`. `namespace` is the namespace and `data` is the basic data as described + /// by RFC 4122. + pub fn new_v3(namespace: &Self, data: &[u8]) -> Self { + ffi::quuid_new_v3(namespace, data) + } + + /// On any platform other than Windows, this function returns a new UUID with variant + /// `QUuidVariant::DCE` and version `QUuidVersion::Random`. On Windows, a GUID is generated using + /// the Windows API and will be of the type that the API decides to create. + pub fn new_v4() -> Self { + ffi::quuid_new_v4() + } + + /// This function returns a new UUID with variant `QUuidVariant::DCE` and version + /// `QUuidVersion::Sha1`. `namespace` is the namespace and `data` is the basic data as described + /// by RFC 4122. + pub fn new_v5(namespace: &Self, data: &[u8]) -> Self { + ffi::quuid_new_v5(namespace, data) + } + + /// Creates a QUuid object from the string text, which must be formatted as five hex fields + /// separated by '-', e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex + /// digit. The curly braces shown here are optional, but it is normal to include them. + /// + /// If the conversion fails, a null UUID is returned. + pub fn from_string<'a, S>(s: S) -> Self + where + S: Into>, + { + ffi::quuid_from_string(s.into()) + } + + /// Creates a UUID with the value specified by the parameters. + pub const fn from_fields(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self { + Self { + data1, + data2, + data3, + data4, + } + } + + pub const fn as_fields(&self) -> (u32, u16, u16, [u8; 8]) { + (self.data1, self.data2, self.data3, self.data4) + } + + /// Creates a UUID from its representation as a byte array in big endian. + pub const fn from_bytes(bytes: [u8; 16]) -> Self { + #[cfg(target_endian = "big")] + let [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf] = bytes; + #[cfg(target_endian = "little")] + let [b3, b2, b1, b0, b5, b4, b7, b6, b8, b9, ba, bb, bc, bd, be, bf] = bytes; + Self { + data1: u32::from_ne_bytes([b0, b1, b2, b3]), + data2: u16::from_ne_bytes([b4, b5]), + data3: u16::from_ne_bytes([b6, b7]), + data4: [b8, b9, ba, bb, bc, bd, be, bf], + } + } + + /// Returns the memory representation of this UUID as a byte array in big-endian byte order. + pub const fn to_bytes(self) -> [u8; 16] { + let [b0, b1, b2, b3] = self.data1.to_ne_bytes(); + let [b4, b5] = self.data2.to_ne_bytes(); + let [b6, b7] = self.data3.to_ne_bytes(); + let [b8, b9, ba, bb, bc, bd, be, bf] = self.data4; + #[cfg(target_endian = "big")] + { + [ + b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf, + ] + } + #[cfg(target_endian = "little")] + { + [ + b3, b2, b1, b0, b5, b4, b7, b6, b8, b9, ba, bb, bc, bd, be, bf, + ] + } + } + + /// Creates a UUID from its representation as a 128-bit integer. + pub const fn from_u128(data: u128) -> Self { + Self::from_bytes(data.to_be_bytes()) + } + + /// Returns the memory representation of this UUID as a 128-bit integer. + pub const fn to_u128(self) -> u128 { + u128::from_be_bytes(self.to_bytes()) + } +} + +unsafe impl ExternType for QUuid { + type Id = type_id!("QUuid"); + type Kind = cxx::kind::Trivial; +} + +impl From for QString { + fn from(value: QUuid) -> Self { + ffi::quuid_to_string(&value) + } +} + +impl From for QUuid { + fn from(value: u128) -> Self { + Self::from_u128(value) + } +} + +impl From for u128 { + fn from(value: QUuid) -> Self { + value.to_u128() + } +} + +#[cfg(feature = "uuid")] +impl From for QUuid { + fn from(value: Uuid) -> Self { + let (data1, data2, data3, &data4) = value.as_fields(); + Self { + data1, + data2, + data3, + data4, + } + } +} + +#[cfg(feature = "uuid")] +impl From for Uuid { + fn from(value: QUuid) -> Self { + Self::from_fields(value.data1, value.data2, value.data3, &value.data4) + } +} + +#[cfg(test)] +mod test { + use super::*; + + const NAMESPACE_DNS: &QUuid = &QUuid::from_u128(0x6ba7b8109dad11d180b400c04fd430c); + + #[test] + fn quuid_is_null() { + assert!(QUuid::null().is_null()) + } + + #[test] + fn quuid_is_not_null() { + assert!(!QUuid::new_v4().is_null()) + } + + #[test] + fn quuid_variant() { + assert_eq!( + [QUuid::null().variant(), QUuid::new_v4().variant()], + [QUuidVariant::VarUnknown, QUuidVariant::DCE] + ); + } + + #[test] + fn quuid_version() { + assert_eq!( + [ + QUuid::null().version(), + QUuid::new_v3(NAMESPACE_DNS, &[]).version(), + QUuid::new_v4().version(), + QUuid::new_v5(NAMESPACE_DNS, &[]).version(), + ], + [ + QUuidVersion::VerUnknown, + QUuidVersion::Md5, + QUuidVersion::Random, + QUuidVersion::Sha1 + ] + ) + } + + #[test] + fn quuid_to_rfc_122() { + let bytes = <[u8; 16]>::try_from("random test data".as_bytes()).unwrap(); + assert_eq!(Vec::from(&QUuid::from_bytes(bytes).to_rfc_122()), bytes) + } + + #[test] + fn quuid_null() { + assert_eq!(QUuid::null(), QUuid::from_u128(0)); + } + + #[test] + fn quuid_new_v3() { + assert_eq!( + QUuid::new_v3(NAMESPACE_DNS, "testdata".as_bytes()), + QUuid::from_u128(0x5157facac7e1345c927671c2c6d41e7a) + ); + } + + #[test] + fn quuid_new_v4() { + assert_ne!(QUuid::new_v4(), QUuid::new_v4()); + } + + #[test] + fn quuid_new_v5() { + assert_eq!( + QUuid::new_v5(NAMESPACE_DNS, "testdata".as_bytes()), + QUuid::from_u128(0x7e95e361a22c51c18c297ac24cb61e83) + ); + } + + #[test] + fn quuid_to_string() { + assert_eq!( + QUuid::from_u128(0x7e95e361a22c51c18c297ac24cb61e83).to_string(), + "{7e95e361-a22c-51c1-8c29-7ac24cb61e83}" + ) + } + + #[test] + fn quuid_string_round_trip() { + let uuid = QUuid::new_v4(); + let roundtrip = QUuid::from_string(&QString::from(&uuid.to_string())); + assert_eq!(uuid, roundtrip) + } + + #[test] + fn quuid_fields_round_trip() { + let uuid = QUuid::new_v4(); + let (d1, d2, d3, d4) = uuid.as_fields(); + let roundtrip = QUuid::from_fields(d1, d2, d3, d4); + assert_eq!(uuid, roundtrip) + } + + #[test] + fn quuid_bytes_round_trip() { + let uuid = QUuid::new_v4(); + let roundtrip = QUuid::from_bytes(uuid.to_bytes()); + assert_eq!(uuid, roundtrip) + } + + #[test] + fn quuid_u128_round_trip() { + let uuid = QUuid::new_v4(); + let roundtrip = QUuid::from_u128(uuid.to_u128()); + assert_eq!(uuid, roundtrip) + } +} diff --git a/crates/cxx-qt-lib/src/core/qvariant/generate.sh b/crates/cxx-qt-lib/src/core/qvariant/generate.sh index f9eab338e..2bb4701a1 100755 --- a/crates/cxx-qt-lib/src/core/qvariant/generate.sh +++ b/crates/cxx-qt-lib/src/core/qvariant/generate.sh @@ -116,6 +116,7 @@ generate_bridge_qt "QString" "qstring" generate_bridge_qt "QStringList" "qstringlist" generate_bridge_qt "QTime" "qtime" generate_bridge_qt "QUrl" "qurl" +generate_bridge_qt "QUuid" "quuid" generate_bridge_primitive "u8" "U8" generate_bridge_primitive "u16" "U16" generate_bridge_primitive "u32" "U32" diff --git a/crates/cxx-qt-lib/src/core/qvariant/mod.rs b/crates/cxx-qt-lib/src/core/qvariant/mod.rs index 8d196ca96..ccdd3f80b 100644 --- a/crates/cxx-qt-lib/src/core/qvariant/mod.rs +++ b/crates/cxx-qt-lib/src/core/qvariant/mod.rs @@ -181,6 +181,7 @@ impl_qvariant_value!(crate::QString, qvariant_qstring); impl_qvariant_value!(crate::QStringList, qvariant_qstringlist); impl_qvariant_value!(crate::QTime, qvariant_qtime); impl_qvariant_value!(crate::QUrl, qvariant_qurl); +impl_qvariant_value!(crate::QUuid, qvariant_quuid); impl_qvariant_value!(u8, qvariant_u8); impl_qvariant_value!(u16, qvariant_u16); impl_qvariant_value!(u32, qvariant_u32); diff --git a/crates/cxx-qt-lib/src/core/qvariant/qvariant.cpp b/crates/cxx-qt-lib/src/core/qvariant/qvariant.cpp index bf94ff721..5d812e501 100644 --- a/crates/cxx-qt-lib/src/core/qvariant/qvariant.cpp +++ b/crates/cxx-qt-lib/src/core/qvariant/qvariant.cpp @@ -83,6 +83,7 @@ CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::QString, QString) CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::QStringList, QStringList) CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::QTime, QTime) CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::QUrl, QUrl) +CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::QUuid, QUuid) CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::std::uint8_t, U8) CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::std::uint16_t, U16) CXX_QT_QVARIANT_CAN_CONVERT_IMPL(::std::uint32_t, U32) diff --git a/crates/cxx-qt-lib/src/core/qvariant/qvariant_quuid.rs b/crates/cxx-qt-lib/src/core/qvariant/qvariant_quuid.rs new file mode 100644 index 000000000..c3dca7b65 --- /dev/null +++ b/crates/cxx-qt-lib/src/core/qvariant/qvariant_quuid.rs @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#[cxx::bridge] +pub mod ffi { + unsafe extern "C++" { + include!("cxx-qt-lib/quuid.h"); + type QUuid = crate::QUuid; + + include!("cxx-qt-lib/qvariant.h"); + type QVariant = crate::QVariant; + } + + #[namespace = "rust::cxxqtlib1::qvariant"] + unsafe extern "C++" { + #[rust_name = "can_convert_QUuid"] + fn qvariantCanConvertQUuid(variant: &QVariant) -> bool; + #[rust_name = "construct_QUuid"] + fn qvariantConstruct(value: &QUuid) -> QVariant; + #[rust_name = "value_or_default_QUuid"] + fn qvariantValueOrDefault(variant: &QVariant) -> QUuid; + } +} + +pub(crate) fn can_convert(variant: &ffi::QVariant) -> bool { + ffi::can_convert_QUuid(variant) +} + +pub(crate) fn construct(value: &ffi::QUuid) -> ffi::QVariant { + ffi::construct_QUuid(value) +} + +pub(crate) fn value_or_default(variant: &ffi::QVariant) -> ffi::QUuid { + ffi::value_or_default_QUuid(variant) +} diff --git a/crates/cxx-qt-lib/src/core/qvector/generate.sh b/crates/cxx-qt-lib/src/core/qvector/generate.sh index 519400a2a..229ca3c75 100755 --- a/crates/cxx-qt-lib/src/core/qvector/generate.sh +++ b/crates/cxx-qt-lib/src/core/qvector/generate.sh @@ -229,6 +229,7 @@ generate_bridge_qt "QSizeF" "qsizef" generate_bridge_qt "QString" "qstring" generate_bridge_qt "QTime" "qtime" generate_bridge_qt "QUrl" "qurl" +generate_bridge_qt "QUuid" "quuid" generate_bridge_qt "QVariant" "qvariant" generate_bridge_primitive "u8" generate_bridge_primitive "u16" diff --git a/crates/cxx-qt-lib/src/core/qvector/mod.rs b/crates/cxx-qt-lib/src/core/qvector/mod.rs index 1894418fe..2f1568287 100644 --- a/crates/cxx-qt-lib/src/core/qvector/mod.rs +++ b/crates/cxx-qt-lib/src/core/qvector/mod.rs @@ -9,7 +9,7 @@ use crate::QColor; use crate::QDateTime; use crate::{ QByteArray, QDate, QLine, QLineF, QMargins, QMarginsF, QPersistentModelIndex, QPoint, QPointF, - QRect, QRectF, QSize, QSizeF, QString, QTime, QUrl, QVariant, + QRect, QRectF, QSize, QSizeF, QString, QTime, QUrl, QUuid, QVariant, }; use core::{marker::PhantomData, mem::MaybeUninit}; use cxx::{type_id, ExternType}; @@ -373,6 +373,7 @@ impl_qvector_element!(QSizeF, qvector_qsizef, "QVector_QSizeF"); impl_qvector_element!(QString, qvector_qstring, "QVector_QString"); impl_qvector_element!(QTime, qvector_qtime, "QVector_QTime"); impl_qvector_element!(QUrl, qvector_qurl, "QVector_QUrl"); +impl_qvector_element!(QUuid, qvector_quuid, "QVector_QUuid"); impl_qvector_element!(QVariant, qvector_qvariant, "QVector_QVariant"); impl_qvector_element!(u8, qvector_u8, "QVector_u8"); impl_qvector_element!(u16, qvector_u16, "QVector_u16"); diff --git a/crates/cxx-qt-lib/src/core/qvector/qvector.cpp b/crates/cxx-qt-lib/src/core/qvector/qvector.cpp index 236f92e6f..7323c5df9 100644 --- a/crates/cxx-qt-lib/src/core/qvector/qvector.cpp +++ b/crates/cxx-qt-lib/src/core/qvector/qvector.cpp @@ -58,6 +58,7 @@ CXX_QT_QVECTOR_ASSERTS(::QSizeF, QSizeF); CXX_QT_QVECTOR_ASSERTS(::QString, QString); CXX_QT_QVECTOR_ASSERTS(::QTime, QTime); CXX_QT_QVECTOR_ASSERTS(::QUrl, QUrl); +CXX_QT_QVECTOR_ASSERTS(::QUuid, QUuid); CXX_QT_QVECTOR_ASSERTS(::QVariant, QVariant); CXX_QT_QVECTOR_ASSERTS(::std::uint8_t, u8); CXX_QT_QVECTOR_ASSERTS(::std::uint16_t, u16); diff --git a/crates/cxx-qt-lib/src/core/qvector/qvector_quuid.rs b/crates/cxx-qt-lib/src/core/qvector/qvector_quuid.rs new file mode 100644 index 000000000..8cf0a4702 --- /dev/null +++ b/crates/cxx-qt-lib/src/core/qvector/qvector_quuid.rs @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#[cxx::bridge] +pub mod ffi { + unsafe extern "C++" { + include!("cxx-qt-lib/quuid.h"); + type QUuid = crate::QUuid; + + include!("cxx-qt-lib/qvector.h"); + type QVector_QUuid = crate::QVector; + } + + unsafe extern "C++" { + #[rust_name = "cxx_clear"] + fn clear(self: &mut QVector_QUuid); + #[rust_name = "cxx_contains"] + fn contains(self: &QVector_QUuid, _: &QUuid) -> bool; + } + + #[namespace = "rust::cxxqtlib1"] + unsafe extern "C++" { + include!("cxx-qt-lib/common.h"); + + #[rust_name = "qvector_clone_QUuid"] + fn construct(_: &QVector_QUuid) -> QVector_QUuid; + #[rust_name = "qvector_default_QUuid"] + fn construct() -> QVector_QUuid; + #[rust_name = "qvector_drop_QUuid"] + fn drop(_: &mut QVector_QUuid); + } + + #[namespace = "rust::cxxqtlib1::qvector"] + unsafe extern "C++" { + #[rust_name = "reserve_QUuid"] + fn qvectorReserve(_: &mut QVector_QUuid, size: isize); + #[rust_name = "append_QUuid"] + fn qvectorAppend(_: &mut QVector_QUuid, _: &QUuid); + #[rust_name = "get_unchecked_QUuid"] + unsafe fn qvectorGetUnchecked(set: &QVector_QUuid, pos: isize) -> &QUuid; + #[rust_name = "index_of_QUuid"] + fn qvectorIndexOf(_: &QVector_QUuid, _: &QUuid) -> isize; + #[rust_name = "insert_QUuid"] + fn qvectorInsert(_: &mut QVector_QUuid, _: isize, _: &QUuid); + #[rust_name = "remove_QUuid"] + fn qvectorRemove(_: &mut QVector_QUuid, _: isize); + #[rust_name = "len_QUuid"] + fn qvectorLen(_: &QVector_QUuid) -> isize; + } +} + +pub(crate) fn append(v: &mut ffi::QVector_QUuid, value: &ffi::QUuid) { + ffi::append_QUuid(v, value); +} + +pub(crate) fn clone(s: &ffi::QVector_QUuid) -> ffi::QVector_QUuid { + ffi::qvector_clone_QUuid(s) +} + +pub(crate) fn reserve(v: &mut ffi::QVector_QUuid, size: isize) { + ffi::reserve_QUuid(v, size); +} + +pub(crate) fn default() -> ffi::QVector_QUuid { + ffi::qvector_default_QUuid() +} + +pub(crate) fn drop(s: &mut ffi::QVector_QUuid) { + ffi::qvector_drop_QUuid(s); +} + +pub(crate) unsafe fn get_unchecked(s: &ffi::QVector_QUuid, pos: isize) -> &ffi::QUuid { + ffi::get_unchecked_QUuid(s, pos) +} + +pub(crate) fn index_of(v: &ffi::QVector_QUuid, value: &ffi::QUuid) -> isize { + ffi::index_of_QUuid(v, value) +} + +pub(crate) fn insert(s: &mut ffi::QVector_QUuid, pos: isize, value: &ffi::QUuid) { + ffi::insert_QUuid(s, pos, value); +} + +pub(crate) fn len(s: &ffi::QVector_QUuid) -> isize { + ffi::len_QUuid(s) +} + +pub(crate) fn remove(s: &mut ffi::QVector_QUuid, pos: isize) { + ffi::remove_QUuid(s, pos); +} From ab59ab3f1a68bfa924f1725698dca39cb7f4335b Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Tue, 24 Dec 2024 17:34:47 -0800 Subject: [PATCH 02/18] cxx-qt-lib: remove superfluous type alias --- crates/cxx-qt-lib/include/core/quuid.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/cxx-qt-lib/include/core/quuid.h b/crates/cxx-qt-lib/include/core/quuid.h index 55f6e4b2d..0103e91e6 100644 --- a/crates/cxx-qt-lib/include/core/quuid.h +++ b/crates/cxx-qt-lib/include/core/quuid.h @@ -14,12 +14,6 @@ using QUuidVariant = QUuid::Variant; using QUuidVersion = QUuid::Version; -#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) -using QUuidFromStringParam = const QString&; -#else -using QUuidFromStringParam = QAnyStringView; -#endif - namespace rust { namespace cxxqtlib1 { QUuid From f135814ddfdd87f2a6a52f991e0827de46295560 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Tue, 24 Dec 2024 17:38:06 -0800 Subject: [PATCH 03/18] cxx-qt-lib: use &self for QUuid::to_bytes and QUuid::to_u128 --- crates/cxx-qt-lib/src/core/quuid.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index d8bb3210e..dfd7d9024 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -200,7 +200,7 @@ impl QUuid { } /// Returns the memory representation of this UUID as a byte array in big-endian byte order. - pub const fn to_bytes(self) -> [u8; 16] { + pub const fn to_bytes(&self) -> [u8; 16] { let [b0, b1, b2, b3] = self.data1.to_ne_bytes(); let [b4, b5] = self.data2.to_ne_bytes(); let [b6, b7] = self.data3.to_ne_bytes(); @@ -225,7 +225,7 @@ impl QUuid { } /// Returns the memory representation of this UUID as a 128-bit integer. - pub const fn to_u128(self) -> u128 { + pub const fn to_u128(&self) -> u128 { u128::from_be_bytes(self.to_bytes()) } } From 59a6d08341023984678fd786fb1f0a2c207a5a39 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Tue, 24 Dec 2024 17:40:52 -0800 Subject: [PATCH 04/18] pass data4 by reference in QUuid::as_fields --- crates/cxx-qt-lib/src/core/quuid.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index dfd7d9024..b818e0231 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -181,8 +181,8 @@ impl QUuid { } } - pub const fn as_fields(&self) -> (u32, u16, u16, [u8; 8]) { - (self.data1, self.data2, self.data3, self.data4) + pub const fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) { + (self.data1, self.data2, self.data3, &self.data4) } /// Creates a UUID from its representation as a byte array in big endian. @@ -365,7 +365,7 @@ mod test { #[test] fn quuid_fields_round_trip() { let uuid = QUuid::new_v4(); - let (d1, d2, d3, d4) = uuid.as_fields(); + let (d1, d2, d3, &d4) = uuid.as_fields(); let roundtrip = QUuid::from_fields(d1, d2, d3, d4); assert_eq!(uuid, roundtrip) } From c650c9df7c202fda8c2a8f15cfe8abcd85e2c301 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Thu, 26 Dec 2024 11:38:28 -0800 Subject: [PATCH 05/18] remove superfluous SPDX-FileContributor comments --- crates/cxx-qt-lib/include/core/quuid.h | 1 - crates/cxx-qt-lib/src/core/quuid.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/crates/cxx-qt-lib/include/core/quuid.h b/crates/cxx-qt-lib/include/core/quuid.h index 0103e91e6..fdda93e8f 100644 --- a/crates/cxx-qt-lib/include/core/quuid.h +++ b/crates/cxx-qt-lib/include/core/quuid.h @@ -1,7 +1,6 @@ // clang-format off // SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company // clang-format on -// SPDX-FileContributor: Andrew Hayzen // SPDX-FileContributor: Joshua Booth // // SPDX-License-Identifier: MIT OR Apache-2.0 diff --git a/crates/cxx-qt-lib/src/core/quuid.cpp b/crates/cxx-qt-lib/src/core/quuid.cpp index a77ccbc64..b1a23f501 100644 --- a/crates/cxx-qt-lib/src/core/quuid.cpp +++ b/crates/cxx-qt-lib/src/core/quuid.cpp @@ -1,7 +1,6 @@ // clang-format off // SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company // clang-format on -// SPDX-FileContributor: Andrew Hayzen // SPDX-FileContributor: Joshua Booth // // SPDX-License-Identifier: MIT OR Apache-2.0 From 729256ee3cbd2af7729befaff3a170157d10434b Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Thu, 26 Dec 2024 11:42:36 -0800 Subject: [PATCH 06/18] cxx-qt-lib: add licensing header to quuid.rs --- crates/cxx-qt-lib/src/core/quuid.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index b818e0231..567e9b0fc 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Joshua Booth +// +// SPDX-License-Identifier: MIT OR Apache-2.0 use crate::QString; use cxx::{type_id, ExternType}; use std::fmt; From 716aaa9e03da28fa108374a188916ed747425ca2 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Thu, 26 Dec 2024 11:53:52 -0800 Subject: [PATCH 07/18] add QUuid to changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01c066438..c8721299f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/KDAB/cxx-qt/compare/v0.7.0...HEAD) +### Added + +- Support for further types: `QUuid` + ### Fixed - Build warnings due to unused unsafe blocks since CXX 1.0.130 From 178ab5f4b49992b73b4af95d1adb526fb5326598 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Wed, 1 Jan 2025 14:22:52 -0800 Subject: [PATCH 08/18] cxx-qt-lib: use std::mem::transmute for QUuids --- crates/cxx-qt-lib/src/core/quuid.rs | 46 ++++++++++++----------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index 567e9b0fc..52e17305e 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::QString; use cxx::{type_id, ExternType}; -use std::fmt; +use std::{fmt, mem}; #[cfg(feature = "uuid")] use uuid::Uuid; @@ -189,40 +189,32 @@ impl QUuid { (self.data1, self.data2, self.data3, &self.data4) } - /// Creates a UUID from its representation as a byte array in big endian. - pub const fn from_bytes(bytes: [u8; 16]) -> Self { - #[cfg(target_endian = "big")] - let [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf] = bytes; - #[cfg(target_endian = "little")] - let [b3, b2, b1, b0, b5, b4, b7, b6, b8, b9, ba, bb, bc, bd, be, bf] = bytes; - Self { - data1: u32::from_ne_bytes([b0, b1, b2, b3]), - data2: u16::from_ne_bytes([b4, b5]), - data3: u16::from_ne_bytes([b6, b7]), - data4: [b8, b9, ba, bb, bc, bd, be, bf], - } - } - - /// Returns the memory representation of this UUID as a byte array in big-endian byte order. - pub const fn to_bytes(&self) -> [u8; 16] { - let [b0, b1, b2, b3] = self.data1.to_ne_bytes(); - let [b4, b5] = self.data2.to_ne_bytes(); - let [b6, b7] = self.data3.to_ne_bytes(); - let [b8, b9, ba, bb, bc, bd, be, bf] = self.data4; + const fn to_big_endian(self) -> Self { #[cfg(target_endian = "big")] { - [ - b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf, - ] + self } #[cfg(target_endian = "little")] { - [ - b3, b2, b1, b0, b5, b4, b7, b6, b8, b9, ba, bb, bc, bd, be, bf, - ] + Self { + data1: self.data1.swap_bytes(), + data2: self.data2.swap_bytes(), + data3: self.data3.swap_bytes(), + data4: self.data4, + } } } + /// Creates a UUID from its representation as a byte array in big endian. + pub const fn from_bytes(bytes: [u8; 16]) -> Self { + unsafe { mem::transmute::<[u8; 16], Self>(bytes) }.to_big_endian() + } + + /// Returns the memory representation of this UUID as a byte array in big-endian byte order. + pub const fn to_bytes(self) -> [u8; 16] { + unsafe { mem::transmute::(self.to_big_endian()) } + } + /// Creates a UUID from its representation as a 128-bit integer. pub const fn from_u128(data: u128) -> Self { Self::from_bytes(data.to_be_bytes()) From 05dd7135645301ee75f154dbda74f8cda6bec5c3 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 10:53:14 -0800 Subject: [PATCH 09/18] Update crates/cxx-qt-lib/src/core/quuid.rs Co-authored-by: Leon Matthes --- crates/cxx-qt-lib/src/core/quuid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index 52e17305e..d171a5dcc 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -312,7 +312,7 @@ mod test { } #[test] - fn quuid_to_rfc_122() { + fn quuid_to_rfc_4122() { let bytes = <[u8; 16]>::try_from("random test data".as_bytes()).unwrap(); assert_eq!(Vec::from(&QUuid::from_bytes(bytes).to_rfc_122()), bytes) } From 1ecc61d1d57cf3c5cec5981363731545ac0262ae Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 10:59:30 -0800 Subject: [PATCH 10/18] Update crates/cxx-qt-lib/src/core/quuid.rs Co-authored-by: Leon Matthes --- crates/cxx-qt-lib/src/core/quuid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index d171a5dcc..2a7a6b2ed 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -75,7 +75,7 @@ mod ffi { /// Returns the binary representation of this UUID. The byte array is in big endian format, /// and formatted according to RFC 4122, section 4.1.2 - "Layout and byte order". - #[rust_name = "to_rfc_122"] + #[rust_name = "to_rfc_4122"] fn toRfc4122(self: &QUuid) -> QByteArray; } From a6ced3b091e52c81246678a85e266b8ef3a8b7ca Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 10:59:59 -0800 Subject: [PATCH 11/18] cxx-qt-lib: add relocatable check to QUuid --- crates/cxx-qt-lib/src/core/quuid.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/cxx-qt-lib/src/core/quuid.cpp b/crates/cxx-qt-lib/src/core/quuid.cpp index b1a23f501..27650e77b 100644 --- a/crates/cxx-qt-lib/src/core/quuid.cpp +++ b/crates/cxx-qt-lib/src/core/quuid.cpp @@ -18,6 +18,8 @@ assert_alignment_and_size(QUuid, { static_assert(::std::is_trivially_copyable::value, "QUuid must be trivially copyable!"); +static_assert(QTypeInfo::isRelocatable, "QUuid must be relocatable!"); + #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) #define byteView(slice) QByteArrayView(slice.data(), slice.length()) #elif QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) From 64f37d069f4544f72a963b5c11e06a93e7f97aad Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 11:05:30 -0800 Subject: [PATCH 12/18] cxx-qt-lib: rename QUuid methods to match Qt names --- crates/cxx-qt-lib/include/core/quuid.h | 6 ++-- crates/cxx-qt-lib/src/core/quuid.cpp | 6 ++-- crates/cxx-qt-lib/src/core/quuid.rs | 48 +++++++++++++------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/crates/cxx-qt-lib/include/core/quuid.h b/crates/cxx-qt-lib/include/core/quuid.h index fdda93e8f..99ca4a6b0 100644 --- a/crates/cxx-qt-lib/include/core/quuid.h +++ b/crates/cxx-qt-lib/include/core/quuid.h @@ -16,13 +16,13 @@ using QUuidVersion = QUuid::Version; namespace rust { namespace cxxqtlib1 { QUuid -quuidNewV3(const QUuid& ns, ::rust::Slice slice); +quuidCreateUuidV3(const QUuid& ns, ::rust::Slice slice); QUuid -quuidNewV4(); +quuidCreateUuid(); QUuid -quuidNewV5(const QUuid& ns, ::rust::Slice slice); +quuidCreateUuidV5(const QUuid& ns, ::rust::Slice slice); QString quuidToString(const QUuid& uuid); diff --git a/crates/cxx-qt-lib/src/core/quuid.cpp b/crates/cxx-qt-lib/src/core/quuid.cpp index 27650e77b..bc16a08f0 100644 --- a/crates/cxx-qt-lib/src/core/quuid.cpp +++ b/crates/cxx-qt-lib/src/core/quuid.cpp @@ -35,19 +35,19 @@ static_assert(QTypeInfo::isRelocatable, "QUuid must be relocatable!"); namespace rust { namespace cxxqtlib1 { QUuid -quuidNewV3(const QUuid& ns, ::rust::Slice slice) +quuidCreateUuidV3(const QUuid& ns, ::rust::Slice slice) { return QUuid::createUuidV3(ns, byteView(slice)); } QUuid -quuidNewV4() +quuidCreateUuid() { return QUuid::createUuid(); } QUuid -quuidNewV5(const QUuid& ns, ::rust::Slice slice) +quuidCreateUuidV5(const QUuid& ns, ::rust::Slice slice) { return QUuid::createUuidV5(ns, byteView(slice)); } diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index 2a7a6b2ed..6ea2b2e5d 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -82,14 +82,14 @@ mod ffi { #[namespace = "rust::cxxqtlib1"] unsafe extern "C++" { #[doc(hidden)] - #[rust_name = "quuid_new_v3"] - fn quuidNewV3(ns: &QUuid, data: &[u8]) -> QUuid; + #[rust_name = "quuid_create_uuid_v3"] + fn quuidCreateUuidV3(ns: &QUuid, data: &[u8]) -> QUuid; #[doc(hidden)] - #[rust_name = "quuid_new_v4"] - fn quuidNewV4() -> QUuid; + #[rust_name = "quuid_create_uuid"] + fn quuidCreateUuid() -> QUuid; #[doc(hidden)] - #[rust_name = "quuid_new_v5"] - fn quuidNewV5(ns: &QUuid, data: &[u8]) -> QUuid; + #[rust_name = "quuid_create_uuid_v5"] + fn quuidCreateUuidV5(ns: &QUuid, data: &[u8]) -> QUuid; #[doc(hidden)] #[rust_name = "quuid_to_string"] fn quuidToString(uuid: &QUuid) -> QString; @@ -145,22 +145,22 @@ impl QUuid { /// This function returns a new UUID with variant `QUuidVariant::DCE` and version /// `QUuidVersion::Md5`. `namespace` is the namespace and `data` is the basic data as described /// by RFC 4122. - pub fn new_v3(namespace: &Self, data: &[u8]) -> Self { - ffi::quuid_new_v3(namespace, data) + pub fn create_uuid_v3(namespace: &Self, data: &[u8]) -> Self { + ffi::quuid_create_uuid_v3(namespace, data) } /// On any platform other than Windows, this function returns a new UUID with variant /// `QUuidVariant::DCE` and version `QUuidVersion::Random`. On Windows, a GUID is generated using /// the Windows API and will be of the type that the API decides to create. - pub fn new_v4() -> Self { - ffi::quuid_new_v4() + pub fn create_uuid() -> Self { + ffi::quuid_create_uuid() } /// This function returns a new UUID with variant `QUuidVariant::DCE` and version /// `QUuidVersion::Sha1`. `namespace` is the namespace and `data` is the basic data as described /// by RFC 4122. - pub fn new_v5(namespace: &Self, data: &[u8]) -> Self { - ffi::quuid_new_v5(namespace, data) + pub fn create_uuid_v5(namespace: &Self, data: &[u8]) -> Self { + ffi::quuid_create_uuid_v5(namespace, data) } /// Creates a QUuid object from the string text, which must be formatted as five hex fields @@ -282,13 +282,13 @@ mod test { #[test] fn quuid_is_not_null() { - assert!(!QUuid::new_v4().is_null()) + assert!(!QUuid::create_uuid().is_null()) } #[test] fn quuid_variant() { assert_eq!( - [QUuid::null().variant(), QUuid::new_v4().variant()], + [QUuid::null().variant(), QUuid::create_uuid().variant()], [QUuidVariant::VarUnknown, QUuidVariant::DCE] ); } @@ -298,9 +298,9 @@ mod test { assert_eq!( [ QUuid::null().version(), - QUuid::new_v3(NAMESPACE_DNS, &[]).version(), - QUuid::new_v4().version(), - QUuid::new_v5(NAMESPACE_DNS, &[]).version(), + QUuid::create_uuid_v3(NAMESPACE_DNS, &[]).version(), + QUuid::create_uuid().version(), + QUuid::create_uuid_v5(NAMESPACE_DNS, &[]).version(), ], [ QUuidVersion::VerUnknown, @@ -325,20 +325,20 @@ mod test { #[test] fn quuid_new_v3() { assert_eq!( - QUuid::new_v3(NAMESPACE_DNS, "testdata".as_bytes()), + QUuid::create_uuid_v3(NAMESPACE_DNS, "testdata".as_bytes()), QUuid::from_u128(0x5157facac7e1345c927671c2c6d41e7a) ); } #[test] fn quuid_new_v4() { - assert_ne!(QUuid::new_v4(), QUuid::new_v4()); + assert_ne!(QUuid::create_uuid(), QUuid::create_uuid()); } #[test] fn quuid_new_v5() { assert_eq!( - QUuid::new_v5(NAMESPACE_DNS, "testdata".as_bytes()), + QUuid::create_uuid_v5(NAMESPACE_DNS, "testdata".as_bytes()), QUuid::from_u128(0x7e95e361a22c51c18c297ac24cb61e83) ); } @@ -353,14 +353,14 @@ mod test { #[test] fn quuid_string_round_trip() { - let uuid = QUuid::new_v4(); + let uuid = QUuid::create_uuid(); let roundtrip = QUuid::from_string(&QString::from(&uuid.to_string())); assert_eq!(uuid, roundtrip) } #[test] fn quuid_fields_round_trip() { - let uuid = QUuid::new_v4(); + let uuid = QUuid::create_uuid(); let (d1, d2, d3, &d4) = uuid.as_fields(); let roundtrip = QUuid::from_fields(d1, d2, d3, d4); assert_eq!(uuid, roundtrip) @@ -368,14 +368,14 @@ mod test { #[test] fn quuid_bytes_round_trip() { - let uuid = QUuid::new_v4(); + let uuid = QUuid::create_uuid(); let roundtrip = QUuid::from_bytes(uuid.to_bytes()); assert_eq!(uuid, roundtrip) } #[test] fn quuid_u128_round_trip() { - let uuid = QUuid::new_v4(); + let uuid = QUuid::create_uuid(); let roundtrip = QUuid::from_u128(uuid.to_u128()); assert_eq!(uuid, roundtrip) } From 4f8e28b3b6b200ed4554b424fc542661a759b14c Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 11:07:19 -0800 Subject: [PATCH 13/18] cxx-qt-lib: fix test type error --- crates/cxx-qt-lib/src/core/quuid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index 6ea2b2e5d..f32fb6e31 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -314,7 +314,7 @@ mod test { #[test] fn quuid_to_rfc_4122() { let bytes = <[u8; 16]>::try_from("random test data".as_bytes()).unwrap(); - assert_eq!(Vec::from(&QUuid::from_bytes(bytes).to_rfc_122()), bytes) + assert_eq!(Vec::from(&QUuid::from_bytes(bytes).to_rfc_4122()), bytes) } #[test] From d8580347d6fc4b885168dab90630edf999ece8a0 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 11:28:24 -0800 Subject: [PATCH 14/18] cxx-qt-lib: add documentation for QUuid::to_be --- crates/cxx-qt-lib/src/core/quuid.rs | 68 +++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index f32fb6e31..1f4265407 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -189,30 +189,18 @@ impl QUuid { (self.data1, self.data2, self.data3, &self.data4) } - const fn to_big_endian(self) -> Self { - #[cfg(target_endian = "big")] - { - self - } - #[cfg(target_endian = "little")] - { - Self { - data1: self.data1.swap_bytes(), - data2: self.data2.swap_bytes(), - data3: self.data3.swap_bytes(), - data4: self.data4, - } - } - } - /// Creates a UUID from its representation as a byte array in big endian. pub const fn from_bytes(bytes: [u8; 16]) -> Self { - unsafe { mem::transmute::<[u8; 16], Self>(bytes) }.to_big_endian() + // On big endian targets, this is a no-op. + // On little endian targets, it swaps the bytes of each integer field (data1, data2, data3). + unsafe { mem::transmute::<[u8; 16], Self>(bytes) }.to_be() } /// Returns the memory representation of this UUID as a byte array in big-endian byte order. pub const fn to_bytes(self) -> [u8; 16] { - unsafe { mem::transmute::(self.to_big_endian()) } + // On big endian targets, this is a no-op. + // On little endian targets, it swaps the bytes of each integer field (data1, data2, data3). + unsafe { mem::transmute::(self.to_be()) } } /// Creates a UUID from its representation as a 128-bit integer. @@ -224,6 +212,50 @@ impl QUuid { pub const fn to_u128(&self) -> u128 { u128::from_be_bytes(self.to_bytes()) } + + /// Converts self to big endian from the target’s endianness. + // This function is analogous to [`u8::to_be`](https://doc.rust-lang.org/src/core/num/uint_macros.rs.html#399-431). + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// This is useful for converting between QUuids and byte arrays because byte array + /// representations of UUIDs are always in big endian mode. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let d1 = 0x1A; + /// let d2 = 0x1B; + /// let d3 = 0x1C; + /// let d4 = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + /// let uuid = QUuid::from_fields(d1, d2, d3, d4); + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(uuid.to_be(), uuid) + /// } else { + /// assert_eq!( + /// uuid.to_be(), + /// QUuid::from_fields(d1.swap_bytes(), d2.swap_bytes(), d3.swap_bytes(), d4) + /// ); + /// } + /// ``` + const fn to_be(self) -> Self { + #[cfg(target_endian = "big")] + { + self + } + #[cfg(target_endian = "little")] + { + Self { + data1: self.data1.swap_bytes(), + data2: self.data2.swap_bytes(), + data3: self.data3.swap_bytes(), + data4: self.data4, + } + } + } } unsafe impl ExternType for QUuid { From 05d5d0c78aed08b132ea5dcd4e2d9ae9868ecff7 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 12:46:27 -0800 Subject: [PATCH 15/18] cxx-qt-lib: make QUuid::is_null a const fn --- crates/cxx-qt-lib/src/core/quuid.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index 1f4265407..40ac630f3 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -59,11 +59,6 @@ mod ffi { type QUuidVariant; type QUuidVersion; - /// Returns true if this is the null UUID `{00000000-0000-0000-0000-000000000000}`. - /// otherwise returns false. - #[rust_name = "is_null"] - fn isNull(self: &QUuid) -> bool; - /// Returns the value in the variant field of the UUID. If the return value is /// `QUuidVariant::DCE`, call `version()` to see which layout it uses. The null UUID is /// considered to be of an unknown variant. @@ -142,6 +137,12 @@ impl QUuid { } } + /// Returns `true` if this is the null UUID {00000000-0000-0000-0000-000000000000}; + /// otherwise returns `false`. + pub const fn is_null(&self) -> bool { + (unsafe { std::mem::transmute::(*self) }) == 0 + } + /// This function returns a new UUID with variant `QUuidVariant::DCE` and version /// `QUuidVersion::Md5`. `namespace` is the namespace and `data` is the basic data as described /// by RFC 4122. From 80e27946cacbf6310bc669c8da61373cc2070645 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 12:53:41 -0800 Subject: [PATCH 16/18] cxx-qt-lib: remove example source from QUuid::to_be --- crates/cxx-qt-lib/src/core/quuid.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index 40ac630f3..127e54b85 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -221,27 +221,7 @@ impl QUuid { /// /// This is useful for converting between QUuids and byte arrays because byte array /// representations of UUIDs are always in big endian mode. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let d1 = 0x1A; - /// let d2 = 0x1B; - /// let d3 = 0x1C; - /// let d4 = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; - /// let uuid = QUuid::from_fields(d1, d2, d3, d4); - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(uuid.to_be(), uuid) - /// } else { - /// assert_eq!( - /// uuid.to_be(), - /// QUuid::from_fields(d1.swap_bytes(), d2.swap_bytes(), d3.swap_bytes(), d4) - /// ); - /// } - /// ``` + #[must_use = "this returns the result of the operation, without modifying the original"] const fn to_be(self) -> Self { #[cfg(target_endian = "big")] { From dd3a69fc6110937d994f26be7324d6839e48992d Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 12:54:29 -0800 Subject: [PATCH 17/18] cxx-qt-lib: replace QUuid::from(QAnyStringView) with separate types --- crates/cxx-qt-lib/include/core/quuid.h | 9 ++- crates/cxx-qt-lib/src/core/quuid.cpp | 17 +++- crates/cxx-qt-lib/src/core/quuid.rs | 107 +++++++++++++++++++++---- 3 files changed, 115 insertions(+), 18 deletions(-) diff --git a/crates/cxx-qt-lib/include/core/quuid.h b/crates/cxx-qt-lib/include/core/quuid.h index 99ca4a6b0..c4ff8b724 100644 --- a/crates/cxx-qt-lib/include/core/quuid.h +++ b/crates/cxx-qt-lib/include/core/quuid.h @@ -28,6 +28,13 @@ QString quuidToString(const QUuid& uuid); QUuid -quuidFromString(QAnyStringView string); +quuidFromString(const QString& string); + +QUuid +quuidFromStr(rust::Str string); + +QUuid +quuidFromRfc4122(const QByteArray& bytes); + } } diff --git a/crates/cxx-qt-lib/src/core/quuid.cpp b/crates/cxx-qt-lib/src/core/quuid.cpp index bc16a08f0..e96d5ed17 100644 --- a/crates/cxx-qt-lib/src/core/quuid.cpp +++ b/crates/cxx-qt-lib/src/core/quuid.cpp @@ -59,14 +59,25 @@ quuidToString(const QUuid& uuid) } QUuid -quuidFromString(QAnyStringView string) +quuidFromString(const QString& string) +{ + return QUuid::fromString(string); +} + +QUuid +quuidFromStr(rust::Str string) { #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) - return QUuid::fromString(string); // we can use UTF8 strings directly + return QUuid::fromString(QAnyStringView(string.data(), string.length())); #else - return QUuid::fromString(QString(string)); + return QUuid::fromString(QString::fromLatin1(string.data(), string.length())); #endif } +QUuid +quuidFromRfc4122(const QByteArray& bytes) +{ + return QUuid::fromRfc4122(bytes); +} } } diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index 127e54b85..a25487715 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -2,7 +2,7 @@ // SPDX-FileContributor: Joshua Booth // // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::QString; +use crate::{QByteArray, QString}; use cxx::{type_id, ExternType}; use std::{fmt, mem}; #[cfg(feature = "uuid")] @@ -50,7 +50,6 @@ mod ffi { unsafe extern "C++" { include!("cxx-qt-lib/qstring.h"); type QString = crate::QString; - type QAnyStringView<'a> = crate::QAnyStringView<'a>; } unsafe extern "C++" { @@ -90,7 +89,13 @@ mod ffi { fn quuidToString(uuid: &QUuid) -> QString; #[doc(hidden)] #[rust_name = "quuid_from_string"] - fn quuidFromString(string: QAnyStringView) -> QUuid; + fn quuidFromString(string: &QString) -> QUuid; + #[doc(hidden)] + #[rust_name = "quuid_from_str"] + fn quuidFromStr(string: &str) -> QUuid; + #[doc(hidden)] + #[rust_name = "quuid_from_rfc_4122"] + fn quuidFromRfc4122(bytes: &QByteArray) -> QUuid; } } @@ -164,16 +169,15 @@ impl QUuid { ffi::quuid_create_uuid_v5(namespace, data) } - /// Creates a QUuid object from the string text, which must be formatted as five hex fields - /// separated by '-', e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex - /// digit. The curly braces shown here are optional, but it is normal to include them. + /// Creates a `QUuid` object from the binary representation of the UUID. + /// The byte array is in big endian format, and formatted according to RFC 4122, section 4.1.2 - + /// "Layout and byte order". /// - /// If the conversion fails, a null UUID is returned. - pub fn from_string<'a, S>(s: S) -> Self - where - S: Into>, - { - ffi::quuid_from_string(s.into()) + /// The byte array accepted is NOT a human readable format. + /// + /// If the conversion fails, a null UUID is created. + pub fn from_rfc_4122(bytes: &QByteArray) -> Self { + ffi::quuid_from_rfc_4122(bytes) } /// Creates a UUID with the value specified by the parameters. @@ -262,6 +266,67 @@ impl From for u128 { } } +impl From<[u8; 16]> for QUuid { + /// See [`QUuid::from_bytes`]. + fn from(value: [u8; 16]) -> Self { + Self::from_bytes(value) + } +} + +impl From for [u8; 16] { + /// See [`QUuid::to_bytes`]. + fn from(value: QUuid) -> Self { + value.to_bytes() + } +} + +impl From<&QString> for QUuid { + /// Creates a QUuid object from the string text, which must be formatted as five hex fields + /// separated by '-', e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex + /// digit. The curly braces shown here are optional, but it is normal to include them. + /// + /// If the conversion fails, a null UUID is returned. + fn from(value: &QString) -> Self { + ffi::quuid_from_string(value) + } +} + +impl From<&str> for QUuid { + /// Creates a QUuid object from the string text, which must be formatted as five hex fields + /// separated by '-', e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex + /// digit. The curly braces shown here are optional, but it is normal to include them. + /// + /// If the conversion fails, a null UUID is returned. + fn from(value: &str) -> Self { + ffi::quuid_from_str(value) + } +} + +impl From<&String> for QUuid { + /// Creates a QUuid object from the string text, which must be formatted as five hex fields + /// separated by '-', e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex + /// digit. The curly braces shown here are optional, but it is normal to include them. + /// + /// If the conversion fails, a null UUID is returned. + fn from(value: &String) -> Self { + ffi::quuid_from_str(value) + } +} + +impl From<&QByteArray> for QUuid { + /// See [`QUuid::from_rfc_4122`]. + fn from(value: &QByteArray) -> Self { + ffi::quuid_from_rfc_4122(value) + } +} + +impl From for QByteArray { + /// See [`QUuid::to_rfc_4122`]. + fn from(value: QUuid) -> Self { + value.to_rfc_4122() + } +} + #[cfg(feature = "uuid")] impl From for QUuid { fn from(value: Uuid) -> Self { @@ -365,9 +430,16 @@ mod test { } #[test] - fn quuid_string_round_trip() { + fn quuid_qstring_round_trip() { let uuid = QUuid::create_uuid(); - let roundtrip = QUuid::from_string(&QString::from(&uuid.to_string())); + let roundtrip = QUuid::from(&QString::from(&uuid.to_string())); + assert_eq!(uuid, roundtrip) + } + + #[test] + fn quuid_str_round_trip() { + let uuid = QUuid::create_uuid(); + let roundtrip = QUuid::from(&uuid.to_string()); assert_eq!(uuid, roundtrip) } @@ -386,6 +458,13 @@ mod test { assert_eq!(uuid, roundtrip) } + #[test] + fn quuid_qbytearray_round_trip() { + let uuid = QUuid::create_uuid(); + let roundtrip = QUuid::from_rfc_4122(&uuid.to_rfc_4122()); + assert_eq!(uuid, roundtrip) + } + #[test] fn quuid_u128_round_trip() { let uuid = QUuid::create_uuid(); From 9971b2d382d59fc444d6525a01c92913cd632b43 Mon Sep 17 00:00:00 2001 From: Joshua Booth Date: Fri, 10 Jan 2025 23:37:34 -0800 Subject: [PATCH 18/18] cxx-qt-lib: remove [u8; 16] From conversions for QUuid --- crates/cxx-qt-lib/src/core/quuid.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/crates/cxx-qt-lib/src/core/quuid.rs b/crates/cxx-qt-lib/src/core/quuid.rs index a25487715..aa4168b8d 100644 --- a/crates/cxx-qt-lib/src/core/quuid.rs +++ b/crates/cxx-qt-lib/src/core/quuid.rs @@ -266,20 +266,6 @@ impl From for u128 { } } -impl From<[u8; 16]> for QUuid { - /// See [`QUuid::from_bytes`]. - fn from(value: [u8; 16]) -> Self { - Self::from_bytes(value) - } -} - -impl From for [u8; 16] { - /// See [`QUuid::to_bytes`]. - fn from(value: QUuid) -> Self { - value.to_bytes() - } -} - impl From<&QString> for QUuid { /// Creates a QUuid object from the string text, which must be formatted as five hex fields /// separated by '-', e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex