1use std::future::{Future, poll_fn};
27use std::io::{self, SeekFrom};
28use std::mem;
29use std::path::{Path, PathBuf};
30use std::pin::Pin;
31use std::sync::Arc;
32use std::task::{Context, Poll, ready};
33
34use moirai_pal::fs::{File as Handle, FileOpenOptions};
35
36use crate::blocking::{Abandoned, Admission, Completion};
37use crate::fs::pool;
38use crate::fs::stats::FileStats;
39
40mod fence;
41pub(in crate::fs) mod request;
42mod traits;
43
44use fence::Fence;
45use request::{Outcome, Request};
46
47type Admitting = Pin<Box<dyn Future<Output = io::Result<Admission>> + Send + Sync>>;
49
50enum State {
51 Idle,
52 Admitting(Admitting),
54 Busy(Completion<Outcome>),
56}
57
58enum Settled {
60 Absorbed,
62 EndOfFile,
64}
65
66pub struct File {
68 handle: Arc<Handle>,
69 state: State,
70 fence: Arc<Fence>,
73 unread: Vec<u8>,
76 deferred: Option<io::Error>,
78 path: PathBuf,
79 stats: FileStats,
80}
81
82impl File {
83 pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
85 Self::open_with_options(path, FileOpenOptions::read_only()).await
86 }
87
88 pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<Self> {
90 Self::open_with_options(path, FileOpenOptions::write_only()).await
91 }
92
93 pub async fn open_with_options<P: AsRef<Path>>(
95 path: P,
96 options: FileOpenOptions,
97 ) -> io::Result<Self> {
98 let path = path.as_ref().to_path_buf();
99 let target = path.clone();
100 let handle = pool()
101 .run(Abandoned::Skip, move || Handle::open_with(target, options))
102 .await??;
103 Ok(Self {
104 handle: Arc::new(handle),
105 state: State::Idle,
106 fence: Arc::default(),
107 unread: Vec::new(),
108 deferred: None,
109 path,
110 stats: FileStats::default(),
111 })
112 }
113
114 pub async fn read_to_string(&mut self) -> io::Result<String> {
116 let contents = String::from_utf8(self.read_all().await?)
117 .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;
118 Ok(contents)
119 }
120
121 pub async fn read_to_end(&mut self) -> io::Result<Vec<u8>> {
123 self.read_all().await
124 }
125
126 async fn read_all(&mut self) -> io::Result<Vec<u8>> {
127 let Outcome::Read(contents) = self
128 .perform(Request::ReadToEnd { prefix: Vec::new() })
129 .await?
130 else {
131 unreachable!("invariant: a read-to-end request yields a read outcome");
132 };
133 let contents = contents?;
134 self.stats.bytes_read += contents.len() as u64;
135 self.stats.read_operations += 1;
136 Ok(contents)
137 }
138
139 pub async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
141 let bytes_read = poll_fn(|cx| self.poll_read_into(cx, buf)).await?;
142 self.stats.bytes_read += bytes_read as u64;
143 self.stats.read_operations += 1;
144 Ok(bytes_read)
145 }
146
147 pub async fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
149 let Outcome::Wrote(written) = self
150 .perform(Request::Write {
151 data: buf.to_vec(),
152 rewind: 0,
153 })
154 .await?
155 else {
156 unreachable!("invariant: a write request yields a write outcome");
157 };
158 let bytes_written = written?;
159 self.stats.bytes_written += bytes_written as u64;
160 self.stats.write_operations += 1;
161 Ok(bytes_written)
162 }
163
164 pub async fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
169 if buf.is_empty() {
170 return Ok(());
171 }
172 let Outcome::Done(done) = self
173 .perform(Request::WriteAll {
174 data: buf.to_vec(),
175 rewind: 0,
176 })
177 .await?
178 else {
179 unreachable!("invariant: a write-all request yields a done outcome");
180 };
181 done?;
182 self.stats.bytes_written += buf.len() as u64;
183 self.stats.write_operations += 1;
184 Ok(())
185 }
186
187 pub async fn write_str(&mut self, s: &str) -> io::Result<()> {
189 self.write_all(s.as_bytes()).await
190 }
191
192 pub async fn flush(&mut self) -> io::Result<()> {
194 poll_fn(|cx| self.poll_settled(cx)).await
195 }
196
197 pub async fn sync_all(&mut self) -> io::Result<()> {
199 self.perform_unit(Request::SyncAll).await
200 }
201
202 pub async fn sync_data(&mut self) -> io::Result<()> {
204 self.perform_unit(Request::SyncData).await
205 }
206
207 async fn perform_unit(&mut self, request: Request) -> io::Result<()> {
208 let Outcome::Done(done) = self.perform(request).await? else {
209 unreachable!("invariant: a sync request yields a done outcome");
210 };
211 done
212 }
213
214 pub async fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
216 let Outcome::Sought(position) = self.perform(Request::Seek(pos)).await? else {
217 unreachable!("invariant: a seek request yields a seek outcome");
218 };
219 let new_pos = position?;
220 self.stats.seek_operations += 1;
221 Ok(new_pos)
222 }
223
224 pub async fn stream_position(&mut self) -> io::Result<u64> {
226 let Outcome::Sought(position) = self.perform(Request::Seek(SeekFrom::Current(0))).await?
227 else {
228 unreachable!("invariant: a seek request yields a seek outcome");
229 };
230 position
231 }
232
233 pub async fn metadata(&self) -> io::Result<std::fs::Metadata> {
236 self.fence.settled().await;
237 let handle = Arc::clone(&self.handle);
238 pool()
239 .run(Abandoned::Skip, move || handle.metadata())
240 .await?
241 }
242
243 pub fn path(&self) -> &Path {
245 &self.path
246 }
247
248 pub fn stats(&self) -> &FileStats {
252 &self.stats
253 }
254
255 async fn perform(&mut self, request: Request) -> io::Result<Outcome> {
259 let mut request = Some(request);
260 poll_fn(|cx| {
261 if request.is_some() {
262 ready!(self.poll_settle(cx));
263 if let Some(error) = self.deferred.take() {
264 request = None;
265 return Poll::Ready(Err(error));
266 }
267 let admission = ready!(self.poll_admission(cx))?;
268 let pending = request
269 .take()
270 .expect("invariant: the request is submitted at most once, checked above");
271 self.submit(admission, pending)?;
272 }
273 let State::Busy(completion) = &mut self.state else {
274 unreachable!(
275 "invariant: this call's request is in flight while it borrows the file"
276 );
277 };
278 let outcome = ready!(Pin::new(completion).poll(cx));
279 self.state = State::Idle;
280 Poll::Ready(outcome)
281 })
282 .await
283 }
284
285 fn submit(&mut self, admission: Admission, request: Request) -> io::Result<()> {
287 let request = match request {
288 Request::ReadToEnd { .. } => Request::ReadToEnd {
289 prefix: mem::take(&mut self.unread),
290 },
291 Request::Write { data, .. } => Request::Write {
292 data,
293 rewind: self.take_unread_len(),
294 },
295 Request::WriteAll { data, .. } => Request::WriteAll {
296 data,
297 rewind: self.take_unread_len(),
298 },
299 Request::Seek(SeekFrom::Current(offset)) => {
300 let rewind = i64::try_from(self.unread.len()).map_err(|_| {
301 io::Error::new(
302 io::ErrorKind::InvalidInput,
303 "unread bytes exceed a seek offset",
304 )
305 })?;
306 let offset = offset.checked_sub(rewind).ok_or_else(|| {
307 io::Error::new(io::ErrorKind::InvalidInput, "seek offset overflows i64")
308 })?;
309 self.unread.clear();
310 Request::Seek(SeekFrom::Current(offset))
311 }
312 Request::Seek(absolute) => {
313 self.unread.clear();
314 Request::Seek(absolute)
315 }
316 other => other,
317 };
318 let handle = Arc::clone(&self.handle);
319 let abandoned = request.abandoned();
320 let ticket = self.fence.issue();
323 let completion = admission.submit(abandoned, move || {
324 let outcome = request.run(&handle);
325 #[cfg(test)]
326 request::test_hooks::after_run();
327 drop(ticket);
328 outcome
329 })?;
330 self.state = State::Busy(completion);
331 Ok(())
332 }
333
334 fn take_unread_len(&mut self) -> u64 {
335 let rewind = self.unread.len() as u64;
336 self.unread.clear();
337 rewind
338 }
339
340 fn poll_settle(&mut self, cx: &mut Context<'_>) -> Poll<Settled> {
343 let State::Busy(completion) = &mut self.state else {
344 return Poll::Ready(Settled::Absorbed);
345 };
346 let outcome = ready!(Pin::new(completion).poll(cx));
347 self.state = State::Idle;
348 Poll::Ready(match outcome {
349 Ok(Outcome::Read(Ok(data))) if data.is_empty() => Settled::EndOfFile,
350 Ok(Outcome::Read(Ok(data))) => {
351 self.unread.extend_from_slice(&data);
352 Settled::Absorbed
353 }
354 Ok(outcome) => {
355 if let Some(error) = outcome.into_error() {
356 self.defer(error);
357 }
358 Settled::Absorbed
359 }
360 Err(error) => {
361 self.defer(error);
362 Settled::Absorbed
363 }
364 })
365 }
366
367 fn poll_settled(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
369 ready!(self.poll_settle(cx));
370 Poll::Ready(self.deferred.take().map_or(Ok(()), Err))
371 }
372
373 fn defer(&mut self, error: io::Error) {
374 if self.deferred.is_none() {
375 self.deferred = Some(error);
376 }
377 }
378
379 fn poll_admission(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<Admission>> {
380 if matches!(self.state, State::Idle) {
381 self.state = State::Admitting(Box::pin(pool().admit()));
382 }
383 let State::Admitting(admitting) = &mut self.state else {
384 unreachable!("invariant: callers settle a busy state before admission");
385 };
386 let admitted = ready!(admitting.as_mut().poll(cx));
387 self.state = State::Idle;
388 Poll::Ready(admitted)
389 }
390
391 fn poll_read_into(&mut self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
392 loop {
393 if !self.unread.is_empty() {
394 let delivered = self.unread.len().min(buf.len());
395 buf[..delivered].copy_from_slice(&self.unread[..delivered]);
396 self.unread.drain(..delivered);
397 return Poll::Ready(Ok(delivered));
398 }
399 if buf.is_empty() {
400 return Poll::Ready(Ok(0));
401 }
402 if matches!(self.state, State::Busy(_)) {
403 if let Settled::EndOfFile = ready!(self.poll_settle(cx)) {
404 return Poll::Ready(Ok(0));
405 }
406 continue;
407 }
408 if let Some(error) = self.deferred.take() {
409 return Poll::Ready(Err(error));
410 }
411 let admission = ready!(self.poll_admission(cx))?;
412 self.submit(admission, Request::Read { len: buf.len() })?;
413 }
414 }
415
416 fn poll_write_behind(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
417 if buf.is_empty() {
418 return Poll::Ready(Ok(0));
419 }
420 ready!(self.poll_settled(cx))?;
421 let admission = ready!(self.poll_admission(cx))?;
422 self.submit(
423 admission,
424 Request::WriteAll {
425 data: buf.to_vec(),
426 rewind: 0,
427 },
428 )?;
429 Poll::Ready(Ok(buf.len()))
430 }
431}