From 5a97090b04262f3960323d16fe062b969466994e Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sat, 8 May 2021 22:04:38 -0700 Subject: [PATCH] more efficent File::read_buf impl for windows and unix --- library/std/src/fs.rs | 6 ++++- library/std/src/io/mod.rs | 13 +++++++--- library/std/src/sys/hermit/fd.rs | 2 +- library/std/src/sys/hermit/fs.rs | 6 ++++- library/std/src/sys/unix/fd.rs | 19 ++++++++++++++- library/std/src/sys/unix/fs.rs | 6 ++++- library/std/src/sys/unsupported/fs.rs | 6 ++++- library/std/src/sys/wasi/fs.rs | 6 ++++- library/std/src/sys/windows/fs.rs | 6 ++++- library/std/src/sys/windows/handle.rs | 35 ++++++++++++++++++++++++++- 10 files changed, 93 insertions(+), 12 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 3609afa9479..55c22092c45 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -13,7 +13,7 @@ mod tests; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; +use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; @@ -624,6 +624,10 @@ impl Read for File { self.inner.read_vectored(bufs) } + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + #[inline] fn is_read_vectored(&self) -> bool { self.inner.is_read_vectored() diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index c1e3afd389d..5a1e03c7f5a 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -448,6 +448,15 @@ pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [ } } +pub(crate) fn default_read_buf(read: F, buf: &mut ReadBuf<'_>) -> Result<()> +where + F: FnOnce(&mut [u8]) -> Result, +{ + let n = read(buf.initialize_unfilled())?; + buf.add_filled(n); + Ok(()) +} + /// The `Read` trait allows for reading bytes from a source. /// /// Implementors of the `Read` trait are called 'readers'. @@ -787,9 +796,7 @@ pub trait Read { /// The default implementation delegates to `read`. #[unstable(feature = "read_buf", issue = "78485")] fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> { - let n = self.read(buf.initialize_unfilled())?; - buf.add_filled(n); - Ok(()) + default_read_buf(|b| self.read(b), buf) } /// Read the exact number of bytes required to fill `buf`. diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs index c400f5f2c2e..1179a49c22f 100644 --- a/library/std/src/sys/hermit/fd.rs +++ b/library/std/src/sys/hermit/fd.rs @@ -1,6 +1,6 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] -use crate::io::{self, Read}; +use crate::io::{self, Read, ReadBuf}; use crate::mem; use crate::sys::cvt; use crate::sys::hermit::abi; diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index be019d4435d..974c44eb8dd 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -2,7 +2,7 @@ use crate::ffi::{CStr, CString, OsString}; use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::io::{self, Error, ErrorKind}; -use crate::io::{IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::os::unix::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sys::cvt; @@ -312,6 +312,10 @@ impl File { false } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index a05e8f6c3db..93cdf89e1db 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; -use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -127,6 +127,23 @@ impl FileDesc { } } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + let ret = cvt(unsafe { + libc::read( + self.as_raw_fd(), + buf.unfilled_mut().as_mut_ptr() as *mut c_void, + cmp::min(buf.remaining(), READ_LIMIT), + ) + })?; + + // Safety: `ret` bytes were written to the initialized portion of the buffer + unsafe { + buf.assume_init(ret as usize); + } + buf.add_filled(ret as usize); + Ok(()) + } + pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { libc::write( diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index a4fff9b2e64..45eac987aa4 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -2,7 +2,7 @@ use crate::os::unix::prelude::*; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; -use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::path::{Path, PathBuf}; @@ -864,6 +864,10 @@ impl File { self.0.read_at(buf, offset) } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index 6b45e29c145..cee7295a43a 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::unsupported; @@ -206,6 +206,10 @@ impl File { self.0 } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.0 + } + pub fn write(&self, _buf: &[u8]) -> io::Result { self.0 } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 984dda8dc0b..1a3da3746ac 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -3,7 +3,7 @@ use super::fd::WasiFd; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::iter; use crate::mem::{self, ManuallyDrop}; use crate::os::raw::c_int; @@ -411,6 +411,10 @@ impl File { true } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(buf)]) } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 9859000c8d4..b258fc0478b 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -2,7 +2,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::mem; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::path::{Path, PathBuf}; @@ -420,6 +420,10 @@ impl File { self.handle.read_at(buf, offset) } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.handle.read_buf(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.handle.write(buf) } diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 21d86b00226..c3a3482f910 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -1,7 +1,7 @@ #![unstable(issue = "none", feature = "windows_handle")] use crate::cmp; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read}; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf}; use crate::mem; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, @@ -130,6 +130,39 @@ impl Handle { } } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + let mut read = 0; + let len = cmp::min(buf.remaining(), ::MAX as usize) as c::DWORD; + let res = cvt(unsafe { + c::ReadFile( + self.as_raw_handle(), + buf.unfilled_mut().as_mut_ptr() as c::LPVOID, + len, + &mut read, + ptr::null_mut(), + ) + }); + + match res { + Ok(_) => { + // Safety: `read` bytes were written to the initialized portion of the buffer + unsafe { + buf.assume_init(read as usize); + } + buf.add_filled(read as usize); + Ok(()) + } + + // The special treatment of BrokenPipe is to deal with Windows + // pipe semantics, which yields this error when *reading* from + // a pipe after the other end has closed; we interpret that as + // EOF on the pipe. + Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(()), + + Err(e) => Err(e), + } + } + pub unsafe fn read_overlapped( &self, buf: &mut [u8],