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

Code before:
))]
async fn read_uring(path: &Path) -> io::Result<Vec<u8>> {
    use crate::{fs::OpenOptions, runtime::driver::op::Op};
    use std::os::fd::OwnedFd;

    let file = OpenOptions::new().read(true).open(path).await?;

    let size = file
        .metadata()
        .await
        .map(|m| m.len() as usize)
        .ok()
        .unwrap_or(0);

    let mut buf = Vec::with_capacity(size);

    let mut fd: OwnedFd = file
        .try_into_std()
        .expect("unexpected in-flight operation detected")
        .into();

    let mut size_read = 0;
    let mut offset = 0;

    while size_read < size {
        let left_to_read = (size - size_read) as u32;

        let (_size_read, _fd) = Op::read(fd, &mut buf, left_to_read, offset)?.await?;

        // break if EOF reached
        if _size_read == 0 {
            break;
        }

        size_read += _size_read as usize;
        offset += _size_read as u64;

        fd = _fd;
    }

    // SAFETY:
    // 1. The buffer is initialized with `size` capacity
    // 2. the read_size is the number of bytes read from the file
    unsafe { buf.set_len(size_read as _) };

    Ok(buf)
}


Review comment (suggestion):
```suggestion
        let left_to_read = u32::try_from(size - size_read).unwrap_or(u32::MAX);
```
To properly support files bigger than 4GB.

Code after:
use crate::fs::asyncify;

use std::{io, path::Path};

/// Reads the entire contents of a file into a bytes vector.
///
/// This is an async version of [`std::fs::read`].
///
/// This is a convenience function for using [`File::open`] and [`read_to_end`]
/// with fewer imports and without an intermediate variable. It pre-allocates a
/// buffer based on the file size when available, so it is generally faster than
/// reading into a vector created with `Vec::new()`.
///
/// This operation is implemented by running the equivalent blocking operation
/// on a separate thread pool using [`spawn_blocking`].
///
/// [`File::open`]: super::File::open
/// [`read_to_end`]: crate::io::AsyncReadExt::read_to_end
/// [`spawn_blocking`]: crate::task::spawn_blocking
///
/// # Errors
///
/// This function will return an error if `path` does not already exist.
/// Other errors may also be returned according to [`OpenOptions::open`].
///
/// [`OpenOptions::open`]: super::OpenOptions::open
///
/// It will also return an error if it encounters while reading an error
/// of a kind other than [`ErrorKind::Interrupted`].
///
/// [`ErrorKind::Interrupted`]: std::io::ErrorKind::Interrupted
///
/// # io_uring support
///
/// On Linux, you can also use io_uring for executing system calls. To enable
/// io_uring, you need to specify the `--cfg tokio_unstable` flag at compile time,
/// enable the io-uring cargo feature, and set the `Builder::enable_io_uring`
/// runtime option.
///
/// Support for io_uring is currently experimental, so its behavior may change
/// or it may be removed in future versions.
///
/// # Examples
///
/// ```no_run
/// use tokio::fs;
/// use std::net::SocketAddr;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
///     let contents = fs::read("address.txt").await?;
///     let foo: SocketAddr = String::from_utf8_lossy(&contents).parse()?;
///     Ok(())
/// }
/// ```
pub async fn read(path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
    let path = path.as_ref().to_owned();

    #[cfg(all(
        tokio_unstable,
        feature = "io-uring",
        feature = "rt",
        feature = "fs",
        target_os = "linux"
    ))]
    {
        use crate::fs::read_uring;

        let handle = crate::runtime::Handle::current();
        let driver_handle = handle.inner.driver().io();
        if driver_handle.check_and_init()? {
            return read_uring(&path).await;
        }
    }

    asyncify(move || std::fs::read(path)).await
}