azur 0.3.1

A no_std Rust crate that implements an executor/reactor and futures using io_uring
Documentation
use core::mem::MaybeUninit;

use super::Op;
use crate::{
    buf::{
        IoBufMut,
        PtrBufMut,
    },
    future::Future,
};

pub struct Read<B: IoBufMut> {
    fd: lx::RawFd,
    buf: B,
    off: u64,
}

unsafe impl<B: IoBufMut> Op for Read<B> {
    type Output = (lx::Result<()>, B);

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

    fn complete(mut 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);
        }

        unsafe { self.buf.set_len(usize::try_from(ret).unwrap()) };
        (Ok(()), self.buf)
    }
}

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

pub async fn read_exact<B: IoBufMut>(
    fd: &impl lx::AsRawFd,
    mut 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.uninit_bytes().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 { PtrBufMut::new(&mut buf.uninit_bytes()[done..end] as *mut [MaybeUninit<u8>]) };

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

        if let Err(err) = ret {
            return (Err(err), buf);
        }

        let n = slice_buf.as_ref().len();

        done += n;

        if off != u64::MAX {
            off += u64::try_from(n).unwrap();
        }
    }

    (Ok(()), buf)
}