tokio/io/uring/
write.rs

1use crate::{
2    runtime::driver::op::{CancelData, Cancellable, Completable, CqeResult, Op},
3    util::as_ref::OwnedBuf,
4};
5use io_uring::{opcode, types};
6use std::{
7    io,
8    os::fd::{AsRawFd, OwnedFd},
9};
10
11#[derive(Debug)]
12pub(crate) struct Write {
13    buf: OwnedBuf,
14    fd: OwnedFd,
15}
16
17impl Completable for Write {
18    type Output = (u32, OwnedBuf, OwnedFd);
19    fn complete(self, cqe: CqeResult) -> io::Result<Self::Output> {
20        Ok((cqe.result?, self.buf, self.fd))
21    }
22}
23
24impl Cancellable for Write {
25    fn cancel(self) -> CancelData {
26        CancelData::Write(self)
27    }
28}
29
30impl Op<Write> {
31    /// Issue a write that starts at `buf_offset` within `buf` and writes some bytes
32    /// into `file` at `file_offset`.
33    pub(crate) fn write_at(
34        fd: OwnedFd,
35        buf: OwnedBuf,
36        buf_offset: usize,
37        file_offset: u64,
38    ) -> io::Result<Self> {
39        // There is a cap on how many bytes we can write in a single uring write operation.
40        // ref: https://github.com/axboe/liburing/discussions/497
41        let len = u32::try_from(buf.as_ref().len() - buf_offset).unwrap_or(u32::MAX);
42
43        let ptr = buf.as_ref()[buf_offset..buf_offset + len as usize].as_ptr();
44
45        let sqe = opcode::Write::new(types::Fd(fd.as_raw_fd()), ptr, len)
46            .offset(file_offset)
47            .build();
48
49        // SAFETY: parameters of the entry, such as `fd` and `buf`, are valid
50        // until this operation completes.
51        let op = unsafe { Op::new(sqe, Write { buf, fd }) };
52        Ok(op)
53    }
54}