Skip to main content

tempest_rt/fs/
stat_file.rs

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