diff --git a/crates/cxx-qt-gen/src/generator/rust/fragment.rs b/crates/cxx-qt-gen/src/generator/rust/fragment.rs index 3a440fd82..04828656d 100644 --- a/crates/cxx-qt-gen/src/generator/rust/fragment.rs +++ b/crates/cxx-qt-gen/src/generator/rust/fragment.rs @@ -78,7 +78,7 @@ impl GeneratedRustFragment { } }], cxx_qt_mod_contents: vec![parse_quote! { - impl ::cxx_qt::Upcast<#base_qualified> for #struct_name { + unsafe impl ::cxx_qt::Upcast<#base_qualified> for #struct_name { unsafe fn upcast_ptr(this: *const Self) -> *const #base_qualified { #upcast_fn_qualified(this) } 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 4129e34bf..1b04c1a2b 100644 --- a/crates/cxx-qt/src/lib.rs +++ b/crates/cxx-qt/src/lib.rs @@ -130,7 +130,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 /// diff --git a/examples/qml_features/rust/src/custom_base_class.rs b/examples/qml_features/rust/src/custom_base_class.rs index 3d0555227..0d427552b 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,51 @@ pub mod qobject { } } -use crate::custom_base_class::qobject::CustomBaseClass; +macro_rules! impl_transitive_cast { + ($first:ty, $second:ty, $third:ty) => { + unsafe impl cxx_qt::Upcast<$third> for $first { + unsafe fn upcast_ptr(this: *const Self) -> *const $third { + let base = Self::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 { + Self::from_base_ptr(base) + } + } + } + }; +} + +macro_rules! chain_cast { + ($first:ty, $second:ty, $third:ty) => { + impl_transitive_cast!($first, $second, $third); + }; + + ($first:ty, $second:ty, $third:ty, $($rest:ty),*) => { + impl_transitive_cast!($first, $second, $third); + $(impl_transitive_cast!($first, $third, $rest);)* + }; +} + +use crate::custom_base_class::qobject::{ + AbstractBaseClass, CustomBaseClass, QAbstractListModel, QObject, +}; use core::pin::Pin; -use cxx_qt::{CxxQtType, Threading}; +use cxx_qt::{CxxQtType, Threading, Upcast}; 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 @@ -300,6 +341,12 @@ pub struct CustomBaseClassRust { impl qobject::CustomBaseClass { /// Virtual method for logging type pub fn log(self: &CustomBaseClass) { + let _abs: &AbstractBaseClass = self.upcast(); + let _qabs: &QAbstractListModel = self.upcast(); + let qobj: &QObject = self.upcast(); + + qobj.dump_object_info(); + println!( "state: {}\npending adds: {}\nid: {}\nvector: {:?}\n", self.state.repr, self.pending_adds, self.id, self.vector