Skip to content

Commit 5d1f561

Browse files
authored
Merge pull request #92 from ratijas/futures
Futures: typos, code style, docs
2 parents 260d03d + 396c671 commit 5d1f561

File tree

1 file changed

+44
-20
lines changed

1 file changed

+44
-20
lines changed

qmetaobject/src/future.rs

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ use std::future::Future;
33
use std::os::raw::c_void;
44
use std::pin::Pin;
55

6-
static QTWAKERVTABLE: std::task::RawWakerVTable = unsafe {
6+
static QT_WAKER_VTABLE: std::task::RawWakerVTable = unsafe {
77
std::task::RawWakerVTable::new(
88
|s: *const ()| {
99
std::task::RawWaker::new(
1010
cpp!([s as "Waker*"] -> *const() as "Waker*" {
11-
s->ref++;
11+
s->refs++;
1212
return s;
1313
}),
14-
&QTWAKERVTABLE,
14+
&QT_WAKER_VTABLE,
1515
)
1616
},
1717
|s: *const ()| {
@@ -34,35 +34,59 @@ static QTWAKERVTABLE: std::task::RawWakerVTable = unsafe {
3434
};
3535

3636
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.
3740
struct Waker : QObject {
38-
public:
41+
/// Wrapped Rust's Future as a dynamic trait object.
3942
TraitObject future;
43+
/// Guard against redundant processing of multiple consecutive wake-up calls.
4044
bool woken = false;
45+
/// Guard against polling a future after it has been completed.
4146
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+
4353
void customEvent(QEvent *e) override {
4454
Q_UNUSED(e);
4555
woken = false;
4656
// 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" {
5064
poll_with_qt_waker(this, Pin::new_unchecked(&mut *future))
5165
});
52-
if (completed) deref();
66+
if (completed) {
67+
deref();
68+
}
5369
}
70+
5471
void deref() {
55-
if (!--ref) {
72+
if (!--refs) {
5673
deleteLater();
5774
}
5875
}
76+
5977
void wake() {
60-
if (woken) return;
78+
if (woken) {
79+
return;
80+
}
6181
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.
6285
QApplication::postEvent(this, new QEvent(QEvent::User));
6386
}
87+
6488
~Waker() {
65-
rust!(QtDestroyFuture [future : *mut dyn Future<Output=()> as "TraitObject"] {
89+
rust!(QtDestroyFuture [future: *mut dyn Future<Output=()> as "TraitObject"] {
6690
std::mem::drop(Box::from_raw(future))
6791
});
6892
}
@@ -81,18 +105,16 @@ pub fn execute_async(f: impl Future<Output = ()> + 'static) {
81105
let f = Box::into_raw(Box::new(f)) as *mut dyn Future<Output = ()>;
82106
unsafe {
83107
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);
88109
});
89110
poll_with_qt_waker(waker, Pin::new_unchecked(&mut *f));
90111
}
91112
}
92113

114+
// SAFETY: caller must ensure that given future hasn't returned Poll::Ready earlier.
93115
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);
96118
let waker = std::task::Waker::from_raw(waker);
97119
let mut context = std::task::Context::from_waker(&waker);
98120
future.poll(&mut context).is_ready()
@@ -103,9 +125,11 @@ unsafe fn poll_with_qt_waker(waker: *const (), future: Pin<&mut dyn Future<Outpu
103125
/// The arguments of the signal need to implement `Clone`, and the Output of the future is a tuple
104126
/// containing the arguments of the signal (or the empty tuple if there are none.)
105127
///
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.
107131
///
108-
/// This is unsafe for the same reason that connections::connect is unsafe.
132+
/// [`connections::connect`]: ../connections/fn.connect.html
109133
pub unsafe fn wait_on_signal<Args: SignalArgArrayToTuple>(
110134
sender: *const c_void,
111135
signal: crate::connections::CppSignal<Args>,

0 commit comments

Comments
 (0)