Repository: tokio-rs/tokio
File: tokio/src/fs/read_uring.rs (Rust)

Code before:
        let buf_len = usize::min(buf.spare_capacity_mut().len(), MAX_READ_SIZE);

        // buf_len cannot be greater than u32::MAX because MAX_READ_SIZE
        // is u32::MAX
        let mut read_len = buf_len as u32;

        // read into spare capacity
        let (size_read, r_fd, r_buf) = op_read(fd, buf, &mut offset, &mut read_len).await?;

        if size_read == 0 {
            return Ok(r_buf);
        }

        fd = r_fd;
        buf = r_buf;
    }
}

async fn small_probe_read(
    fd: OwnedFd,
    mut buf: Vec<u8>,
    offset: &mut u64,
) -> io::Result<(u32, OwnedFd, Vec<u8>)> {
    let mut read_len = PROBE_SIZE_U32;

    if buf.len() < PROBE_SIZE {
        buf.try_reserve(PROBE_SIZE)?;

        return op_read(fd, buf, offset, &mut read_len).await;
    }

    let mut temp_arr = [0; PROBE_SIZE];
    let back_bytes_len = buf.len() - PROBE_SIZE;

    temp_arr.copy_from_slice(&buf[back_bytes_len..]);

    // We're decreasing the length of the buffer and len is greater
    // than PROBE_SIZE. So we can read into the discarded length
    buf.truncate(back_bytes_len);

    let (size_read, r_fd, mut r_buf) = op_read(fd, buf, offset, &mut read_len).await?;

    r_buf.splice(back_bytes_len..back_bytes_len, temp_arr);

    Ok((size_read, r_fd, r_buf))
}

async fn op_read(
    mut fd: OwnedFd,
    mut buf: Vec<u8>,
    offset: &mut u64,

Review comment (bug):
We can handle allocation failure by error rather than panic by allocating before calling `splice`. Note that this doesn't allocate if `size_read == 0` since the capacity is guaranteed enough in that case.
```suggestion
    r_buf.try_reserve(PROBE_SIZE)?;
    r_buf.splice(back_bytes_len..back_bytes_len, temp_arr);
```

Code after:
        buf = r_buf;
    }
}

async fn small_probe_read(
    fd: OwnedFd,
    mut buf: Vec<u8>,
    offset: &mut u64,
) -> io::Result<(OwnedFd, Vec<u8>, bool)> {
    let read_len = PROBE_SIZE_U32;

    let mut temp_arr = [0; PROBE_SIZE];
    // we don't call this function if buffer's length < PROBE_SIZE
    let back_bytes_len = buf.len() - PROBE_SIZE;

    temp_arr.copy_from_slice(&buf[back_bytes_len..]);

    // We're decreasing the length of the buffer and len is greater
    // than PROBE_SIZE. So we can read into the discarded length
    buf.truncate(back_bytes_len);

    let (r_fd, mut r_buf, is_eof) = op_read(fd, buf, offset, read_len).await?;
    // If `size_read` returns zero due to reasons such as buffer's exact fit,
    // then this `try_reserve` does not perform allocation.
    r_buf.try_reserve(PROBE_SIZE)?;
    r_buf.splice(back_bytes_len..back_bytes_len, temp_arr);

    Ok((r_fd, r_buf, is_eof))
}

// Takes a amount of length to read and returns a singluar read in the buffer
//
// Returns the file descriptor, buffer and EOF reached or not
async fn op_read(
    mut fd: OwnedFd,
    mut buf: Vec<u8>,
    offset: &mut u64,
    read_len: u32,
) -> io::Result<(OwnedFd, Vec<u8>, bool)> {
    loop {
        let (res, r_fd, r_buf) = Op::read(fd, buf, read_len, *offset).await;

        match res {
            Err(e) if e.kind() == ErrorKind::Interrupted => {
                buf = r_buf;
                fd = r_fd;
            }
            Err(e) => return Err(e),
            Ok(size_read) => {
                *offset += size_read as u64;