Skip to main content

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}