Skip to main content

fast_pull/core/
handle.rs

1use std::sync::Arc;
2use tokio::{
3    sync::watch,
4    task::{JoinError, JoinHandle},
5};
6
7#[derive(Debug)]
8pub struct SharedHandle<T> {
9    rx: watch::Receiver<Option<Result<T, Arc<JoinError>>>>,
10}
11
12impl<T> SharedHandle<T>
13where
14    T: Clone + Send + Sync + 'static,
15{
16    pub fn new(handle: JoinHandle<T>) -> Self {
17        let (tx, rx) = watch::channel(None);
18        tokio::spawn(async move {
19            let _ = tx.send(Some(handle.await.map_err(Arc::from)));
20        });
21        Self { rx }
22    }
23
24    /// # Panics
25    /// 当用于等待任务完成的后台线程意外退出时报错
26    ///
27    /// # Errors
28    /// 当任务本身返回 `JoinError` 时,返回 `Arc<JoinError>`
29    pub async fn join(&self) -> Result<T, Arc<JoinError>> {
30        let mut rx = self.rx.clone();
31        loop {
32            let res = rx.borrow_and_update().clone();
33            if let Some(res) = res {
34                return res;
35            }
36            if rx.changed().await.is_err() {
37                #[allow(clippy::expect_used)]
38                return rx
39                    .borrow()
40                    .clone()
41                    .expect("SharedHandle background task panicked or was cancelled unexpectedly");
42            }
43        }
44    }
45}