Skip to main content

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}