Skip to content

Commit 0926cf7

Browse files
Add book entry and rename macro
1 parent e47b8da commit 0926cf7

File tree

8 files changed

+85
-236
lines changed

8 files changed

+85
-236
lines changed

book/src/concepts/casting.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ or a `#[base = T]` attribute. See the [attributes documentation](../bridge/attri
1515
1616
## Accessing the base class
1717

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

2121
| Self Type | Method |
@@ -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, ignore
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-lib/src/gui/qpolygon.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use crate::{QPoint, QRect, QVector};
66
use core::mem::MaybeUninit;
77
use cxx::{type_id, ExternType};
8-
use cxx_qt::Upcast;
8+
use cxx_qt::casting::Upcast;
99
use std::fmt;
1010
use std::ops::{Deref, DerefMut};
1111

@@ -193,7 +193,7 @@ impl DerefMut for QPolygon {
193193
}
194194
}
195195

196-
impl Upcast<QVector<QPoint>> for QPolygon {
196+
unsafe impl Upcast<QVector<QPoint>> for QPolygon {
197197
unsafe fn upcast_ptr(this: *const Self) -> *const QVector<QPoint> {
198198
ffi::upcast_qpolygon(this)
199199
}

crates/cxx-qt-lib/src/gui/qpolygonf.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55
use core::mem::MaybeUninit;
66
use cxx::{type_id, ExternType};
7-
use cxx_qt::Upcast;
7+
use cxx_qt::casting::Upcast;
88
use std::fmt;
99
use std::ops::{Deref, DerefMut};
1010

@@ -175,7 +175,7 @@ impl DerefMut for QPolygonF {
175175
}
176176
}
177177

178-
impl Upcast<QVector<QPointF>> for QPolygonF {
178+
unsafe impl Upcast<QVector<QPointF>> for QPolygonF {
179179
unsafe fn upcast_ptr(this: *const Self) -> *const QVector<QPointF> {
180180
ffi::upcast_qpolygonf(this)
181181
}

crates/cxx-qt/src/casting.rs

Lines changed: 62 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -106,130 +106,57 @@ 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-
}
109+
unsafe impl<T> Upcast<T> for T {
110+
unsafe fn upcast_ptr(this: *const Self) -> *const Self {
111+
this
112+
}
189113

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-
}
114+
unsafe fn from_base_ptr(base: *const T) -> *const Self {
115+
base
116+
}
117+
118+
fn upcast(&self) -> &Self {
119+
self
120+
}
201121

122+
fn upcast_mut(&mut self) -> &mut Self {
123+
self
124+
}
125+
126+
fn upcast_pin(self: Pin<&mut Self>) -> Pin<&mut Self> {
127+
self
128+
}
129+
}
202130
/// Implements transitive casting in a chain for a type and all its ancestors
203131
///
204132
/// 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!`
133+
/// `impl_transitive_cast!(A, B, C)` will implement the relationship A -> C
206134
///
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
135+
/// `impl_transitive_cast!` will implement casting between the first type and ***all*** its ancestors.
136+
/// For example, impl_transitive_cast!(A, B, C, D, E) will implement the following casts
210137
/// - A -> C
211138
/// - A -> D
212139
/// - A -> E
213140
///
214141
/// # Example
215142
///
216143
/// ```
217-
/// use cxx_qt::chain_cast;
144+
/// use cxx_qt::impl_transitive_cast;
218145
///
219146
///
220147
/// #[derive(Debug)]
221148
/// struct A {
222-
/// value: i32
149+
/// parent: B
223150
/// }
224151
///
225152
/// #[derive(Debug)]
226153
/// struct B {
227-
/// value: i32
154+
/// parent: C
228155
/// }
229156
///
230157
/// #[derive(Debug)]
231158
/// struct C {
232-
/// value: i32
159+
/// parent: D
233160
/// }
234161
///
235162
/// #[derive(Debug)]
@@ -241,74 +168,78 @@ macro_rules! impl_transitive_cast {
241168
///
242169
/// unsafe impl Upcast<B> for A {
243170
/// unsafe fn upcast_ptr(this: *const Self) -> *const B {
244-
/// let b = B {
245-
/// value: unsafe { (*this).value }
246-
/// };
247-
/// &b as *const B
171+
/// unsafe { &(*this).parent }
248172
/// }
249173
///
250174
/// 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
175+
/// std::ptr::null() // Not needed for this example
255176
/// }
256177
///
257178
/// }
258179
///
259180
/// unsafe impl Upcast<C> for B {
260181
/// unsafe fn upcast_ptr(this: *const Self) -> *const C {
261-
/// let c = C {
262-
/// value: unsafe { (*this).value }
263-
/// };
264-
/// &c as *const C
182+
/// unsafe { &(*this).parent }
265183
/// }
266184
///
267185
/// 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
186+
/// std::ptr::null()
272187
/// }
273188
///
274189
/// }
275190
///
276191
/// unsafe impl Upcast<D> for C {
277192
/// unsafe fn upcast_ptr(this: *const Self) -> *const D {
278-
/// let d = D {
279-
/// value: unsafe { (*this).value }
280-
/// };
281-
/// &d as *const D
193+
/// unsafe { &(*this).parent }
282194
/// }
283195
///
284196
/// 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
197+
/// std::ptr::null()
289198
/// }
290199
///
291200
/// }
292201
///
293-
/// chain_cast!(A, B, C, D);
202+
/// impl_transitive_cast!(A, B, C, D);
294203
///
295204
/// # // Note that we need a fake main function for doc tests to build.
296205
/// # fn main() {
297206
/// # 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);
207+
/// #
208+
/// # let a = A {
209+
/// # parent: B {
210+
/// # parent: C {
211+
/// # parent: D {
212+
/// # value: 25
213+
/// # }
214+
/// # }
215+
/// # }
216+
/// # };
301217
/// # assert_eq!(Upcast::<D>::upcast(&a).value, 25);
302218
/// # }
303219
/// ```
304220
#[macro_export]
305-
macro_rules! chain_cast {
221+
macro_rules! impl_transitive_cast {
306222
($first:ty, $second:ty, $third:ty) => {
307-
$crate::impl_transitive_cast!($first, $second, $third);
223+
// $crate::impl_transitive_cast!($first, $second, $third);
224+
unsafe impl ::cxx_qt::casting::Upcast<$third> for $first {
225+
unsafe fn upcast_ptr(this: *const Self) -> *const $third {
226+
let base = <Self as Upcast<$second>>::upcast_ptr(this);
227+
<$second as Upcast<$third>>::upcast_ptr(base)
228+
}
229+
230+
unsafe fn from_base_ptr(base: *const $third) -> *const Self {
231+
let base = <$second as Upcast<$third>>::from_base_ptr(base);
232+
if base.is_null() {
233+
std::ptr::null()
234+
} else {
235+
<Self as Upcast<$second>>::from_base_ptr(base)
236+
}
237+
}
238+
}
308239
};
309240

310241
($first:ty, $second:ty, $third:ty, $($rest:ty),*) => {
311-
$crate::impl_transitive_cast!($first, $second, $third);
312-
chain_cast!($first, $third, $($rest),*);
242+
impl_transitive_cast!($first, $second, $third);
243+
impl_transitive_cast!($first, $third, $($rest),*);
313244
};
314245
}

0 commit comments

Comments
 (0)