@@ -3,15 +3,15 @@ use std::future::Future;
3
3
use std:: os:: raw:: c_void;
4
4
use std:: pin:: Pin ;
5
5
6
- static QTWAKERVTABLE : std:: task:: RawWakerVTable = unsafe {
6
+ static QT_WAKER_VTABLE : std:: task:: RawWakerVTable = unsafe {
7
7
std:: task:: RawWakerVTable :: new (
8
8
|s : * const ( ) | {
9
9
std:: task:: RawWaker :: new (
10
10
cpp ! ( [ s as "Waker*" ] -> * const ( ) as "Waker*" {
11
- s->ref ++;
11
+ s->refs ++;
12
12
return s;
13
13
} ) ,
14
- & QTWAKERVTABLE ,
14
+ & QT_WAKER_VTABLE ,
15
15
)
16
16
} ,
17
17
|s : * const ( ) | {
@@ -34,35 +34,59 @@ static QTWAKERVTABLE: std::task::RawWakerVTable = unsafe {
34
34
} ;
35
35
36
36
cpp ! { {
37
+ /// Special QObject subclass to glue together internals of Rust's futures and Qt's events.
38
+ /// It's lifetime is determined through reference counting, and its lifecycle is based on
39
+ /// Qt's QObject rather than C++ RAII.
37
40
struct Waker : QObject {
38
- public :
41
+ /// Wrapped Rust's Future as a dynamic trait object.
39
42
TraitObject future;
43
+ /// Guard against redundant processing of multiple consecutive wake-up calls.
40
44
bool woken = false ;
45
+ /// Guard against polling a future after it has been completed.
41
46
bool completed = false ;
42
- QAtomicInt ref = 0 ;
47
+ /// Reference counter.
48
+ QAtomicInt refs = 0 ;
49
+
50
+ // start with refs count of 1, because caller gets the ownership.
51
+ Waker ( TraitObject f) : future( f) , refs( 1 ) { }
52
+
43
53
void customEvent( QEvent * e) override {
44
54
Q_UNUSED ( e) ;
45
55
woken = false ;
46
56
// future must not be polled after it returned `Poll::Ready`
47
- if ( completed) return ;
48
- completed = rust!( ProcessQtEvent [ this: * const ( ) as "Waker*" ,
49
- future : * mut dyn Future <Output =( ) > as "TraitObject" ] -> bool as "bool" {
57
+ if ( completed) {
58
+ return ;
59
+ }
60
+ completed = rust!( ProcessQtEvent [
61
+ this: * const ( ) as "Waker*" ,
62
+ future: * mut dyn Future <Output =( ) > as "TraitObject"
63
+ ] -> bool as "bool" {
50
64
poll_with_qt_waker( this, Pin :: new_unchecked( & mut * future) )
51
65
} ) ;
52
- if ( completed) deref( ) ;
66
+ if ( completed) {
67
+ deref( ) ;
68
+ }
53
69
}
70
+
54
71
void deref( ) {
55
- if ( !--ref ) {
72
+ if ( !--refs ) {
56
73
deleteLater( ) ;
57
74
}
58
75
}
76
+
59
77
void wake( ) {
60
- if ( woken) return ;
78
+ if ( woken) {
79
+ return ;
80
+ }
61
81
woken = true ;
82
+ // This line results in invocation of customEvent(QEvent*) method above.
83
+ // Note that object may be waken multiple times before the wake up call
84
+ // actually gets proceeded by the Qt's event loop.
62
85
QApplication :: postEvent( this, new QEvent ( QEvent :: User ) ) ;
63
86
}
87
+
64
88
~Waker ( ) {
65
- rust!( QtDestroyFuture [ future : * mut dyn Future <Output =( ) > as "TraitObject" ] {
89
+ rust!( QtDestroyFuture [ future: * mut dyn Future <Output =( ) > as "TraitObject" ] {
66
90
std:: mem:: drop( Box :: from_raw( future) )
67
91
} ) ;
68
92
}
@@ -81,18 +105,16 @@ pub fn execute_async(f: impl Future<Output = ()> + 'static) {
81
105
let f = Box :: into_raw ( Box :: new ( f) ) as * mut dyn Future < Output = ( ) > ;
82
106
unsafe {
83
107
let waker = cpp ! ( [ f as "TraitObject" ] -> * const ( ) as "Waker*" {
84
- auto w = new Waker ;
85
- w->ref++;
86
- w->future = f;
87
- return w;
108
+ return new Waker ( f) ;
88
109
} ) ;
89
110
poll_with_qt_waker ( waker, Pin :: new_unchecked ( & mut * f) ) ;
90
111
}
91
112
}
92
113
114
+ // SAFETY: caller must ensure that given future hasn't returned Poll::Ready earlier.
93
115
unsafe fn poll_with_qt_waker ( waker : * const ( ) , future : Pin < & mut dyn Future < Output = ( ) > > ) -> bool {
94
- cpp ! ( [ waker as "Waker*" ] { waker->ref ++; } ) ;
95
- let waker = std:: task:: RawWaker :: new ( waker, & QTWAKERVTABLE ) ;
116
+ cpp ! ( [ waker as "Waker*" ] { waker->refs ++; } ) ;
117
+ let waker = std:: task:: RawWaker :: new ( waker, & QT_WAKER_VTABLE ) ;
96
118
let waker = std:: task:: Waker :: from_raw ( waker) ;
97
119
let mut context = std:: task:: Context :: from_waker ( & waker) ;
98
120
future. poll ( & mut context) . is_ready ( )
@@ -103,9 +125,11 @@ unsafe fn poll_with_qt_waker(waker: *const (), future: Pin<&mut dyn Future<Outpu
103
125
/// The arguments of the signal need to implement `Clone`, and the Output of the future is a tuple
104
126
/// containing the arguments of the signal (or the empty tuple if there are none.)
105
127
///
106
- /// The future will be ready as soon as the signal is emited.
128
+ /// The future will be ready as soon as the signal is emitted.
129
+ ///
130
+ /// This is unsafe for the same reason that [`connections::connect`][] is unsafe.
107
131
///
108
- /// This is unsafe for the same reason that connections::connect is unsafe.
132
+ /// [` connections::connect`]: ../connections/fn.connect.html
109
133
pub unsafe fn wait_on_signal < Args : SignalArgArrayToTuple > (
110
134
sender : * const c_void ,
111
135
signal : crate :: connections:: CppSignal < Args > ,
0 commit comments