Last active
November 29, 2022 20:12
-
-
Save gftea/0a8e23dac310b55d88a70aeaabfc6c0a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use futures::{ | |
task::{waker_ref, ArcWake}, // to create `context` from type implements ArcWake trait | |
FutureExt, // to use `Future::boxed` method | |
}; | |
use std::{ | |
future::Future, | |
sync::Arc, | |
task::{Context, Poll}, | |
}; | |
/// rustc will do the magic below for `async` function | |
/// 1. automatically implement `Future`trait | |
/// 2. generate state machine | |
/// the `fut_top` state will be `Poll::Ready` when and only when all its dependent futures are completed. | |
/// `fut_top` is a task from executor's view. Tasks are the top-level futures that have been submitted to an executor. | |
async fn fut_top() { | |
println!("poll top future"); | |
let fake = FakeFuture; | |
// rustc do the magic below for `await`, | |
// 1. the generated state machine of `fut_top` will depend on `fake` future state | |
// 2. when we poll `fut_top`, it will poll `fake` future | |
fake.await; | |
} | |
struct FakeFuture; | |
impl Future for FakeFuture { | |
type Output = (); | |
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | |
static mut SWITCH: bool = false; // pretend to be pending at the beginning | |
println!("poll fake future"); | |
// We are only to demo how the returned state impact the state machine. | |
unsafe { | |
if SWITCH == false { | |
SWITCH = true; | |
return Poll::Pending; | |
} | |
} | |
return Poll::Ready(()); | |
} | |
} | |
fn run(f: impl Future<Output = ()> + Send + 'static) { | |
// ------------------------------------------------------------------------ | |
// To drive future to completion, we only need to call `poll`. | |
// But, in order to satisfy the `poll` interface, we need to create a `context` object. | |
// We are not going to use context object at all, so just create a Dummy Task type, | |
// and utilize `futures` helper functions to create a context object from it. | |
struct DummyTask; | |
impl ArcWake for DummyTask { | |
fn wake_by_ref(arc_self: &Arc<Self>) { | |
todo!() | |
} | |
} | |
let task = Arc::new(DummyTask); | |
let waker = waker_ref(&task); | |
let context = &mut Context::from_waker(&*waker); | |
// ------------------------------------------------------------------------ | |
// drive future to completion | |
let mut f = f.boxed(); | |
while let Poll::Pending = f.as_mut().poll(context) { | |
println!("pending..."); | |
} | |
} | |
fn main() { | |
let f = fut_top(); // future is lazy which means no execution occurs here | |
println!("start to drive future!"); | |
run(f); | |
println!("future completed!"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment