Skip to main content

tempest_rt/fs/
remove_file.rs

1//! Async file removal operation.
2
3use std::{
4    io,
5    marker::PhantomData,
6    mem::replace,
7    path::PathBuf,
8    pin::Pin,
9    task::{Context, Poll},
10};
11
12use tempest_io::{Io, OpHandle};
13
14use crate::context::{current_io, get_op_handle};
15
16enum RemoveFileState {
17    NeedsSubmit {
18        path: PathBuf,
19        handle: Option<OpHandle>,
20    },
21    InFlight {
22        handle: OpHandle,
23    },
24    Done,
25}
26
27/// Future that removes a file at a given path.
28#[must_use = "futures do nothing unless awaited"]
29pub struct RemoveFile<I: Io> {
30    state: RemoveFileState,
31    // NB: we use I as the return here, so that RemoveFile stays Unpin
32    _marker: PhantomData<fn() -> I>,
33}
34
35/// Removes the file at `path`.
36pub fn remove_file<I: Io>(path: PathBuf) -> RemoveFile<I> {
37    RemoveFile {
38        state: RemoveFileState::NeedsSubmit { path, handle: None },
39        _marker: PhantomData,
40    }
41}
42
43// NB: required because of Fd, which is Copy
44impl<I: Io> Unpin for RemoveFile<I> {}
45
46impl<I: Io> Future for RemoveFile<I> {
47    type Output = io::Result<()>;
48
49    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
50        let this = self.get_mut();
51
52        match replace(&mut this.state, RemoveFileState::Done) {
53            RemoveFileState::NeedsSubmit { path, handle } => {
54                let handle = handle.unwrap_or_else(|| unsafe { get_op_handle(cx) });
55
56                // SAFETY: we do not hold on to io outside of this function
57                let io = unsafe { current_io::<I>() };
58                match io.remove(&path, handle) {
59                    Ok(()) => {
60                        this.state = RemoveFileState::InFlight { handle };
61                        Poll::Pending
62                    }
63                    Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
64                        // io SQ is full, retry next tick
65                        this.state = RemoveFileState::NeedsSubmit {
66                            path,
67                            handle: Some(handle),
68                        };
69                        cx.waker().wake_by_ref();
70                        Poll::Pending
71                    }
72                    Err(e) => Poll::Ready(Err(e)),
73                }
74            }
75            RemoveFileState::InFlight { handle } => {
76                // SAFETY: we do not hold on to io outside of this function
77                let io = unsafe { current_io::<I>() };
78                match io.get_cqe(handle).transpose()? {
79                    Some(_) => Poll::Ready(Ok(())),
80                    None => {
81                        this.state = RemoveFileState::InFlight { handle };
82                        Poll::Pending
83                    }
84                }
85            }
86            RemoveFileState::Done => panic!("polled after completion"),
87        }
88    }
89}