Skip to content

Commit 4bb9023

Browse files
committed
Auto merge of #27588 - cesarb:read_all, r=alexcrichton
This implements the proposed "read_exact" RFC (rust-lang/rfcs#980). Tracking issue: #27585
2 parents 2f74925 + 73e7a72 commit 4bb9023

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

src/libstd/io/error.rs

+9
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ pub enum ErrorKind {
150150
#[stable(feature = "rust1", since = "1.0.0")]
151151
Other,
152152

153+
/// An error returned when an operation could not be completed because an
154+
/// "end of file" was reached prematurely.
155+
///
156+
/// This typically means that an operation could only succeed if it read a
157+
/// particular number of bytes but only a smaller number of bytes could be
158+
/// read.
159+
#[unstable(feature = "read_exact", reason = "recently added", issue = "27585")]
160+
UnexpectedEOF,
161+
153162
/// Any I/O error not part of this list.
154163
#[unstable(feature = "io_error_internals",
155164
reason = "better expressed through extensible enums that this \

src/libstd/io/impls.rs

+21
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
3636
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
3737
(**self).read_to_string(buf)
3838
}
39+
40+
#[inline]
41+
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
42+
(**self).read_exact(buf)
43+
}
3944
}
4045
#[stable(feature = "rust1", since = "1.0.0")]
4146
impl<'a, W: Write + ?Sized> Write for &'a mut W {
@@ -95,6 +100,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
95100
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
96101
(**self).read_to_string(buf)
97102
}
103+
104+
#[inline]
105+
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
106+
(**self).read_exact(buf)
107+
}
98108
}
99109
#[stable(feature = "rust1", since = "1.0.0")]
100110
impl<W: Write + ?Sized> Write for Box<W> {
@@ -151,6 +161,17 @@ impl<'a> Read for &'a [u8] {
151161
*self = b;
152162
Ok(amt)
153163
}
164+
165+
#[inline]
166+
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
167+
if buf.len() > self.len() {
168+
return Err(Error::new(ErrorKind::UnexpectedEOF, "failed to fill whole buffer"));
169+
}
170+
let (a, b) = self.split_at(buf.len());
171+
slice::bytes::copy_memory(a, buf);
172+
*self = b;
173+
Ok(())
174+
}
154175
}
155176

156177
#[stable(feature = "rust1", since = "1.0.0")]

src/libstd/io/mod.rs

+107
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,72 @@ pub trait Read {
544544
append_to_string(buf, |b| read_to_end(self, b))
545545
}
546546

547+
/// Read the exact number of bytes required to fill `buf`.
548+
///
549+
/// This function reads as many bytes as necessary to completely fill the
550+
/// specified buffer `buf`.
551+
///
552+
/// No guarantees are provided about the contents of `buf` when this
553+
/// function is called, implementations cannot rely on any property of the
554+
/// contents of `buf` being true. It is recommended that implementations
555+
/// only write data to `buf` instead of reading its contents.
556+
///
557+
/// # Errors
558+
///
559+
/// If this function encounters an error of the kind
560+
/// `ErrorKind::Interrupted` then the error is ignored and the operation
561+
/// will continue.
562+
///
563+
/// If this function encounters an "end of file" before completely filling
564+
/// the buffer, it returns an error of the kind `ErrorKind::UnexpectedEOF`.
565+
/// The contents of `buf` are unspecified in this case.
566+
///
567+
/// If any other read error is encountered then this function immediately
568+
/// returns. The contents of `buf` are unspecified in this case.
569+
///
570+
/// If this function returns an error, it is unspecified how many bytes it
571+
/// has read, but it will never read more than would be necessary to
572+
/// completely fill the buffer.
573+
///
574+
/// # Examples
575+
///
576+
/// [`File`][file]s implement `Read`:
577+
///
578+
/// [file]: ../std/fs/struct.File.html
579+
///
580+
/// ```
581+
/// #![feature(read_exact)]
582+
/// use std::io;
583+
/// use std::io::prelude::*;
584+
/// use std::fs::File;
585+
///
586+
/// # fn foo() -> io::Result<()> {
587+
/// let mut f = try!(File::open("foo.txt"));
588+
/// let mut buffer = [0; 10];
589+
///
590+
/// // read exactly 10 bytes
591+
/// try!(f.read_exact(&mut buffer));
592+
/// # Ok(())
593+
/// # }
594+
/// ```
595+
#[unstable(feature = "read_exact", reason = "recently added", issue = "27585")]
596+
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
597+
while !buf.is_empty() {
598+
match self.read(buf) {
599+
Ok(0) => break,
600+
Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
601+
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
602+
Err(e) => return Err(e),
603+
}
604+
}
605+
if !buf.is_empty() {
606+
Err(Error::new(ErrorKind::UnexpectedEOF,
607+
"failed to fill whole buffer"))
608+
} else {
609+
Ok(())
610+
}
611+
}
612+
547613
/// Creates a "by reference" adaptor for this instance of `Read`.
548614
///
549615
/// The returned adaptor also implements `Read` and will simply borrow this
@@ -1818,6 +1884,47 @@ mod tests {
18181884
assert!(c.read_to_string(&mut v).is_err());
18191885
}
18201886

1887+
#[test]
1888+
fn read_exact() {
1889+
let mut buf = [0; 4];
1890+
1891+
let mut c = Cursor::new(&b""[..]);
1892+
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
1893+
io::ErrorKind::UnexpectedEOF);
1894+
1895+
let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..]));
1896+
c.read_exact(&mut buf).unwrap();
1897+
assert_eq!(&buf, b"1234");
1898+
c.read_exact(&mut buf).unwrap();
1899+
assert_eq!(&buf, b"5678");
1900+
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
1901+
io::ErrorKind::UnexpectedEOF);
1902+
}
1903+
1904+
#[test]
1905+
fn read_exact_slice() {
1906+
let mut buf = [0; 4];
1907+
1908+
let mut c = &b""[..];
1909+
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
1910+
io::ErrorKind::UnexpectedEOF);
1911+
1912+
let mut c = &b"123"[..];
1913+
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
1914+
io::ErrorKind::UnexpectedEOF);
1915+
// make sure the optimized (early returning) method is being used
1916+
assert_eq!(&buf, &[0; 4]);
1917+
1918+
let mut c = &b"1234"[..];
1919+
c.read_exact(&mut buf).unwrap();
1920+
assert_eq!(&buf, b"1234");
1921+
1922+
let mut c = &b"56789"[..];
1923+
c.read_exact(&mut buf).unwrap();
1924+
assert_eq!(&buf, b"5678");
1925+
assert_eq!(c, b"9");
1926+
}
1927+
18211928
#[test]
18221929
fn take_eof() {
18231930
struct R;

src/libstd/io/stdio.rs

+3
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ impl Read for Stdin {
271271
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
272272
self.lock().read_to_string(buf)
273273
}
274+
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
275+
self.lock().read_exact(buf)
276+
}
274277
}
275278

276279
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)