Skip to main content

file_engine/
handle.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use tokio_stream::wrappers::UnboundedReceiverStream;
6use tokio_util::sync::CancellationToken;
7
8use crate::error::{FileEngineError, Result};
9use crate::progress::Progress;
10
11/// Handle to a spawned operation (`copy`, `move_path`, `analyze`, `compress`,
12/// `sync`, ...). Implements `Future` so callers can simply `.await` it for
13/// the final result, and exposes a `Progress` stream + cooperative
14/// cancellation in the meantime.
15///
16/// Not used by `watch` — see design doc §9.1.
17pub struct Handle<T> {
18    pub(crate) join: tokio::task::JoinHandle<Result<T>>,
19    pub(crate) progress_rx: UnboundedReceiverStream<Progress>,
20    pub(crate) cancel_token: CancellationToken,
21}
22
23impl<T> Handle<T> {
24    pub fn progress(&mut self) -> &mut UnboundedReceiverStream<Progress> {
25        &mut self.progress_rx
26    }
27
28    pub fn cancel(&self) {
29        self.cancel_token.cancel();
30    }
31}
32
33impl<T> Future for Handle<T> {
34    type Output = Result<T>;
35
36    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
37        let this = self.get_mut();
38        match Pin::new(&mut this.join).poll(cx) {
39            Poll::Ready(Ok(result)) => Poll::Ready(result),
40            Poll::Ready(Err(join_err)) => Poll::Ready(Err(FileEngineError::Io {
41                path: Default::default(),
42                source: std::io::Error::other(join_err),
43            })),
44            Poll::Pending => Poll::Pending,
45        }
46    }
47}