rust / expert
Snippet
Implementierung eines benutzerdefinierten manuellen Future-Pollers
Dieses Snippet zeigt, wie man eine Future manuell implementiert und ausführt, ohne die async/await-Syntax zu verwenden. Es konstruiert einen Dummy-Waker mithilfe einer benutzerdefinierten virtuellen Tabelle (RawWakerVTable) und pollt eine zustandsbehaftete Countdown-Future in einer manuellen Ausführungsschleife.
snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use std::future::Future;use std::pin::Pin;use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| RawWaker::new(std::ptr::null(), &VTABLE),|_| {},|_| {},|_| {},);struct CountdownFuture {count: usize,}impl Future for CountdownFuture {type Output = String;fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {if self.count == 0 {Poll::Ready("Finished!".to_string())} else {self.count -= 1;cx.waker().wake_by_ref();Poll::Pending}}}fn execute_future() -> String {let mut fut = CountdownFuture { count: 3 };let mut pinned = Pin::new(&mut fut);let raw_waker = RawWaker::new(std::ptr::null(), &VTABLE);let waker = unsafe { Waker::from_raw(raw_waker) };let mut cx = Context::from_waker(&waker);loop {match pinned.as_mut().poll(&mut cx) {Poll::Ready(result) => return result,Poll::Pending => {}}}}
Erklärung
1
static VTABLE: RawWakerVTable = ...
Defines a no-op virtual table for the custom raw waker to fulfill the task interface requirement.
2
cx.waker().wake_by_ref();
Instructs the executor that the task is ready to be polled again immediately by waking its ref.
3
let waker = unsafe { Waker::from_raw(raw_waker) };
Reconstitutes a safe Waker instance from our raw waker pointer structure.
4
loop { match pinned.as_mut().poll(&mut cx) { ... } }
Drives the future to completion by calling poll inside a standard control flow loop.