more efficent File::read_buf impl for windows and unix

This commit is contained in:
DrMeepster 2021-05-08 22:04:38 -07:00
parent 146b396f21
commit 5a97090b04
10 changed files with 93 additions and 12 deletions

View File

@ -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()

View File

@ -448,6 +448,15 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
}
}
pub(crate) fn default_read_buf<F>(read: F, buf: &mut ReadBuf<'_>) -> Result<()>
where
F: FnOnce(&mut [u8]) -> Result<usize>,
{
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`.

View File

@ -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;

View File

@ -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<usize> {
self.0.write(buf)
}

View File

@ -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<usize> {
let ret = cvt(unsafe {
libc::write(

View File

@ -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<usize> {
self.0.write(buf)
}

View File

@ -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<usize> {
self.0
}

View File

@ -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<usize> {
self.write_vectored(&[IoSlice::new(buf)])
}

View File

@ -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<usize> {
self.handle.write(buf)
}

View File

@ -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(), <c::DWORD>::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],