tokio/io/uring/
write.rs

1use crate::io::blocking;
2use crate::io::uring::utils::ArcFd;
3use crate::runtime::driver::op::{CancelData, Cancellable, Completable, CqeResult, Op};
4
5use io_uring::{opcode, types};
6use std::io::{self, Error};
7
8pub(crate) struct Write {
9    buf: blocking::Buf,
10    fd: ArcFd,
11}
12
13impl std::fmt::Debug for Write {
14    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15        f.debug_struct("Write")
16            .field("buf_len", &self.buf.len())
17            .field("fd", &self.fd.as_raw_fd())
18            .finish()
19    }
20}
21
22impl Completable for Write {
23    type Output = (io::Result<u32>, blocking::Buf, ArcFd);
24    fn complete(mut self, cqe: CqeResult) -> Self::Output {
25        if let Ok(n) = cqe.result.as_ref() {
26            self.buf.advance(*n as usize);
27        }
28
29        (cqe.result, self.buf, self.fd)
30    }
31
32    fn complete_with_error(self, err: Error) -> Self::Output {
33        (Err(err), self.buf, self.fd)
34    }
35}
36
37impl Cancellable for Write {
38    fn cancel(self) -> CancelData {
39        CancelData::Write(self)
40    }
41}
42
43impl Op<Write> {
44    /// Issue a write at `file_offset` from the provided `buf`. To use current file cursor, set `file_offset` to `-1` or `u64::MAX`.
45    pub(crate) fn write_at(fd: ArcFd, buf: blocking::Buf, file_offset: u64) -> Self {
46        // There is a cap on how many bytes we can write in a single uring write operation.
47        // ref: https://github.com/axboe/liburing/discussions/497
48        let len = u32::try_from(buf.len()).unwrap_or(u32::MAX);
49
50        let ptr = buf.bytes().as_ptr();
51
52        let sqe = opcode::Write::new(types::Fd(fd.as_raw_fd()), ptr, len)
53            .offset(file_offset)
54            .build();
55
56        // SAFETY: parameters of the entry, such as `fd` and `buf`, are valid
57        // until this operation completes.
58        unsafe { Op::new(sqe, Write { buf, fd }) }
59    }
60}