Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions library/std/src/fs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,43 @@ fn test_seek_read_buf() {
check!(fs::remove_file(&filename));
}

#[test]
#[cfg(windows)]
fn test_seek_read_buf_exact() {
use crate::os::windows::fs::FileExt;

let tmpdir = tmpdir();
let filename = tmpdir.join("file_rt_io_file_test_seek_read_buf_exact.txt");
{
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
let mut file = check!(oo.open(&filename));
check!(file.write_all(b"0123456789"));
}
{
let mut file = check!(File::open(&filename));
let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
let mut buf = BorrowedBuf::from(buf.as_mut_slice());

// Exact read
check!(file.seek_read_buf_exact(buf.unfilled(), 2));
assert_eq!(buf.filled(), b"23456");
assert_eq!(check!(file.stream_position()), 7);

// Already full
check!(file.seek_read_buf_exact(buf.unfilled(), 3));
assert_eq!(check!(file.stream_position()), 7);
check!(file.seek_read_buf_exact(buf.unfilled(), 10)); // No call to seek_read()
assert_eq!(buf.filled(), b"23456");
assert_eq!(check!(file.stream_position()), 7);

// Non-empty exact read past eof fails
let err = file.seek_read_buf_exact(buf.clear().unfilled(), 6).unwrap_err();
assert_eq!(err.kind(), ErrorKind::UnexpectedEof);
assert_eq!(check!(file.stream_position()), 10);
}
check!(fs::remove_file(&filename));
}

#[test]
fn file_test_read_buf() {
let tmpdir = tmpdir();
Expand Down
56 changes: 56 additions & 0 deletions library/std/src/os/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,62 @@ pub trait FileExt {
io::default_read_buf(|b| self.seek_read(b, offset), buf)
}

/// Seeks to a given position and reads the exact number of bytes required to fill `buf`.
///
/// This is equivalent to the [`seek_read_exact`](FileExt::seek_read_exact) method, except
/// that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with
/// uninitialized buffers. The new data will be appended to any existing contents of `buf`.
///
/// Reading beyond the end of the file will always succeed without reading any bytes.
///
/// # Examples
///
#[cfg_attr(windows, doc = "```no_run")]
#[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
/// #![feature(core_io_borrowed_buf)]
/// #![feature(seek_read_exact_seek_write_all)]
///
/// use std::io;
/// use std::io::BorrowedBuf;
/// use std::fs::File;
/// use std::mem::MaybeUninit;
/// use std::os::windows::prelude::*;
///
/// fn main() -> io::Result<()> {
/// let mut file = File::open("pi.txt")?;
///
/// // Read some bytes starting from offset 2
/// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
/// let mut buf = BorrowedBuf::from(buf.as_mut_slice());
/// file.seek_read_buf_exact(buf.unfilled(), 2)?;
///
/// assert!(buf.filled().starts_with(b"1"));
///
/// Ok(())
/// }
/// ```
#[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")]
fn seek_read_buf_exact(
&self,
mut buf: BorrowedCursor<'_, u8>,
mut offset: u64,
) -> io::Result<()> {
while buf.capacity() > 0 {
let prev_written = buf.written();
match self.seek_read_buf(buf.reborrow(), offset) {
Ok(()) => {}
Err(e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
let n = buf.written() - prev_written;
offset += n as u64;
if n == 0 {
return Err(io::Error::READ_EXACT_EOF);
}
}
Ok(())
}

/// Seeks to a given position and writes a number of bytes.
///
/// Returns the number of bytes written.
Expand Down
Loading