futures-rs icon indicating copy to clipboard operation
futures-rs copied to clipboard

Proposal: Add a future that can be paused and restarted

Open notgull opened this issue 2 years ago • 0 comments

Sometimes, you'd like to temporarily suspend a future until something else happens. I propose a Pausable<F> API that allows one to render a Future as stopped.

Public API

pub trait FutureExt {
    /* ... */
    fn pausable(self) -> Pausable<F>;
}

pub struct Pausable<F> { /* ... */ }

pub struct PausableHandle { /* ... */ }

impl<F: Future> Future for Pausable<F> {
    type Output = F::Output;

    /* ... */
}

impl<F> Pausable<F> {
    pub fn pause_handle(&self) -> PausableHandle { /* ... */ }
}

impl PausableHandle {
    pub fn pause(&self) { /* ... */ }
    pub fn unpause(&self) { /* ... */ }
}

Reference Level

This would be implemented by having a SharedState struct between Pausable and PausableHandle through an Arc that looks like this:

struct SharedState {
    paused: AtomicBool,
    waker: AtomicWaker,
}

PausableHandle would then be implemented like this (ignoring atomics):

pub struct PausableHandle {
    state: Arc<SharedState>,
}

impl PausableHandle {
    pub fn pause(&self) {
        self.state.store(true);
    }

    pub fn unpause(&self) {
        self.state.store(false);
        self.waker.wake();
    }
}

Pausable<F> would then be implemented like this:

#[pin_project]
pub struct Pausable<F> {
    #[pin] 
    fut: F,
    state: Arc<SharedState>,
}

impl<F> {
    pub fn handle(&self) -> PausableHandle {
        PausableHandle { state: self.state.clone() }
    }

    // also have pause() and unpause() from the handle struct here
}

impl<F: Future> Future for Pausable<F> {
    type Item = F::Item;

    fn poll(&mut self, cx: &mut Context) -> Poll<Item> {
        if self.state.paused.load() {
            // store waker so we're woken up on unpause
            self.state.waker.register(cx.waker());
            Poll::Pending
        } else {
            self.fut.poll(cx)
        }
    }
}

notgull avatar Jul 05 '22 19:07 notgull