Skip to content

Commit f45893f

Browse files
Add book entry and rename macro
1 parent 7baae3e commit f45893f

File tree

3 files changed

+59
-135
lines changed

3 files changed

+59
-135
lines changed

book/src/concepts/casting.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,17 @@ The child can then be accessed in the same manner, with the following methods
4141
These will return an `Option<T>`, as it is possible that downcasting will fail,
4242
if the type is not actually of the given subclass,
4343
and these also return in the same format as the self type, e.g. `downcast()` returns `Option<&Sub>`, etc...
44+
45+
## Transitive casting
46+
47+
Given 3 types, where there is a grandparent relationship, e.g. that using 2 casts, you can go from A -> B -> C,
48+
CXX-Qt inlcudes a macro for automatically implementing a cast between A and C. This property also extends for longer chains.
49+
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.
50+
51+
```rust
52+
use cxx_qt::impl_transitive_cast;
53+
54+
impl_transitive_cast!(A, B, C, D);
55+
```
56+
57+
Will generate casting from A -> C, and A -> D, **provided** A -> B -> C -> D is already implemented.

crates/cxx-qt/src/casting.rs

Lines changed: 43 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -106,130 +106,36 @@ pub trait Downcast: Sized {
106106
/// Automatic implementation of Downcast for any applicable types
107107
impl<T: Sized> Downcast for T {}
108108

109-
/// Implements transitive casting between a type and its grandparent
110-
///
111-
/// Suppose you have 3 types, A, B and C where A -> B and B -> C casting relationships exist,
112-
/// `impl_transitive_cast!(A, B, C)` will implement the relationship A -> C.
113-
///
114-
/// # Example
115-
///
116-
/// ```
117-
/// use cxx_qt::impl_transitive_cast;
118-
///
119-
///
120-
/// #[derive(Debug)]
121-
/// struct A {
122-
/// value: i32
123-
/// }
124-
///
125-
/// #[derive(Debug)]
126-
/// struct B {
127-
/// value: i32
128-
/// }
129-
///
130-
/// #[derive(Debug)]
131-
/// struct C {
132-
/// value: i32
133-
/// }
134-
///
135-
/// use cxx_qt::casting::Upcast;
136-
///
137-
/// unsafe impl Upcast<B> for A {
138-
/// unsafe fn upcast_ptr(this: *const Self) -> *const B {
139-
/// let b = B {
140-
/// value: unsafe { (*this).value }
141-
/// };
142-
/// &b as *const B
143-
/// }
144-
///
145-
/// unsafe fn from_base_ptr(base: *const B) -> *const Self {
146-
/// let this = A {
147-
/// value: unsafe { (*base).value }
148-
/// };
149-
/// &this as *const Self
150-
/// }
151-
///
152-
/// }
153-
///
154-
/// unsafe impl Upcast<C> for B {
155-
/// unsafe fn upcast_ptr(this: *const Self) -> *const C {
156-
/// let c = C {
157-
/// value: unsafe { (*this).value }
158-
/// };
159-
/// &c as *const C
160-
/// }
161-
///
162-
/// unsafe fn from_base_ptr(base: *const C) -> *const Self {
163-
/// let this = B {
164-
/// value: unsafe { (*base).value }
165-
/// };
166-
/// &this as *const Self
167-
/// }
168-
///
169-
/// }
170-
///
171-
/// impl_transitive_cast!(A, B, C);
172-
///
173-
/// # // Note that we need a fake main function for doc tests to build.
174-
/// # fn main() {
175-
/// # cxx_qt::init_crate!(cxx_qt);
176-
/// # let a = A { value: 25 };
177-
/// # assert_eq!(Upcast::<B>::upcast(&a).value, 25);
178-
/// # assert_eq!(Upcast::<C>::upcast(&a).value, 25);
179-
/// # }
180-
/// ```
181-
#[macro_export]
182-
macro_rules! impl_transitive_cast {
183-
($first:ty, $second:ty, $third:ty) => {
184-
unsafe impl ::cxx_qt::casting::Upcast<$third> for $first {
185-
unsafe fn upcast_ptr(this: *const Self) -> *const $third {
186-
let base = <Self as Upcast<$second>>::upcast_ptr(this);
187-
<$second as Upcast<$third>>::upcast_ptr(base)
188-
}
189-
190-
unsafe fn from_base_ptr(base: *const $third) -> *const Self {
191-
let base = <$second as Upcast<$third>>::from_base_ptr(base);
192-
if base.is_null() {
193-
std::ptr::null()
194-
} else {
195-
<Self as Upcast<$second>>::from_base_ptr(base)
196-
}
197-
}
198-
}
199-
};
200-
}
201-
202109
/// Implements transitive casting in a chain for a type and all its ancestors
203110
///
204111
/// Suppose you have 3 types, A, B and C where A -> B and B -> C casting relationships exist,
205-
/// `chain_cast!(A, B, C)` will implement the relationship A -> C just like `impl_transitive_cast!`
112+
/// `impl_transitive_cast!(A, B, C)` will implement the relationship A -> C
206113
///
207-
/// Where these 2 macros differ is in longer chains as for a longer chain,
208-
/// `chain_cast!` will implement casting between the first type and all its ancestors.
209-
/// For example, chain_cast!(A, B, C, D, E) will implement the following casts
114+
/// `impl_transitive_cast!` will implement casting between the first type and ***all*** its ancestors.
115+
/// For example, impl_transitive_cast!(A, B, C, D, E) will implement the following casts
210116
/// - A -> C
211117
/// - A -> D
212118
/// - A -> E
213119
///
214120
/// # Example
215121
///
216122
/// ```
217-
/// use cxx_qt::chain_cast;
123+
/// use cxx_qt::impl_transitive_cast;
218124
///
219125
///
220126
/// #[derive(Debug)]
221127
/// struct A {
222-
/// value: i32
128+
/// parent: B
223129
/// }
224130
///
225131
/// #[derive(Debug)]
226132
/// struct B {
227-
/// value: i32
133+
/// parent: C
228134
/// }
229135
///
230136
/// #[derive(Debug)]
231137
/// struct C {
232-
/// value: i32
138+
/// parent: D
233139
/// }
234140
///
235141
/// #[derive(Debug)]
@@ -241,74 +147,78 @@ macro_rules! impl_transitive_cast {
241147
///
242148
/// unsafe impl Upcast<B> for A {
243149
/// unsafe fn upcast_ptr(this: *const Self) -> *const B {
244-
/// let b = B {
245-
/// value: unsafe { (*this).value }
246-
/// };
247-
/// &b as *const B
150+
/// unsafe { &(*this).parent }
248151
/// }
249152
///
250153
/// unsafe fn from_base_ptr(base: *const B) -> *const Self {
251-
/// let this = A {
252-
/// value: unsafe { (*base).value }
253-
/// };
254-
/// &this as *const Self
154+
/// std::ptr::null() // Not needed for this example
255155
/// }
256156
///
257157
/// }
258158
///
259159
/// unsafe impl Upcast<C> for B {
260160
/// unsafe fn upcast_ptr(this: *const Self) -> *const C {
261-
/// let c = C {
262-
/// value: unsafe { (*this).value }
263-
/// };
264-
/// &c as *const C
161+
/// unsafe { &(*this).parent }
265162
/// }
266163
///
267164
/// unsafe fn from_base_ptr(base: *const C) -> *const Self {
268-
/// let this = B {
269-
/// value: unsafe { (*base).value }
270-
/// };
271-
/// &this as *const Self
165+
/// std::ptr::null()
272166
/// }
273167
///
274168
/// }
275169
///
276170
/// unsafe impl Upcast<D> for C {
277171
/// unsafe fn upcast_ptr(this: *const Self) -> *const D {
278-
/// let d = D {
279-
/// value: unsafe { (*this).value }
280-
/// };
281-
/// &d as *const D
172+
/// unsafe { &(*this).parent }
282173
/// }
283174
///
284175
/// unsafe fn from_base_ptr(base: *const D) -> *const Self {
285-
/// let this = C {
286-
/// value: unsafe { (*base).value }
287-
/// };
288-
/// &this as *const Self
176+
/// std::ptr::null()
289177
/// }
290178
///
291179
/// }
292180
///
293-
/// chain_cast!(A, B, C, D);
181+
/// impl_transitive_cast!(A, B, C, D);
294182
///
295183
/// # // Note that we need a fake main function for doc tests to build.
296184
/// # fn main() {
297185
/// # cxx_qt::init_crate!(cxx_qt);
298-
/// # let a = A { value: 25 };
299-
/// # assert_eq!(Upcast::<B>::upcast(&a).value, 25);
300-
/// # assert_eq!(Upcast::<C>::upcast(&a).value, 25);
186+
/// #
187+
/// # let a = A {
188+
/// # parent: B {
189+
/// # parent: C {
190+
/// # parent: D {
191+
/// # value: 25
192+
/// # }
193+
/// # }
194+
/// # }
195+
/// # };
301196
/// # assert_eq!(Upcast::<D>::upcast(&a).value, 25);
302197
/// # }
303198
/// ```
304199
#[macro_export]
305-
macro_rules! chain_cast {
200+
macro_rules! impl_transitive_cast {
306201
($first:ty, $second:ty, $third:ty) => {
307-
$crate::impl_transitive_cast!($first, $second, $third);
202+
// $crate::impl_transitive_cast!($first, $second, $third);
203+
unsafe impl ::cxx_qt::casting::Upcast<$third> for $first {
204+
unsafe fn upcast_ptr(this: *const Self) -> *const $third {
205+
let base = <Self as Upcast<$second>>::upcast_ptr(this);
206+
<$second as Upcast<$third>>::upcast_ptr(base)
207+
}
208+
209+
unsafe fn from_base_ptr(base: *const $third) -> *const Self {
210+
let base = <$second as Upcast<$third>>::from_base_ptr(base);
211+
if base.is_null() {
212+
std::ptr::null()
213+
} else {
214+
<Self as Upcast<$second>>::from_base_ptr(base)
215+
}
216+
}
217+
}
308218
};
309219

310220
($first:ty, $second:ty, $third:ty, $($rest:ty),*) => {
311-
$crate::impl_transitive_cast!($first, $second, $third);
312-
chain_cast!($first, $third, $($rest),*);
221+
impl_transitive_cast!($first, $second, $third);
222+
impl_transitive_cast!($first, $third, $($rest),*);
313223
};
314224
}

examples/qml_features/rust/src/custom_base_class.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,10 @@ use crate::custom_base_class::qobject::{
277277
AbstractBaseClass, CustomBaseClass, QAbstractListModel, QObject,
278278
};
279279
use core::pin::Pin;
280-
use cxx_qt::{casting::Upcast, chain_cast, CxxQtType, Threading};
280+
use cxx_qt::{casting::Upcast, impl_transitive_cast, CxxQtType, Threading};
281281
use cxx_qt_lib::{QByteArray, QHash, QHashPair_i32_QByteArray, QModelIndex, QVariant, QVector};
282282

283-
chain_cast!(
283+
impl_transitive_cast!(
284284
CustomBaseClass,
285285
AbstractBaseClass,
286286
QAbstractListModel,

0 commit comments

Comments
 (0)