Skip to content

Instantly share code, notes, and snippets.

@jakobrs
Created October 2, 2021 08:28
Show Gist options
  • Save jakobrs/d10539e40856ba297bd552d156c4a3fe to your computer and use it in GitHub Desktop.
Save jakobrs/d10539e40856ba297bd552d156c4a3fe to your computer and use it in GitHub Desktop.
use pin_project::*;
use pin_utils::*;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
async fn with_context<F, A>(f: F) -> A
where
F: for<'a, 'b> FnOnce(&'a mut Context<'b>) -> A,
{
#[pin_project]
struct WithContext<F>(Option<F>);
impl<F, A> Future for WithContext<F>
where
F: for<'a, 'b> FnOnce(&'a mut Context<'b>) -> A,
{
type Output = A;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<A> {
let f = self.project().0;
match std::mem::take(f) {
Some(f) => Poll::Ready(f(cx)),
None => panic!("WithContext polled after returning Poll::Ready"),
}
}
}
WithContext(Some(f)).await
}
// Like tokio::task::yield_now, but doesn't call the waker
async fn yields() {
struct Yields(bool);
impl Future for Yields {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
match self.0 {
false => {
self.0 = true;
//cx.waker().wake_by_ref();
Poll::Pending
}
true => Poll::Ready(()),
}
}
}
Yields(false).await
}
async fn poll_async<F>(future: Pin<&mut F>) -> Poll<F::Output>
where
F: Future,
{
with_context(|cx| future.poll(cx)).await
}
async fn poll_async_mut<F, P>(future: &mut Pin<P>) -> Poll<F::Output>
where
P: Deref<Target = F> + DerefMut,
F: Future,
{
poll_async(future.as_mut()).await
}
#[tokio::main]
async fn main() {
let sleep = tokio::time::sleep(tokio::time::Duration::from_secs(1));
pin_mut!(sleep);
loop {
let poll_res = poll_async(sleep.as_mut()).await;
match poll_res {
Poll::Ready(a) => {
println!("{:?}", a);
break;
}
Poll::Pending => {
println!("Pending");
yields().await;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment