Skip to content

Add Transitive casting and testing code #1252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion book/src/concepts/casting.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ or a `#[base = T]` attribute. See the [attributes documentation](../bridge/attri

## Accessing the base class

To access the methods of a base class in Rust, use the `Upcast` trait like so `use cxx_qt::Upcast;`.
To access the methods of a base class in Rust, use the `Upcast` trait like so `use cxx_qt::casting::Upcast;`.
Objects with base classes can then be accessed with the following methods

| Self Type | Method |
Expand All @@ -41,3 +41,17 @@ The child can then be accessed in the same manner, with the following methods
These will return an `Option<T>`, as it is possible that downcasting will fail,
if the type is not actually of the given subclass,
and these also return in the same format as the self type, e.g. `downcast()` returns `Option<&Sub>`, etc...

## Transitive casting

Given 3 types, where there is a grandparent relationship, e.g. that using 2 casts, you can go from A -> B -> C,
CXX-Qt inlcudes a macro for automatically implementing a cast between A and C. This property also extends for longer chains.
For example, if you have a deeply nested set of inheritance, you can quickly generate helpers to cast from your child type to any of its ancestors.

```rust, ignore
use cxx_qt::impl_transitive_cast;

impl_transitive_cast!(A, B, C, D);
```

Will generate casting from A -> C, and A -> D, **provided** A -> B -> C -> D is already implemented.
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/src/generator/rust/fragment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::casting::Upcast<#base_qualified> for #struct_name {
unsafe fn upcast_ptr(this: *const Self) -> *const #base_qualified {
#upcast_fn_qualified(this)
}
Expand Down
8 changes: 4 additions & 4 deletions crates/cxx-qt-gen/test_outputs/cfgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ cxx_qt::static_assertions::assert_eq_size!(
cxx_qt::signalhandler::CxxQtSignalHandler<QObjectEnabledCxxQtSignalClosuresignal_enabled>,
[usize; 2]
);
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)
}
Expand Down Expand Up @@ -864,7 +864,7 @@ cxx_qt::static_assertions::assert_eq_size!(
cxx_qt::signalhandler::CxxQtSignalHandler<QObjectDisabledCxxQtSignalClosuresignal_enabled>,
[usize; 2]
);
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)
}
Expand Down Expand Up @@ -895,7 +895,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::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)
}
Expand Down Expand Up @@ -1073,7 +1073,7 @@ cxx_qt::static_assertions::assert_eq_size!(
>,
[usize; 2]
);
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)
}
Expand Down
6 changes: 3 additions & 3 deletions crates/cxx-qt-gen/test_outputs/inheritance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ mod inheritance {
type QObject = cxx_qt::QObject;
}
}
impl ::cxx_qt::Upcast<inheritance::QAbstractItemModel> for inheritance::MyObject {
unsafe impl ::cxx_qt::casting::Upcast<inheritance::QAbstractItemModel> for inheritance::MyObject {
unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QAbstractItemModel {
inheritance::cxx_qt_ffi_MyObject_upcastPtr(this)
}
Expand Down Expand Up @@ -158,15 +158,15 @@ 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::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)
}
unsafe fn from_base_ptr(base: *const ::cxx_qt::QObject) -> *const Self {
inheritance::cxx_qt_ffi_QPushButton_downcastPtr(base)
}
}
impl ::cxx_qt::Upcast<inheritance::QPushButton> for inheritance::QPushButtonChild {
unsafe impl ::cxx_qt::casting::Upcast<inheritance::QPushButton> for inheritance::QPushButtonChild {
unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QPushButton {
inheritance::cxx_qt_ffi_QPushButtonChild_upcastPtr(this)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_outputs/invokables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ impl cxx_qt::Threading for ffi::MyObject {
pub struct MyObjectCxxQtThreadQueuedFn {
inner: std::boxed::Box<dyn FnOnce(core::pin::Pin<&mut ffi::MyObject>) + Send>,
}
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)
}
Expand Down
10 changes: 5 additions & 5 deletions crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ cxx_qt::static_assertions::assert_eq_size!(
cxx_qt::signalhandler::CxxQtSignalHandler<MyObjectCxxQtSignalClosureready>,
[usize; 2]
);
impl ::cxx_qt::Upcast<ffi::QStringListModel> for ffi::MyObject {
unsafe impl ::cxx_qt::casting::Upcast<ffi::QStringListModel> for ffi::MyObject {
unsafe fn upcast_ptr(this: *const Self) -> *const ffi::QStringListModel {
ffi::cxx_qt_ffi_MyObject_upcastPtr(this)
}
Expand Down Expand Up @@ -839,7 +839,7 @@ cxx_qt::static_assertions::assert_eq_size!(
cxx_qt::signalhandler::CxxQtSignalHandler<SecondObjectCxxQtSignalClosureready>,
[usize; 2]
);
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)
}
Expand Down Expand Up @@ -867,7 +867,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::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)
}
Expand Down Expand Up @@ -895,15 +895,15 @@ 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::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)
}
unsafe fn from_base_ptr(base: *const ::cxx_qt::QObject) -> *const Self {
ffi::cxx_qt_ffi_QPushButton_downcastPtr(base)
}
}
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)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_outputs/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@ cxx_qt::static_assertions::assert_eq_size!(
cxx_qt::signalhandler::CxxQtSignalHandler<MyObjectCxxQtSignalClosuremy_on_changed>,
[usize; 2]
);
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)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/test_outputs/qenum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::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)
}
Expand Down Expand Up @@ -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::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)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/test_outputs/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ cxx_qt::static_assertions::assert_eq_size!(
cxx_qt::signalhandler::CxxQtSignalHandler<MyObjectCxxQtSignalClosurenewData>,
[usize; 2]
);
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)
}
Expand Down Expand Up @@ -492,7 +492,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::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)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-lib/src/core/qstringlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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};

Expand Down Expand Up @@ -204,7 +204,7 @@ impl DerefMut for QStringList {
}
}

impl Upcast<QList<QString>> for QStringList {
unsafe impl Upcast<QList<QString>> for QStringList {
unsafe fn upcast_ptr(this: *const Self) -> *const QList<QString> {
ffi::upcast_qstringlist(this)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-lib/src/gui/qpolygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use crate::{QPoint, QRect, QVector};
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};

Expand Down Expand Up @@ -193,7 +193,7 @@ impl DerefMut for QPolygon {
}
}

impl Upcast<QVector<QPoint>> for QPolygon {
unsafe impl Upcast<QVector<QPoint>> for QPolygon {
unsafe fn upcast_ptr(this: *const Self) -> *const QVector<QPoint> {
ffi::upcast_qpolygon(this)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-lib/src/gui/qpolygonf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
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};

Expand Down Expand Up @@ -175,7 +175,7 @@ impl DerefMut for QPolygonF {
}
}

impl Upcast<QVector<QPointF>> for QPolygonF {
unsafe impl Upcast<QVector<QPointF>> for QPolygonF {
unsafe fn upcast_ptr(this: *const Self) -> *const QVector<QPointF> {
ffi::upcast_qpolygonf(this)
}
Expand Down
Loading
Loading