unegare
unegare

Reputation: 2579

How to make Future counter?

I'm willing to impl a simple Future counter, but smth goes decidedly wrong about it. Without any use of Context the following programme would just block forever;

use std::future::Future;
use std::task::{Poll, Context};
use std::pin::Pin;
use futures::executor::block_on;

struct MyStruct {
    counter: u32
}

impl Future for MyStruct {
    type Output = String;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.counter == 5 {
            Poll::Ready(self.counter.to_string())
        } else {
            unsafe {
                Pin::get_unchecked_mut(self).counter += 1;
            }
//            cx.waker().wake();
            Poll::Pending
        }
    }
}

fn main() {
    let ms = MyStruct{counter: 0};
    block_on(ms);
}

I imagine that I have to postpone somehow a call of Waker, but it's not that straightforward. So I wonder, how to wake it in the most simple form?

Upvotes: 0

Views: 110

Answers (1)

kmdreko
kmdreko

Reputation: 60457

You can call .wake_by_ref(). Waking the waker will tell the executor that is handling the Future to be .poll()'d again:

impl Future for MyStruct {
    type Output = String;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.counter == 5 {
            Poll::Ready(self.counter.to_string())
        } else {
            unsafe {
                Pin::get_unchecked_mut(self).counter += 1;
            }
            cx.waker().wake_by_ref();
            Poll::Pending
        }
    }
}

So your implementation will always ask to be immediately re-polled. I'll note that this is logically no different than simply returning Poll::Ready("5".to_string()) on the first invocation since there's no asynchronous work being done here. Because of that, there's no reason for it to be a Future at all.

Upvotes: 1

Related Questions