From 1ae2ab39012b5a19b073d8fc43dcc2531791d2db Mon Sep 17 00:00:00 2001 From: Ben Ford Date: Tue, 8 Apr 2025 18:31:35 +0100 Subject: [PATCH 1/2] Add Transitive casting and testing code --- .../cxx-qt-gen/src/generator/rust/fragment.rs | 26 +++++++++++------ crates/cxx-qt-gen/test_outputs/cfgs.rs | 8 +++--- crates/cxx-qt-gen/test_outputs/inheritance.rs | 6 ++-- crates/cxx-qt-gen/test_outputs/invokables.rs | 2 +- .../test_outputs/passthrough_and_naming.rs | 10 +++---- crates/cxx-qt-gen/test_outputs/properties.rs | 2 +- crates/cxx-qt-gen/test_outputs/qenum.rs | 4 +-- crates/cxx-qt-gen/test_outputs/signals.rs | 4 +-- crates/cxx-qt-lib/src/core/qstringlist.rs | 2 +- crates/cxx-qt/src/lib.rs | 28 ++++++++++++++++++- examples/qml_minimal/qml/main.qml | 11 ++++++++ 11 files changed, 74 insertions(+), 29 deletions(-) diff --git a/crates/cxx-qt-gen/src/generator/rust/fragment.rs b/crates/cxx-qt-gen/src/generator/rust/fragment.rs index 3a440fd82..0a7bf8612 100644 --- a/crates/cxx-qt-gen/src/generator/rust/fragment.rs +++ b/crates/cxx-qt-gen/src/generator/rust/fragment.rs @@ -77,17 +77,25 @@ impl GeneratedRustFragment { unsafe fn #downcast_fn(base: *const #base_unqualified) -> *const #struct_name_unqualified; } }], - cxx_qt_mod_contents: vec![parse_quote! { - impl ::cxx_qt::Upcast<#base_qualified> for #struct_name { - unsafe fn upcast_ptr(this: *const Self) -> *const #base_qualified { - #upcast_fn_qualified(this) - } + cxx_qt_mod_contents: vec![ + parse_quote! { + unsafe impl ::cxx_qt::Upcast<#base_qualified> for #struct_name { + unsafe fn upcast_ptr(this: *const Self) -> *const #base_qualified { + #upcast_fn_qualified(this) + } - unsafe fn from_base_ptr(base: *const #base_qualified) -> *const Self { - #downcast_fn_qualified(base) + unsafe fn from_base_ptr(base: *const #base_qualified) -> *const Self { + #downcast_fn_qualified(base) + } } - } - }], + }, + // Add back once we figure out the bug with QObject, for automatic transitive casts + // parse_quote! { + // unsafe impl ::cxx_qt::MainCast for #struct_name { + // type Base = #base_qualified; + // } + // } + ], }) } diff --git a/crates/cxx-qt-gen/test_outputs/cfgs.rs b/crates/cxx-qt-gen/test_outputs/cfgs.rs index af2f2f565..ac3d9cc41 100644 --- a/crates/cxx-qt-gen/test_outputs/cfgs.rs +++ b/crates/cxx-qt-gen/test_outputs/cfgs.rs @@ -668,7 +668,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectEnabled { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectEnabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectEnabled_upcastPtr(this) } @@ -847,7 +847,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectDisabled { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectDisabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectDisabled_upcastPtr(this) } @@ -878,7 +878,7 @@ impl ::cxx_qt::CxxQtType for ffi::QObjectDisabled { ffi::cxx_qt_ffi_QObjectDisabled_unsafeRustMut(self) } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectExternEnabled { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectExternEnabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectExternEnabled_upcastPtr(this) } @@ -1048,7 +1048,7 @@ cxx_qt::static_assertions::assert_eq_size!( >, [usize; 2] ); -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectExternDisabled { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectExternDisabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectExternDisabled_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.rs b/crates/cxx-qt-gen/test_outputs/inheritance.rs index 3baf93952..0ccbd5437 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_outputs/inheritance.rs @@ -130,7 +130,7 @@ mod inheritance { type QObject = cxx_qt::QObject; } } -impl ::cxx_qt::Upcast for inheritance::MyObject { +unsafe impl ::cxx_qt::Upcast for inheritance::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QAbstractItemModel { inheritance::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -158,7 +158,7 @@ impl ::cxx_qt::CxxQtType for inheritance::MyObject { inheritance::cxx_qt_ffi_MyObject_unsafeRustMut(self) } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for inheritance::QPushButton { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for inheritance::QPushButton { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { inheritance::cxx_qt_ffi_QPushButton_upcastPtr(this) } @@ -166,7 +166,7 @@ impl ::cxx_qt::Upcast<::cxx_qt::QObject> for inheritance::QPushButton { inheritance::cxx_qt_ffi_QPushButton_downcastPtr(base) } } -impl ::cxx_qt::Upcast for inheritance::QPushButtonChild { +unsafe impl ::cxx_qt::Upcast for inheritance::QPushButtonChild { unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QPushButton { inheritance::cxx_qt_ffi_QPushButtonChild_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/invokables.rs b/crates/cxx-qt-gen/test_outputs/invokables.rs index 9ee861444..74ad36c04 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -326,7 +326,7 @@ impl cxx_qt::Threading for ffi::MyObject { pub struct MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + Send>, } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs index 40fe6462d..443f087d4 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs @@ -648,7 +648,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -impl ::cxx_qt::Upcast for ffi::MyObject { +unsafe impl ::cxx_qt::Upcast for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ffi::QStringListModel { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -822,7 +822,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::SecondObject { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::SecondObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_SecondObject_upcastPtr(this) } @@ -850,7 +850,7 @@ impl ::cxx_qt::CxxQtType for ffi::SecondObject { ffi::cxx_qt_ffi_SecondObject_unsafeRustMut(self) } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyRustName { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyRustName { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyCxxName_upcastPtr(this) } @@ -878,7 +878,7 @@ impl ::cxx_qt::CxxQtType for ffi::MyRustName { ffi::cxx_qt_ffi_MyCxxName_unsafeRustMut(self) } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QPushButton { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QPushButton { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QPushButton_upcastPtr(this) } @@ -886,7 +886,7 @@ impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QPushButton { ffi::cxx_qt_ffi_QPushButton_downcastPtr(base) } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::ExternObject { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::ExternObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_ExternObjectCpp_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index 440e13c7a..a6cabf33b 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -1052,7 +1052,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/qenum.rs b/crates/cxx-qt-gen/test_outputs/qenum.rs index f054521d1..09c7c6641 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.rs +++ b/crates/cxx-qt-gen/test_outputs/qenum.rs @@ -169,7 +169,7 @@ mod ffi { type QObject = cxx_qt::QObject; } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -197,7 +197,7 @@ impl ::cxx_qt::CxxQtType for ffi::MyObject { ffi::cxx_qt_ffi_MyObject_unsafeRustMut(self) } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyRenamedObject { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyRenamedObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_CxxName_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index ba6f41b6e..7a8384fde 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -455,7 +455,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -483,7 +483,7 @@ impl ::cxx_qt::CxxQtType for ffi::MyObject { ffi::cxx_qt_ffi_MyObject_unsafeRustMut(self) } } -impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QTimer { +unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QTimer { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QTimer_upcastPtr(this) } diff --git a/crates/cxx-qt-lib/src/core/qstringlist.rs b/crates/cxx-qt-lib/src/core/qstringlist.rs index fbb6eb806..95f0a2938 100644 --- a/crates/cxx-qt-lib/src/core/qstringlist.rs +++ b/crates/cxx-qt-lib/src/core/qstringlist.rs @@ -207,7 +207,7 @@ impl DerefMut for QStringList { } } -impl Upcast for QStringList { +unsafe impl Upcast for QStringList { unsafe fn upcast_ptr(this: *const Self) -> *const QList_QString { ffi::upcast_qstringlist(this) } diff --git a/crates/cxx-qt/src/lib.rs b/crates/cxx-qt/src/lib.rs index ea6f18ae9..e06564f79 100644 --- a/crates/cxx-qt/src/lib.rs +++ b/crates/cxx-qt/src/lib.rs @@ -219,7 +219,7 @@ pub trait Threading: Sized { /// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it. /// Allows upcasting to either [QObject] or the provided base class of a type. /// Will not be implemented if no types inherit from [QObject] or have the `#[base = T]` attribute. -pub trait Upcast { +pub unsafe trait Upcast { #[doc(hidden)] /// # Safety /// @@ -267,6 +267,32 @@ pub trait Upcast { } } +/// Docs +pub unsafe trait MainCast: Upcast { + /// The first parent of the Type + type Base; +} + +unsafe impl Upcast for T +where + T: MainCast, + A: MainCast, +{ + unsafe fn upcast_ptr(this: *const Self) -> *const B { + let base = Self::upcast_ptr(this); + A::upcast_ptr(base) + } + + unsafe fn from_base_ptr(base: *const B) -> *const Self { + let base = A::from_base_ptr(base); + if base.is_null() { + std::ptr::null() + } else { + Self::from_base_ptr(base) + } + } +} + /// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it. /// Trait for downcasting to a subclass, provided the subclass implements [Upcast] to this type. /// Returns `None` in cases where `Sub` isn't a child class of `Self`. diff --git a/examples/qml_minimal/qml/main.qml b/examples/qml_minimal/qml/main.qml index 0b32505e4..5b7c3b6ec 100644 --- a/examples/qml_minimal/qml/main.qml +++ b/examples/qml_minimal/qml/main.qml @@ -28,6 +28,11 @@ ApplicationWindow { string: qsTr("My String with my number: %1").arg(myObject.number) } + A { + id: a + number: 10 + } + Column { anchors.fill: parent anchors.margins: 10 @@ -55,6 +60,12 @@ ApplicationWindow { onClicked: myObject.sayHi(myObject.string, myObject.number) } + Button { + text: qsTr("Test A") + + onClicked: a.test() + } + Button { text: qsTr("Quit") From 7baae3e5f4afc005180aacdd721400f8c9e7645c Mon Sep 17 00:00:00 2001 From: Ben Ford Date: Tue, 8 Apr 2025 18:31:35 +0100 Subject: [PATCH 2/2] Add Transitive casting and testing code --- .../cxx-qt-gen/src/generator/rust/fragment.rs | 26 +- crates/cxx-qt-gen/test_outputs/cfgs.rs | 8 +- crates/cxx-qt-gen/test_outputs/inheritance.rs | 6 +- crates/cxx-qt-gen/test_outputs/invokables.rs | 2 +- .../test_outputs/passthrough_and_naming.rs | 10 +- crates/cxx-qt-gen/test_outputs/properties.rs | 2 +- crates/cxx-qt-gen/test_outputs/qenum.rs | 4 +- crates/cxx-qt-gen/test_outputs/signals.rs | 4 +- crates/cxx-qt-lib/src/core/qstringlist.rs | 2 +- crates/cxx-qt/src/casting.rs | 314 ++++++++++++++++++ crates/cxx-qt/src/lib.rs | 126 +------ examples/cargo_without_cmake/src/main.rs | 2 +- .../rust/src/custom_base_class.rs | 16 +- examples/qml_minimal/qml/main.qml | 11 - .../qml_multi_crates/rust/main/src/main.rs | 2 +- 15 files changed, 359 insertions(+), 176 deletions(-) create mode 100644 crates/cxx-qt/src/casting.rs diff --git a/crates/cxx-qt-gen/src/generator/rust/fragment.rs b/crates/cxx-qt-gen/src/generator/rust/fragment.rs index 0a7bf8612..03624d57c 100644 --- a/crates/cxx-qt-gen/src/generator/rust/fragment.rs +++ b/crates/cxx-qt-gen/src/generator/rust/fragment.rs @@ -77,25 +77,17 @@ impl GeneratedRustFragment { unsafe fn #downcast_fn(base: *const #base_unqualified) -> *const #struct_name_unqualified; } }], - cxx_qt_mod_contents: vec![ - parse_quote! { - unsafe impl ::cxx_qt::Upcast<#base_qualified> for #struct_name { - unsafe fn upcast_ptr(this: *const Self) -> *const #base_qualified { - #upcast_fn_qualified(this) - } + cxx_qt_mod_contents: vec![parse_quote! { + unsafe impl ::cxx_qt::casting::Upcast<#base_qualified> for #struct_name { + unsafe fn upcast_ptr(this: *const Self) -> *const #base_qualified { + #upcast_fn_qualified(this) + } - unsafe fn from_base_ptr(base: *const #base_qualified) -> *const Self { - #downcast_fn_qualified(base) - } + unsafe fn from_base_ptr(base: *const #base_qualified) -> *const Self { + #downcast_fn_qualified(base) } - }, - // Add back once we figure out the bug with QObject, for automatic transitive casts - // parse_quote! { - // unsafe impl ::cxx_qt::MainCast for #struct_name { - // type Base = #base_qualified; - // } - // } - ], + } + }], }) } diff --git a/crates/cxx-qt-gen/test_outputs/cfgs.rs b/crates/cxx-qt-gen/test_outputs/cfgs.rs index ac3d9cc41..79e42650a 100644 --- a/crates/cxx-qt-gen/test_outputs/cfgs.rs +++ b/crates/cxx-qt-gen/test_outputs/cfgs.rs @@ -668,7 +668,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectEnabled { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::QObjectEnabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectEnabled_upcastPtr(this) } @@ -847,7 +847,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectDisabled { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::QObjectDisabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectDisabled_upcastPtr(this) } @@ -878,7 +878,7 @@ impl ::cxx_qt::CxxQtType for ffi::QObjectDisabled { ffi::cxx_qt_ffi_QObjectDisabled_unsafeRustMut(self) } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectExternEnabled { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::QObjectExternEnabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectExternEnabled_upcastPtr(this) } @@ -1048,7 +1048,7 @@ cxx_qt::static_assertions::assert_eq_size!( >, [usize; 2] ); -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QObjectExternDisabled { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::QObjectExternDisabled { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QObjectExternDisabled_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.rs b/crates/cxx-qt-gen/test_outputs/inheritance.rs index 0ccbd5437..a44c252d0 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_outputs/inheritance.rs @@ -130,7 +130,7 @@ mod inheritance { type QObject = cxx_qt::QObject; } } -unsafe impl ::cxx_qt::Upcast for inheritance::MyObject { +unsafe impl ::cxx_qt::casting::Upcast for inheritance::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QAbstractItemModel { inheritance::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -158,7 +158,7 @@ impl ::cxx_qt::CxxQtType for inheritance::MyObject { inheritance::cxx_qt_ffi_MyObject_unsafeRustMut(self) } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for inheritance::QPushButton { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for inheritance::QPushButton { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { inheritance::cxx_qt_ffi_QPushButton_upcastPtr(this) } @@ -166,7 +166,7 @@ unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for inheritance::QPushButton { inheritance::cxx_qt_ffi_QPushButton_downcastPtr(base) } } -unsafe impl ::cxx_qt::Upcast for inheritance::QPushButtonChild { +unsafe impl ::cxx_qt::casting::Upcast for inheritance::QPushButtonChild { unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QPushButton { inheritance::cxx_qt_ffi_QPushButtonChild_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/invokables.rs b/crates/cxx-qt-gen/test_outputs/invokables.rs index 74ad36c04..4d01c4102 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -326,7 +326,7 @@ impl cxx_qt::Threading for ffi::MyObject { pub struct MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + Send>, } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs index 443f087d4..23278ffec 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs @@ -648,7 +648,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -unsafe impl ::cxx_qt::Upcast for ffi::MyObject { +unsafe impl ::cxx_qt::casting::Upcast for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ffi::QStringListModel { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -822,7 +822,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::SecondObject { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::SecondObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_SecondObject_upcastPtr(this) } @@ -850,7 +850,7 @@ impl ::cxx_qt::CxxQtType for ffi::SecondObject { ffi::cxx_qt_ffi_SecondObject_unsafeRustMut(self) } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyRustName { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::MyRustName { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyCxxName_upcastPtr(this) } @@ -878,7 +878,7 @@ impl ::cxx_qt::CxxQtType for ffi::MyRustName { ffi::cxx_qt_ffi_MyCxxName_unsafeRustMut(self) } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QPushButton { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::QPushButton { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QPushButton_upcastPtr(this) } @@ -886,7 +886,7 @@ unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QPushButton { ffi::cxx_qt_ffi_QPushButton_downcastPtr(base) } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::ExternObject { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::ExternObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_ExternObjectCpp_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index a6cabf33b..3588093d9 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -1052,7 +1052,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/qenum.rs b/crates/cxx-qt-gen/test_outputs/qenum.rs index 09c7c6641..e18480148 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.rs +++ b/crates/cxx-qt-gen/test_outputs/qenum.rs @@ -169,7 +169,7 @@ mod ffi { type QObject = cxx_qt::QObject; } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -197,7 +197,7 @@ impl ::cxx_qt::CxxQtType for ffi::MyObject { ffi::cxx_qt_ffi_MyObject_unsafeRustMut(self) } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyRenamedObject { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::MyRenamedObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_CxxName_upcastPtr(this) } diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index 7a8384fde..1544ebec7 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -455,7 +455,7 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::MyObject { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } @@ -483,7 +483,7 @@ impl ::cxx_qt::CxxQtType for ffi::MyObject { ffi::cxx_qt_ffi_MyObject_unsafeRustMut(self) } } -unsafe impl ::cxx_qt::Upcast<::cxx_qt::QObject> for ffi::QTimer { +unsafe impl ::cxx_qt::casting::Upcast<::cxx_qt::QObject> for ffi::QTimer { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::QObject { ffi::cxx_qt_ffi_QTimer_upcastPtr(this) } diff --git a/crates/cxx-qt-lib/src/core/qstringlist.rs b/crates/cxx-qt-lib/src/core/qstringlist.rs index 95f0a2938..a00553896 100644 --- a/crates/cxx-qt-lib/src/core/qstringlist.rs +++ b/crates/cxx-qt-lib/src/core/qstringlist.rs @@ -6,7 +6,7 @@ use crate::core::qstringlist::ffi::QList_QString; use crate::{QList, QString}; use core::mem::MaybeUninit; use cxx::{type_id, ExternType}; -use cxx_qt::Upcast; +use cxx_qt::casting::Upcast; use std::fmt; use std::ops::{Deref, DerefMut}; diff --git a/crates/cxx-qt/src/casting.rs b/crates/cxx-qt/src/casting.rs new file mode 100644 index 000000000..76b496629 --- /dev/null +++ b/crates/cxx-qt/src/casting.rs @@ -0,0 +1,314 @@ +// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Ben Ford +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use std::ops::Deref; +use std::pin::Pin; + +/// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it. +/// Allows upcasting to either [crate::QObject] or the provided base class of a type. +/// Will not be implemented if no types inherit from [crate::QObject] or have the `#[base = T]` attribute. +/// +/// # Safety +/// +/// By implementing Upcast for your type, you take responsibility that the type you are upcasting to is actually a parent. +pub unsafe trait Upcast { + #[doc(hidden)] + /// # Safety + /// + /// Internal function, Should probably not be implemented manually unless you're absolutely sure you need it. + /// Automatically available for types in RustQt blocks in [cxx_qt::bridge](bridge)s. + /// Upcasts a pointer to `Self` to a pointer to the base class `T`. + /// > Note: Internal implementation uses `static_cast`. + unsafe fn upcast_ptr(this: *const Self) -> *const T; + + #[doc(hidden)] + /// # Safety + /// + /// Internal function, Should probably not be implemented manually unless you're absolutely sure you need it. + /// Automatically available for types in RustQt blocks in [cxx_qt::bridge](bridge)s. + /// Downcasts a pointer to base class `T` to a pointer to `Self`. + /// Return a null pointer if `Self` is not actually a child of base. + /// > Note: Internal implementation uses `dynamic_cast`. + unsafe fn from_base_ptr(base: *const T) -> *const Self; + + /// Upcast a reference to self to a reference to the base class + fn upcast(&self) -> &T { + let ptr = self as *const Self; + unsafe { + let base = Self::upcast_ptr(ptr); + &*base + } + } + + /// Upcast a mutable reference to sell to a mutable reference to the base class + fn upcast_mut(&mut self) -> &mut T { + let ptr = self as *const Self; + unsafe { + let base = Self::upcast_ptr(ptr) as *mut T; + &mut *base + } + } + + /// Upcast a pinned mutable reference to self to a pinned mutable reference to the base class + fn upcast_pin(self: Pin<&mut Self>) -> Pin<&mut T> { + let this = self.deref() as *const Self; + unsafe { + let base = Self::upcast_ptr(this) as *mut T; + Pin::new_unchecked(&mut *base) + } + } +} + +/// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it. +/// Trait for downcasting to a subclass, provided the subclass implements [Upcast] to this type. +/// Returns `None` in cases where `Sub` isn't a child class of `Self`. +pub trait Downcast: Sized { + /// Try to downcast to a subclass of this type, given that the subclass upcasts to this type + fn downcast>(&self) -> Option<&Sub> { + unsafe { + let ptr = Sub::from_base_ptr(self as *const Self); + if ptr.is_null() { + None + } else { + Some(&*ptr) + } + } + } + + /// Try to downcast mutably to a subclass of this, given that the subclass upcasts to this type + fn downcast_mut>(&mut self) -> Option<&mut Sub> { + unsafe { + let ptr = Sub::from_base_ptr(self as *const Self) as *mut Sub; + if ptr.is_null() { + None + } else { + Some(&mut *ptr) + } + } + } + + /// Try to downcast a pin to a pinned subclass of this, given that the subclass upcasts to this type + fn downcast_pin>(self: Pin<&mut Self>) -> Option> { + let this = self.deref() as *const Self; + unsafe { + let ptr = Sub::from_base_ptr(this) as *mut Sub; + if ptr.is_null() { + None + } else { + Some(Pin::new_unchecked(&mut *ptr)) + } + } + } +} + +/// Automatic implementation of Downcast for any applicable types +impl Downcast for T {} + +/// Implements transitive casting between a type and its grandparent +/// +/// Suppose you have 3 types, A, B and C where A -> B and B -> C casting relationships exist, +/// `impl_transitive_cast!(A, B, C)` will implement the relationship A -> C. +/// +/// # Example +/// +/// ``` +/// use cxx_qt::impl_transitive_cast; +/// +/// +/// #[derive(Debug)] +/// struct A { +/// value: i32 +/// } +/// +/// #[derive(Debug)] +/// struct B { +/// value: i32 +/// } +/// +/// #[derive(Debug)] +/// struct C { +/// value: i32 +/// } +/// +/// use cxx_qt::casting::Upcast; +/// +/// unsafe impl Upcast for A { +/// unsafe fn upcast_ptr(this: *const Self) -> *const B { +/// let b = B { +/// value: unsafe { (*this).value } +/// }; +/// &b as *const B +/// } +/// +/// unsafe fn from_base_ptr(base: *const B) -> *const Self { +/// let this = A { +/// value: unsafe { (*base).value } +/// }; +/// &this as *const Self +/// } +/// +/// } +/// +/// unsafe impl Upcast for B { +/// unsafe fn upcast_ptr(this: *const Self) -> *const C { +/// let c = C { +/// value: unsafe { (*this).value } +/// }; +/// &c as *const C +/// } +/// +/// unsafe fn from_base_ptr(base: *const C) -> *const Self { +/// let this = B { +/// value: unsafe { (*base).value } +/// }; +/// &this as *const Self +/// } +/// +/// } +/// +/// impl_transitive_cast!(A, B, C); +/// +/// # // Note that we need a fake main function for doc tests to build. +/// # fn main() { +/// # cxx_qt::init_crate!(cxx_qt); +/// # let a = A { value: 25 }; +/// # assert_eq!(Upcast::::upcast(&a).value, 25); +/// # assert_eq!(Upcast::::upcast(&a).value, 25); +/// # } +/// ``` +#[macro_export] +macro_rules! impl_transitive_cast { + ($first:ty, $second:ty, $third:ty) => { + unsafe impl ::cxx_qt::casting::Upcast<$third> for $first { + unsafe fn upcast_ptr(this: *const Self) -> *const $third { + let base = >::upcast_ptr(this); + <$second as Upcast<$third>>::upcast_ptr(base) + } + + unsafe fn from_base_ptr(base: *const $third) -> *const Self { + let base = <$second as Upcast<$third>>::from_base_ptr(base); + if base.is_null() { + std::ptr::null() + } else { + >::from_base_ptr(base) + } + } + } + }; +} + +/// Implements transitive casting in a chain for a type and all its ancestors +/// +/// Suppose you have 3 types, A, B and C where A -> B and B -> C casting relationships exist, +/// `chain_cast!(A, B, C)` will implement the relationship A -> C just like `impl_transitive_cast!` +/// +/// Where these 2 macros differ is in longer chains as for a longer chain, +/// `chain_cast!` will implement casting between the first type and all its ancestors. +/// For example, chain_cast!(A, B, C, D, E) will implement the following casts +/// - A -> C +/// - A -> D +/// - A -> E +/// +/// # Example +/// +/// ``` +/// use cxx_qt::chain_cast; +/// +/// +/// #[derive(Debug)] +/// struct A { +/// value: i32 +/// } +/// +/// #[derive(Debug)] +/// struct B { +/// value: i32 +/// } +/// +/// #[derive(Debug)] +/// struct C { +/// value: i32 +/// } +/// +/// #[derive(Debug)] +/// struct D { +/// value: i32 +/// } +/// +/// use cxx_qt::casting::Upcast; +/// +/// unsafe impl Upcast for A { +/// unsafe fn upcast_ptr(this: *const Self) -> *const B { +/// let b = B { +/// value: unsafe { (*this).value } +/// }; +/// &b as *const B +/// } +/// +/// unsafe fn from_base_ptr(base: *const B) -> *const Self { +/// let this = A { +/// value: unsafe { (*base).value } +/// }; +/// &this as *const Self +/// } +/// +/// } +/// +/// unsafe impl Upcast for B { +/// unsafe fn upcast_ptr(this: *const Self) -> *const C { +/// let c = C { +/// value: unsafe { (*this).value } +/// }; +/// &c as *const C +/// } +/// +/// unsafe fn from_base_ptr(base: *const C) -> *const Self { +/// let this = B { +/// value: unsafe { (*base).value } +/// }; +/// &this as *const Self +/// } +/// +/// } +/// +/// unsafe impl Upcast for C { +/// unsafe fn upcast_ptr(this: *const Self) -> *const D { +/// let d = D { +/// value: unsafe { (*this).value } +/// }; +/// &d as *const D +/// } +/// +/// unsafe fn from_base_ptr(base: *const D) -> *const Self { +/// let this = C { +/// value: unsafe { (*base).value } +/// }; +/// &this as *const Self +/// } +/// +/// } +/// +/// chain_cast!(A, B, C, D); +/// +/// # // Note that we need a fake main function for doc tests to build. +/// # fn main() { +/// # cxx_qt::init_crate!(cxx_qt); +/// # let a = A { value: 25 }; +/// # assert_eq!(Upcast::::upcast(&a).value, 25); +/// # assert_eq!(Upcast::::upcast(&a).value, 25); +/// # assert_eq!(Upcast::::upcast(&a).value, 25); +/// # } +/// ``` +#[macro_export] +macro_rules! chain_cast { + ($first:ty, $second:ty, $third:ty) => { + $crate::impl_transitive_cast!($first, $second, $third); + }; + + ($first:ty, $second:ty, $third:ty, $($rest:ty),*) => { + $crate::impl_transitive_cast!($first, $second, $third); + chain_cast!($first, $third, $($rest),*); + }; +} diff --git a/crates/cxx-qt/src/lib.rs b/crates/cxx-qt/src/lib.rs index e06564f79..186c56421 100644 --- a/crates/cxx-qt/src/lib.rs +++ b/crates/cxx-qt/src/lib.rs @@ -9,10 +9,10 @@ //! //! See the [book](https://kdab.github.io/cxx-qt/book/) for more information. -use std::ops::Deref; -use std::pin::Pin; use std::{fs::File, io::Write, path::Path}; +#[doc(hidden)] +pub mod casting; mod connection; mod connectionguard; mod qobject; @@ -216,128 +216,6 @@ pub trait Threading: Sized { fn threading_drop(cxx_qt_thread: &mut CxxQtThread); } -/// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it. -/// Allows upcasting to either [QObject] or the provided base class of a type. -/// Will not be implemented if no types inherit from [QObject] or have the `#[base = T]` attribute. -pub unsafe trait Upcast { - #[doc(hidden)] - /// # Safety - /// - /// Internal function, Should probably not be implemented manually unless you're absolutely sure you need it. - /// Automatically available for types in RustQt blocks in [cxx_qt::bridge](bridge)s. - /// Upcasts a pointer to `Self` to a pointer to the base class `T`. - /// > Note: Internal implementation uses `static_cast`. - unsafe fn upcast_ptr(this: *const Self) -> *const T; - - #[doc(hidden)] - /// # Safety - /// - /// Internal function, Should probably not be implemented manually unless you're absolutely sure you need it. - /// Automatically available for types in RustQt blocks in [cxx_qt::bridge](bridge)s. - /// Downcasts a pointer to base class `T` to a pointer to `Self`. - /// Return a null pointer if `Self` is not actually a child of base. - /// > Note: Internal implementation uses `dynamic_cast`. - unsafe fn from_base_ptr(base: *const T) -> *const Self; - - /// Upcast a reference to self to a reference to the base class - fn upcast(&self) -> &T { - let ptr = self as *const Self; - unsafe { - let base = Self::upcast_ptr(ptr); - &*base - } - } - - /// Upcast a mutable reference to sell to a mutable reference to the base class - fn upcast_mut(&mut self) -> &mut T { - let ptr = self as *const Self; - unsafe { - let base = Self::upcast_ptr(ptr) as *mut T; - &mut *base - } - } - - /// Upcast a pinned mutable reference to self to a pinned mutable reference to the base class - fn upcast_pin(self: Pin<&mut Self>) -> Pin<&mut T> { - let this = self.deref() as *const Self; - unsafe { - let base = Self::upcast_ptr(this) as *mut T; - Pin::new_unchecked(&mut *base) - } - } -} - -/// Docs -pub unsafe trait MainCast: Upcast { - /// The first parent of the Type - type Base; -} - -unsafe impl Upcast for T -where - T: MainCast, - A: MainCast, -{ - unsafe fn upcast_ptr(this: *const Self) -> *const B { - let base = Self::upcast_ptr(this); - A::upcast_ptr(base) - } - - unsafe fn from_base_ptr(base: *const B) -> *const Self { - let base = A::from_base_ptr(base); - if base.is_null() { - std::ptr::null() - } else { - Self::from_base_ptr(base) - } - } -} - -/// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it. -/// Trait for downcasting to a subclass, provided the subclass implements [Upcast] to this type. -/// Returns `None` in cases where `Sub` isn't a child class of `Self`. -pub trait Downcast: Sized { - /// Try to downcast to a subclass of this type, given that the subclass upcasts to this type - fn downcast>(&self) -> Option<&Sub> { - unsafe { - let ptr = Sub::from_base_ptr(self as *const Self); - if ptr.is_null() { - None - } else { - Some(&*ptr) - } - } - } - - /// Try to downcast mutably to a subclass of this, given that the subclass upcasts to this type - fn downcast_mut>(&mut self) -> Option<&mut Sub> { - unsafe { - let ptr = Sub::from_base_ptr(self as *const Self) as *mut Sub; - if ptr.is_null() { - None - } else { - Some(&mut *ptr) - } - } - } - - /// Try to downcast a pin to a pinned subclass of this, given that the subclass upcasts to this type - fn downcast_pin>(self: Pin<&mut Self>) -> Option> { - let this = self.deref() as *const Self; - unsafe { - let ptr = Sub::from_base_ptr(this) as *mut Sub; - if ptr.is_null() { - None - } else { - Some(Pin::new_unchecked(&mut *ptr)) - } - } - } -} - -/// Automatic implementation of Downcast for any applicable types -impl Downcast for T {} - /// This trait can be implemented on any [CxxQtType] to define a /// custom constructor in C++ for the QObject. /// diff --git a/examples/cargo_without_cmake/src/main.rs b/examples/cargo_without_cmake/src/main.rs index 12bab6719..bdc1b9b1b 100644 --- a/examples/cargo_without_cmake/src/main.rs +++ b/examples/cargo_without_cmake/src/main.rs @@ -14,7 +14,7 @@ // ANCHOR: book_cargo_imports pub mod cxxqt_object; -use cxx_qt::Upcast; +use cxx_qt::casting::Upcast; use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl}; // ANCHOR_END: book_cargo_imports diff --git a/examples/qml_features/rust/src/custom_base_class.rs b/examples/qml_features/rust/src/custom_base_class.rs index 3d0555227..b5949da12 100644 --- a/examples/qml_features/rust/src/custom_base_class.rs +++ b/examples/qml_features/rust/src/custom_base_class.rs @@ -10,9 +10,10 @@ #[cxx_qt::bridge] pub mod qobject { // ANCHOR: book_base_include - unsafe extern "C++" { + unsafe extern "C++Qt" { include!(); /// Base for Qt type + #[qobject] type QAbstractListModel; } // ANCHOR_END: book_base_include @@ -272,11 +273,20 @@ pub mod qobject { } } -use crate::custom_base_class::qobject::CustomBaseClass; +use crate::custom_base_class::qobject::{ + AbstractBaseClass, CustomBaseClass, QAbstractListModel, QObject, +}; use core::pin::Pin; -use cxx_qt::{CxxQtType, Threading}; +use cxx_qt::{casting::Upcast, chain_cast, CxxQtType, Threading}; use cxx_qt_lib::{QByteArray, QHash, QHashPair_i32_QByteArray, QModelIndex, QVariant, QVector}; +chain_cast!( + CustomBaseClass, + AbstractBaseClass, + QAbstractListModel, + QObject +); + impl Default for qobject::State { fn default() -> Self { Self::Idle diff --git a/examples/qml_minimal/qml/main.qml b/examples/qml_minimal/qml/main.qml index 5b7c3b6ec..0b32505e4 100644 --- a/examples/qml_minimal/qml/main.qml +++ b/examples/qml_minimal/qml/main.qml @@ -28,11 +28,6 @@ ApplicationWindow { string: qsTr("My String with my number: %1").arg(myObject.number) } - A { - id: a - number: 10 - } - Column { anchors.fill: parent anchors.margins: 10 @@ -60,12 +55,6 @@ ApplicationWindow { onClicked: myObject.sayHi(myObject.string, myObject.number) } - Button { - text: qsTr("Test A") - - onClicked: a.test() - } - Button { text: qsTr("Quit") diff --git a/examples/qml_multi_crates/rust/main/src/main.rs b/examples/qml_multi_crates/rust/main/src/main.rs index d39cd93c3..285cbdacf 100644 --- a/examples/qml_multi_crates/rust/main/src/main.rs +++ b/examples/qml_multi_crates/rust/main/src/main.rs @@ -5,7 +5,7 @@ extern crate qml_multi_crates; -use cxx_qt::Upcast; +use cxx_qt::casting::Upcast; use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl}; fn main() {