cxx_qt/casting.rs
1// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Ben Ford <ben.ford@kdab.com>
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5
6use std::pin::Pin;
7
8/// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it.
9/// Allows upcasting to either [crate::QObject] or the provided base class of a type.
10/// Will not be implemented if no types inherit from [crate::QObject] or have the `#[base = T]` attribute.
11///
12/// # Safety
13///
14/// By implementing Upcast for your type, you take responsibility that the type you are upcasting to is actually a parent.
15pub unsafe trait Upcast<T> {
16 #[doc(hidden)]
17 /// # Safety
18 ///
19 /// Internal function, Should probably not be implemented manually unless you're absolutely sure you need it.
20 /// Automatically available for types in RustQt blocks in [cxx_qt::bridge](bridge)s.
21 /// Upcasts a pointer to `Self` to a pointer to the base class `T`.
22 /// > Note: Internal implementation uses `static_cast`.
23 unsafe fn upcast_ptr(this: *const Self) -> *const T;
24
25 #[doc(hidden)]
26 /// # Safety
27 ///
28 /// Internal function, Should probably not be implemented manually unless you're absolutely sure you need it.
29 /// Automatically available for types in RustQt blocks in [cxx_qt::bridge](bridge)s.
30 /// Downcasts a pointer to base class `T` to a pointer to `Self`.
31 /// Return a null pointer if `Self` is not actually a child of base.
32 /// > Note: Internal implementation uses `dynamic_cast`.
33 unsafe fn from_base_ptr(base: *const T) -> *const Self;
34
35 /// Upcast a reference to self to a reference to the base class
36 fn upcast(&self) -> &T {
37 unsafe { &*Self::upcast_ptr(self) }
38 }
39
40 /// Upcast a mutable reference to sell to a mutable reference to the base class
41 fn upcast_mut(&mut self) -> &mut T {
42 unsafe { &mut *Self::upcast_ptr(self).cast_mut() }
43 }
44
45 /// Upcast a pinned mutable reference to self to a pinned mutable reference to the base class
46 fn upcast_pin(self: Pin<&mut Self>) -> Pin<&mut T> {
47 unsafe { Pin::new_unchecked(&mut *Self::upcast_ptr(&*self).cast_mut()) }
48 }
49}
50
51/// This trait is automatically implemented by CXX-Qt and you most likely do not need to manually implement it.
52/// Trait for downcasting to a subclass, provided the subclass implements [Upcast] to this type.
53/// Returns `None` in cases where `Sub` isn't a child class of `Self`.
54pub trait Downcast: Sized {
55 /// Try to downcast to a subclass of this type, given that the subclass upcasts to this type
56 fn downcast<Sub: Upcast<Self>>(&self) -> Option<&Sub> {
57 unsafe {
58 let ptr = Sub::from_base_ptr(self);
59 if ptr.is_null() {
60 None
61 } else {
62 Some(&*ptr)
63 }
64 }
65 }
66
67 /// Try to downcast mutably to a subclass of this, given that the subclass upcasts to this type
68 fn downcast_mut<Sub: Upcast<Self>>(&mut self) -> Option<&mut Sub> {
69 unsafe {
70 let ptr = Sub::from_base_ptr(self);
71 if ptr.is_null() {
72 None
73 } else {
74 Some(&mut *ptr.cast_mut())
75 }
76 }
77 }
78
79 /// Try to downcast a pin to a pinned subclass of this, given that the subclass upcasts to this type
80 fn downcast_pin<Sub: Upcast<Self>>(self: Pin<&mut Self>) -> Option<Pin<&mut Sub>> {
81 unsafe {
82 let ptr = Sub::from_base_ptr(&*self);
83 if ptr.is_null() {
84 None
85 } else {
86 Some(Pin::new_unchecked(&mut *ptr.cast_mut()))
87 }
88 }
89 }
90}
91
92/// Automatic implementation of Downcast for any applicable types
93impl<T: Sized> Downcast for T {}
94
95unsafe impl<T> Upcast<T> for T {
96 unsafe fn upcast_ptr(this: *const Self) -> *const Self {
97 this
98 }
99
100 unsafe fn from_base_ptr(base: *const T) -> *const Self {
101 base
102 }
103
104 fn upcast(&self) -> &Self {
105 self
106 }
107
108 fn upcast_mut(&mut self) -> &mut Self {
109 self
110 }
111
112 fn upcast_pin(self: Pin<&mut Self>) -> Pin<&mut Self> {
113 self
114 }
115}
116/// Implements transitive casting in a chain for a type and all its ancestors
117///
118/// Suppose you have 3 types, A, B and C where A -> B and B -> C casting relationships exist,
119/// `impl_transitive_cast!(A, B, C)` will implement the relationship A -> C
120///
121/// `impl_transitive_cast!` will implement casting between the first type and ***all*** its ancestors.
122/// For example, impl_transitive_cast!(A, B, C, D, E) will implement the following casts
123/// - A -> C
124/// - A -> D
125/// - A -> E
126///
127/// # Example
128///
129/// ```
130/// use cxx_qt::impl_transitive_cast;
131///
132///
133/// #[derive(Debug)]
134/// struct A {
135/// parent: B
136/// }
137///
138/// #[derive(Debug)]
139/// struct B {
140/// parent: C
141/// }
142///
143/// #[derive(Debug)]
144/// struct C {
145/// parent: D
146/// }
147///
148/// #[derive(Debug)]
149/// struct D {
150/// value: i32
151/// }
152///
153/// use cxx_qt::casting::Upcast;
154///
155/// unsafe impl Upcast<B> for A {
156/// unsafe fn upcast_ptr(this: *const Self) -> *const B {
157/// unsafe { &(*this).parent }
158/// }
159///
160/// unsafe fn from_base_ptr(base: *const B) -> *const Self {
161/// std::ptr::null() // Not needed for this example
162/// }
163///
164/// }
165///
166/// unsafe impl Upcast<C> for B {
167/// unsafe fn upcast_ptr(this: *const Self) -> *const C {
168/// unsafe { &(*this).parent }
169/// }
170///
171/// unsafe fn from_base_ptr(base: *const C) -> *const Self {
172/// std::ptr::null()
173/// }
174///
175/// }
176///
177/// unsafe impl Upcast<D> for C {
178/// unsafe fn upcast_ptr(this: *const Self) -> *const D {
179/// unsafe { &(*this).parent }
180/// }
181///
182/// unsafe fn from_base_ptr(base: *const D) -> *const Self {
183/// std::ptr::null()
184/// }
185///
186/// }
187///
188/// impl_transitive_cast!(A, B, C, D);
189///
190/// # // Note that we need a fake main function for doc tests to build.
191/// # fn main() {
192/// # cxx_qt::init_crate!(cxx_qt);
193/// #
194/// # let a = A {
195/// # parent: B {
196/// # parent: C {
197/// # parent: D {
198/// # value: 25
199/// # }
200/// # }
201/// # }
202/// # };
203/// # assert_eq!(Upcast::<D>::upcast(&a).value, 25);
204/// # }
205/// ```
206#[macro_export]
207macro_rules! impl_transitive_cast {
208 ($first:ty, $second:ty, $third:ty) => {
209 // $crate::impl_transitive_cast!($first, $second, $third);
210 unsafe impl ::cxx_qt::casting::Upcast<$third> for $first {
211 unsafe fn upcast_ptr(this: *const Self) -> *const $third {
212 let base = <Self as Upcast<$second>>::upcast_ptr(this);
213 <$second as Upcast<$third>>::upcast_ptr(base)
214 }
215
216 unsafe fn from_base_ptr(base: *const $third) -> *const Self {
217 let base = <$second as Upcast<$third>>::from_base_ptr(base);
218 if base.is_null() {
219 std::ptr::null()
220 } else {
221 <Self as Upcast<$second>>::from_base_ptr(base)
222 }
223 }
224 }
225 };
226
227 ($first:ty, $second:ty, $third:ty, $($rest:ty),*) => {
228 impl_transitive_cast!($first, $second, $third);
229 impl_transitive_cast!($first, $third, $($rest),*);
230 };
231}