base_scheduler/file_writer.rs
1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use crate::{BufferResult, Cancellation, IoBuf};
5use std::{future::Future, io};
6
7/// Scheduler-bound, sequential access to a file's writable direction. Construct through [`FileWriting`](crate::FileWriting). Operations preserve the file's shared OS cursor; separate handles do not coordinate writes through aliases.
8pub trait FileWriter: Send {
9 /// Write once at the shared cursor, returning a possibly short count and the original owner on every result. Success does not imply durability; cancellation cannot roll back a transferred prefix.
10 fn write<B: IoBuf>(
11 &mut self,
12 buffer: B,
13 cancellation: &Cancellation,
14 ) -> impl Future<Output = BufferResult<B>> + Send;
15
16 /// Write once at an explicit offset, requiring the offset to fit in `i64`. Unix implementations leave the shared cursor unchanged; Windows implementations may use `seek_write`, which changes it. The handle maintains no private cursor.
17 fn write_at<B: IoBuf>(
18 &mut self,
19 buffer: B,
20 offset: u64,
21 cancellation: &Cancellation,
22 ) -> impl Future<Output = BufferResult<B>> + Send;
23
24 /// Write the entire initialized range in order, returning its length and original owner. Partial writes advance an owned view without copying. A nonempty zero-progress write is `WriteZero`; failure may follow a transferred prefix.
25 fn write_all<B: IoBuf>(
26 &mut self,
27 buffer: B,
28 cancellation: &Cancellation,
29 ) -> impl Future<Output = BufferResult<B>> + Send {
30 async move {
31 let length = buffer.as_ref().len();
32 let (mut result, remaining) = self.write(buffer.slice(..), cancellation).await;
33 let mut buffer = remaining.into_inner();
34 let mut written = 0;
35 loop {
36 match result {
37 Err(error) => return (Err(error), buffer),
38 Ok(count) => {
39 written += count;
40 if written == length {
41 return (Ok(written), buffer);
42 }
43 if count == 0 {
44 return (
45 Err(io::Error::from(io::ErrorKind::WriteZero).into()),
46 buffer,
47 );
48 }
49 }
50 }
51 let (next, remaining) = self.write(buffer.slice(written..), cancellation).await;
52 buffer = remaining.into_inner();
53 result = next;
54 }
55 }
56 }
57
58 /// Await admission separately from collecting the original owner. Accepted work can complete independently of polling the returned future. The fallback completes the ordinary operation before returning; backends can admit independently progressing work earlier. Pre-cancellation rejects admission and returns the unchanged owner.
59 fn write_submit<B: IoBuf>(
60 &mut self,
61 buffer: B,
62 cancellation: &Cancellation,
63 ) -> impl Future<
64 Output = Result<
65 impl Future<Output = BufferResult<B>> + Send + 'static,
66 (crate::OperationError, B),
67 >,
68 > + Send {
69 async move {
70 if let Err(error) = cancellation.check() {
71 return Err((error.into(), buffer));
72 }
73 let result = self.write(buffer, cancellation).await;
74 Ok(async move { result })
75 }
76 }
77
78 /// Await admission separately from collecting the original owner. Accepted work can complete independently of polling the returned future. The fallback completes the ordinary operation before returning; backends can admit independently progressing work earlier. Pre-cancellation rejects admission and returns the unchanged owner.
79 fn write_at_submit<B: IoBuf>(
80 &mut self,
81 buffer: B,
82 offset: u64,
83 cancellation: &Cancellation,
84 ) -> impl Future<
85 Output = Result<
86 impl Future<Output = BufferResult<B>> + Send + 'static,
87 (crate::OperationError, B),
88 >,
89 > + Send {
90 async move {
91 if let Err(error) = cancellation.check() {
92 return Err((error.into(), buffer));
93 }
94 let result = self.write_at(buffer, offset, cancellation).await;
95 Ok(async move { result })
96 }
97 }
98
99 /// Stop admission and await accepted operation retirement without cancellation. Repeated close is safe; dropping a pending close is not a retirement barrier. This does not synchronize or close the underlying file. Drop the retired handle before exclusive file close.
100 fn close(&mut self) -> impl Future<Output = io::Result<()>> + Send;
101}