diff --git a/crates/cxx-qt-gen/src/generator/rust/qobject.rs b/crates/cxx-qt-gen/src/generator/rust/qobject.rs index 315095f04..a582ff05d 100644 --- a/crates/cxx-qt-gen/src/generator/rust/qobject.rs +++ b/crates/cxx-qt-gen/src/generator/rust/qobject.rs @@ -16,7 +16,7 @@ use crate::{ naming::TypeNames, }; use quote::{format_ident, quote}; -use syn::{parse_quote, Attribute, Ident, Result}; +use syn::{parse_quote, Attribute, Result}; impl GeneratedRustFragment { // Might need to be refactored to use a StructuredQObject instead (confirm with Leon) @@ -30,11 +30,7 @@ impl GeneratedRustFragment { let namespace_idents = NamespaceName::from(qobject); let mut generated = vec![ - generate_qobject_definitions( - &qobject_names, - qobject.base_class.clone(), - type_names, - )?, + generate_qobject_definitions(&qobject_names, &qobject.cfgs)?, generate_rust_properties( &qobject.properties, &qobject_names, @@ -67,18 +63,7 @@ impl GeneratedRustFragment { )?); } - generated.extend(vec![ - constructor::generate( - &structured_qobject.constructors, - &qobject_names, - &namespace_idents, - type_names, - &qobject.cfgs, - )?, - cxxqttype::generate(&qobject_names, type_names, &qobject.cfgs)?, - ]); // Generate casting impl - let mut blocks = GeneratedRustFragment::default(); let base = structured_qobject .declaration .base_class @@ -88,7 +73,7 @@ impl GeneratedRustFragment { .cloned() .unwrap_or( Name::new(format_ident!("QObject")).with_module(parse_quote! {::cxx_qt::qobject}), - ); // TODO! is this default module here causing the issues in the threading examples + ); let base_unqualified = base.rust_unqualified(); let base_qualified = base.rust_qualified(); @@ -98,12 +83,20 @@ impl GeneratedRustFragment { let (upcast_fn, upcast_fn_attrs, upcast_fn_qualified) = qobject_names .cxx_qt_ffi_method("upcastPtr") .into_cxx_parts(); - let fragment = GeneratedRustFragment { + let (downcast_fn, downcast_fn_attrs, downcast_fn_qualified) = qobject_names + .cxx_qt_ffi_method("downcastPtr") + .into_cxx_parts(); + + generated.push(GeneratedRustFragment { cxx_mod_contents: vec![parse_quote! { extern "C++" { #[doc(hidden)] #(#upcast_fn_attrs)* unsafe fn #upcast_fn(thiz: *const #struct_name_unqualified) -> *const #base_unqualified; + + #[doc(hidden)] + #(#downcast_fn_attrs)* + unsafe fn #downcast_fn(base: *const #base_unqualified) -> *const #struct_name_unqualified; } }], cxx_qt_mod_contents: vec![parse_quote! { @@ -111,26 +104,34 @@ impl GeneratedRustFragment { 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) + } } }], - }; + }); - generated.push(fragment); - generated.push(blocks); - - generated.push(constructor::generate( - &structured_qobject.constructors, - &qobject_names, - &namespace_idents, - type_names, - )?); + generated.extend(vec![ + constructor::generate( + &structured_qobject.constructors, + &qobject_names, + &namespace_idents, + type_names, + &qobject.cfgs, + )?, + cxxqttype::generate(&qobject_names, type_names, &qobject.cfgs)?, + ]); Ok(GeneratedRustFragment::flatten(generated)) } } /// Generate the C++ and Rust CXX definitions for the QObject -fn generate_qobject_definitions(qobject_idents: &QObjectNames) -> Result { +fn generate_qobject_definitions( + qobject_idents: &QObjectNames, + cfgs: &[Attribute], +) -> Result { let cpp_class_name_rust = &qobject_idents.name.rust_unqualified(); let cpp_class_name_cpp = &qobject_idents.name.cxx_unqualified(); @@ -264,6 +265,11 @@ mod tests { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyObject_upcastPtr(thiz: *const MyObject) -> *const QObject; + + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyObject_downcastPtr(base: *const QObject) -> *const MyObject; } }, ); diff --git a/crates/cxx-qt-gen/test_outputs/cfgs.h b/crates/cxx-qt-gen/test_outputs/cfgs.h index 440bccaba..67e943c6e 100644 --- a/crates/cxx-qt-gen/test_outputs/cfgs.h +++ b/crates/cxx-qt-gen/test_outputs/cfgs.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include diff --git a/crates/cxx-qt-gen/test_outputs/cfgs.rs b/crates/cxx-qt-gen/test_outputs/cfgs.rs index b07954b71..6dd38ab12 100644 --- a/crates/cxx-qt-gen/test_outputs/cfgs.rs +++ b/crates/cxx-qt-gen/test_outputs/cfgs.rs @@ -160,6 +160,20 @@ mod ffi { self_value: Pin<&mut QObjectEnabled>, ); } + extern "C++" { + #[doc(hidden)] + #[cxx_name = "upcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_QObjectEnabled_upcastPtr( + thiz: *const QObjectEnabled, + ) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_QObjectEnabled_downcastPtr( + base: *const QObject, + ) -> *const QObjectEnabled; + } extern "Rust" { #[cxx_name = "createRs"] #[namespace = "cxx_qt_QObjectEnabled"] @@ -288,6 +302,20 @@ mod ffi { self_value: Pin<&mut QObjectDisabled>, ); } + extern "C++" { + #[doc(hidden)] + #[cxx_name = "upcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_QObjectDisabled_upcastPtr( + thiz: *const QObjectDisabled, + ) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_QObjectDisabled_downcastPtr( + base: *const QObject, + ) -> *const QObjectDisabled; + } extern "Rust" { #[cxx_name = "createRs"] #[namespace = "cxx_qt_QObjectDisabled"] @@ -458,6 +486,11 @@ mod ffi { self_value: Pin<&mut QObjectExternDisabled>, ); } + extern "C++" { + #[doc(hidden)] + #[namespace = ""] + type QObject = cxx_qt::qobject::QObject; + } } #[cfg(not(enabled))] impl ffi::QObjectEnabled { @@ -607,6 +640,14 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); +impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::QObjectEnabled { + unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { + ffi::cxx_qt_ffi_QObjectEnabled_upcastPtr(this) + } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_QObjectEnabled_downcastPtr(base) + } +} #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] #[cfg(enabled)] @@ -778,6 +819,14 @@ cxx_qt::static_assertions::assert_eq_size!( cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2] ); +impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::QObjectDisabled { + unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { + ffi::cxx_qt_ffi_QObjectDisabled_upcastPtr(this) + } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_QObjectDisabled_downcastPtr(base) + } +} #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] #[cfg(not(enabled))] diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.rs b/crates/cxx-qt-gen/test_outputs/inheritance.rs index 42ea01d3d..1598f5fc4 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_outputs/inheritance.rs @@ -67,6 +67,12 @@ mod inheritance { #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyObject_upcastPtr(thiz: *const MyObject) -> *const QAbstractItemModel; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyObject_downcastPtr( + base: *const QAbstractItemModel, + ) -> *const MyObject; } extern "Rust" { #[cxx_name = "createRs"] @@ -90,6 +96,9 @@ impl ::cxx_qt::Upcast for inheritance::MyObject unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QAbstractItemModel { inheritance::cxx_qt_ffi_MyObject_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const inheritance::QAbstractItemModel) -> *const Self { + inheritance::cxx_qt_ffi_MyObject_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] diff --git a/crates/cxx-qt-gen/test_outputs/invokables.rs b/crates/cxx-qt-gen/test_outputs/invokables.rs index 56dcca15d..655fee6cb 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -151,6 +151,10 @@ mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyObject_upcastPtr(thiz: *const MyObject) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyObject_downcastPtr(base: *const QObject) -> *const MyObject; } #[namespace = "cxx_qt::my_object::cxx_qt_MyObject"] #[cxx_name = "CxxQtConstructorArguments0"] @@ -315,6 +319,9 @@ impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_MyObject_downcastPtr(base) + } } #[doc(hidden)] pub fn route_arguments_MyObject_0<'a>( 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 f587e2fc6..4428b9b6d 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs @@ -170,6 +170,11 @@ pub mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyObject_upcastPtr(thiz: *const MyObject) -> *const QStringListModel; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyObject_downcastPtr(base: *const QStringListModel) + -> *const MyObject; } extern "Rust" { #[cxx_name = "createRs"] @@ -292,6 +297,10 @@ pub mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_SecondObject_upcastPtr(thiz: *const SecondObject) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_SecondObject_downcastPtr(base: *const QObject) -> *const SecondObject; } extern "Rust" { #[cxx_name = "createRs"] @@ -334,6 +343,10 @@ pub mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyCxxName_upcastPtr(thiz: *const MyRustName) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyCxxName_downcastPtr(base: *const QObject) -> *const MyRustName; } extern "Rust" { #[cxx_name = "createRs"] @@ -613,6 +626,9 @@ impl ::cxx_qt::Upcast for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ffi::QStringListModel { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ffi::QStringListModel) -> *const Self { + ffi::cxx_qt_ffi_MyObject_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] @@ -784,6 +800,9 @@ impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::SecondObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { ffi::cxx_qt_ffi_SecondObject_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_SecondObject_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] @@ -809,6 +828,9 @@ impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::MyRustName { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { ffi::cxx_qt_ffi_MyCxxName_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_MyCxxName_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index 699b8ae2d..c84c2ed4a 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -394,6 +394,10 @@ mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyObject_upcastPtr(thiz: *const MyObject) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyObject_downcastPtr(base: *const QObject) -> *const MyObject; } extern "Rust" { #[cxx_name = "createRs"] @@ -1052,6 +1056,9 @@ impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_MyObject_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] diff --git a/crates/cxx-qt-gen/test_outputs/qenum.rs b/crates/cxx-qt-gen/test_outputs/qenum.rs index 099dd046e..bb57740b1 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.rs +++ b/crates/cxx-qt-gen/test_outputs/qenum.rs @@ -95,6 +95,10 @@ mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyObject_upcastPtr(thiz: *const MyObject) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyObject_downcastPtr(base: *const QObject) -> *const MyObject; } extern "Rust" { #[cxx_name = "createRs"] @@ -135,6 +139,10 @@ mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_CxxName_upcastPtr(thiz: *const MyRenamedObject) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_CxxName_downcastPtr(base: *const QObject) -> *const MyRenamedObject; } extern "Rust" { #[cxx_name = "createRs"] @@ -165,6 +173,9 @@ impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_MyObject_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] @@ -190,6 +201,9 @@ impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::MyRenamedObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { ffi::cxx_qt_ffi_CxxName_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_CxxName_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index 264d069f6..a969ed105 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -159,6 +159,10 @@ mod ffi { #[cxx_name = "upcastPtr"] #[namespace = "rust::cxxqt1"] unsafe fn cxx_qt_ffi_MyObject_upcastPtr(thiz: *const MyObject) -> *const QObject; + #[doc(hidden)] + #[cxx_name = "downcastPtr"] + #[namespace = "rust::cxxqt1"] + unsafe fn cxx_qt_ffi_MyObject_downcastPtr(base: *const QObject) -> *const MyObject; } extern "Rust" { #[cxx_name = "createRs"] @@ -443,6 +447,9 @@ impl ::cxx_qt::Upcast<::cxx_qt::qobject::QObject> for ffi::MyObject { unsafe fn upcast_ptr(this: *const Self) -> *const ::cxx_qt::qobject::QObject { ffi::cxx_qt_ffi_MyObject_upcastPtr(this) } + unsafe fn from_base_ptr(base: *const ::cxx_qt::qobject::QObject) -> *const Self { + ffi::cxx_qt_ffi_MyObject_downcastPtr(base) + } } #[doc(hidden)] #[allow(clippy::unnecessary_box_returns)] diff --git a/crates/cxx-qt/include/casting.h b/crates/cxx-qt/include/casting.h index 77d4223d2..534ee6317 100644 --- a/crates/cxx-qt/include/casting.h +++ b/crates/cxx-qt/include/casting.h @@ -15,4 +15,12 @@ upcastPtr(const Sub* sub) return static_cast(sub); } +template +const Sub* +downcastPtr(const Base* base) +{ + static_assert(std::is_base_of_v); + return dynamic_cast(base); +} + } diff --git a/crates/cxx-qt/src/lib.rs b/crates/cxx-qt/src/lib.rs index 486024c26..cfde22549 100644 --- a/crates/cxx-qt/src/lib.rs +++ b/crates/cxx-qt/src/lib.rs @@ -132,6 +132,10 @@ pub trait Upcast { /// Internal function, Should not be implemented manually unsafe fn upcast_ptr(this: *const Self) -> *const T; + #[doc(hidden)] + /// Internal function, Should not be implemented manually + unsafe fn from_base_ptr(base: *const T) -> *const Self; + /// Upcast a reference to a reference to the base class fn upcast(&self) -> &T { let ptr = self as *const Self; @@ -160,6 +164,23 @@ pub trait Upcast { } } +/// Trait for downcasting to a subclass, provided the subclass implements Upcast to this type +pub trait Downcast: Sized { + /// try Downcast to a subclass of this, 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) + } + } + } +} + +impl Downcast for T {} + /// This trait can be implemented on any [CxxQtType] to define a /// custom constructor in C++ for the QObject. ///