async_rs/util/
task.rs

1use async_trait::async_trait;
2use std::{
3    future::Future,
4    pin::Pin,
5    task::{Context, Poll},
6};
7
8/// A wrapper around implementation-specific tasks that implement the TaskImpl trait
9#[derive(Debug)]
10pub struct Task<I: TaskImpl>(I);
11
12impl<I: TaskImpl> Task<I> {
13    /// Cancel the task, returning data if it was alredy finished
14    pub async fn cancel(&mut self) -> Option<<Self as Future>::Output> {
15        self.0.cancel().await
16    }
17}
18
19impl<I: TaskImpl> From<I> for Task<I> {
20    fn from(task_impl: I) -> Self {
21        Self(task_impl)
22    }
23}
24
25impl<I: TaskImpl> Future for Task<I> {
26    type Output = <I as Future>::Output;
27
28    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
29        Pin::new(&mut self.0).poll(cx)
30    }
31}
32
33impl<I: TaskImpl> Drop for Task<I> {
34    fn drop(&mut self) {
35        self.0.detach();
36    }
37}
38
39/// A common interface to wait for a Task completion, let it run n the background or cancel it.
40#[async_trait]
41pub trait TaskImpl: Future + Send + Unpin + 'static {
42    /// Cancels the task and waits for it to stop running.
43    ///
44    /// Returns the task's output if it was completed just before it got canceled, or None if it
45    /// didn't complete.
46    async fn cancel(&mut self) -> Option<<Self as Future>::Output> {
47        None
48    }
49
50    /// "Detach" the task from the current context to let it run in the background.
51    ///
52    /// Note that this is automatically called when dropping the Task so that it doesn't get
53    /// canceled.
54    fn detach(&mut self)
55    where
56        Self: Sized,
57    {
58    }
59}