azur 0.3.1

A no_std Rust crate that implements an executor/reactor and futures using io_uring
Documentation
use super::Op;
use crate::{
    buf::{
        IoBuf,
        PtrBuf,
    },
    future::Future,
};

pub struct Write<B: IoBuf> {
    fd: lx::RawFd,
    buf: B,
    off: u64,
}

unsafe impl<B: IoBuf> Op for Write<B> {
    type Output = (lx::Result<u32>, B);

    fn fill_sqe(&mut self, sqe: &mut lx::io_uring_sqe) {
        sqe.opcode = lx::IORING_OP_WRITE;
        sqe.fd = self.fd;
        sqe.off = self.off;
        sqe.addr = self.buf.as_ref().as_ptr() as u64;
        sqe.len = u32::try_from(self.buf.as_ref().len()).unwrap();
    }

    fn complete(self, ret: i32) -> Self::Output {
        // The return value of read and write operations has the type `long` internally, and it is
        // cast to an `int` when writing to the CQE (see `io_req_rw_complete` in the kernel
        // source code. It is thus possible to get values larger than `i32::MAX`.
        let ret = ret as u32;

        if let Ok(err) = lx::Error::try_from(ret) {
            return (Err(err), self.buf);
        }

        (Ok(ret), self.buf)
    }
}

pub fn write<B: IoBuf>(fd: &impl lx::AsRawFd, buf: B, off: u64) -> Future<Write<B>> {
    Future::new(Write {
        fd: fd.as_raw_fd(),
        buf,
        off,
    })
}

pub async fn write_all<B: IoBuf>(
    fd: &impl lx::AsRawFd,
    buf: B,
    mut off: u64,
) -> (lx::Result<()>, B) {
    // Make sure that the return value in the CQE does not overflow.
    let max_len = usize::try_from(u32::MAX - u32::from(lx::MAX_ERRNO)).unwrap_or(usize::MAX);

    let mut done = 0;
    let total = buf.as_ref().len();

    while done != total {
        let end = (done + max_len).min(total);

        // SAFETY: `slice_buf` lives longer than `buf`, so the guarantees from `buf` apply.
        let slice_buf = unsafe { PtrBuf::new(&buf.as_ref()[done..end]) };

        let (ret, _slice_buf) = write(fd, slice_buf, off).await;

        let n = match ret {
            Ok(n) => n,
            Err(err) => return (Err(err), buf),
        };

        done += usize::try_from(n).unwrap();

        if off != u64::MAX {
            off += u64::from(n);
        }
    }

    (Ok(()), buf)
}