mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Implement read_exact for the Read trait
This implements the proposed "read_exact" RFC (https://github.com/rust-lang/rfcs/pull/980).
This commit is contained in:
parent
ef04b07239
commit
ff81920f03
@ -147,6 +147,15 @@ pub enum ErrorKind {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
Other,
|
||||
|
||||
/// An error returned when an operation could not be completed because an
|
||||
/// "end of file" was reached prematurely.
|
||||
///
|
||||
/// This typically means that an operation could only succeed if it read a
|
||||
/// particular number of bytes but only a smaller number of bytes could be
|
||||
/// read.
|
||||
#[unstable(feature = "read_exact", reason = "recently added")]
|
||||
UnexpectedEOF,
|
||||
|
||||
/// Any I/O error not part of this list.
|
||||
#[unstable(feature = "io_error_internals",
|
||||
reason = "better expressed through extensible enums that this \
|
||||
|
@ -38,6 +38,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
(**self).read_to_string(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
(**self).read_exact(buf)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, W: Write + ?Sized> Write for &'a mut W {
|
||||
@ -97,6 +102,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
(**self).read_to_string(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
(**self).read_exact(buf)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W: Write + ?Sized> Write for Box<W> {
|
||||
@ -153,6 +163,17 @@ impl<'a> Read for &'a [u8] {
|
||||
*self = b;
|
||||
Ok(amt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
if buf.len() > self.len() {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEOF, "failed to fill whole buffer"));
|
||||
}
|
||||
let (a, b) = self.split_at(buf.len());
|
||||
slice::bytes::copy_memory(a, buf);
|
||||
*self = b;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -315,6 +315,72 @@ pub trait Read {
|
||||
append_to_string(buf, |b| read_to_end(self, b))
|
||||
}
|
||||
|
||||
/// Read the exact number of bytes required to fill `buf`.
|
||||
///
|
||||
/// This function reads as many bytes as necessary to completely fill the
|
||||
/// specified buffer `buf`.
|
||||
///
|
||||
/// No guarantees are provided about the contents of `buf` when this
|
||||
/// function is called, implementations cannot rely on any property of the
|
||||
/// contents of `buf` being true. It is recommended that implementations
|
||||
/// only write data to `buf` instead of reading its contents.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If this function encounters an error of the kind
|
||||
/// `ErrorKind::Interrupted` then the error is ignored and the operation
|
||||
/// will continue.
|
||||
///
|
||||
/// If this function encounters an "end of file" before completely filling
|
||||
/// the buffer, it returns an error of the kind `ErrorKind::UnexpectedEOF`.
|
||||
/// The contents of `buf` are unspecified in this case.
|
||||
///
|
||||
/// If any other read error is encountered then this function immediately
|
||||
/// returns. The contents of `buf` are unspecified in this case.
|
||||
///
|
||||
/// If this function returns an error, it is unspecified how many bytes it
|
||||
/// has read, but it will never read more than would be necessary to
|
||||
/// completely fill the buffer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`File`][file]s implement `Read`:
|
||||
///
|
||||
/// [file]: ../std/fs/struct.File.html
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(read_exact)]
|
||||
/// use std::io;
|
||||
/// use std::io::prelude::*;
|
||||
/// use std::fs::File;
|
||||
///
|
||||
/// # fn foo() -> io::Result<()> {
|
||||
/// let mut f = try!(File::open("foo.txt"));
|
||||
/// let mut buffer = [0; 10];
|
||||
///
|
||||
/// // read exactly 10 bytes
|
||||
/// try!(f.read_exact(&mut buffer));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "read_exact", reason = "recently added")]
|
||||
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
|
||||
while !buf.is_empty() {
|
||||
match self.read(buf) {
|
||||
Ok(0) => break,
|
||||
Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
if !buf.is_empty() {
|
||||
Err(Error::new(ErrorKind::UnexpectedEOF,
|
||||
"failed to fill whole buffer"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a "by reference" adaptor for this instance of `Read`.
|
||||
///
|
||||
/// The returned adaptor also implements `Read` and will simply borrow this
|
||||
@ -1556,6 +1622,47 @@ mod tests {
|
||||
assert!(c.read_to_string(&mut v).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_exact() {
|
||||
let mut buf = [0; 4];
|
||||
|
||||
let mut c = Cursor::new(&b""[..]);
|
||||
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
|
||||
io::ErrorKind::UnexpectedEOF);
|
||||
|
||||
let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..]));
|
||||
c.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"1234");
|
||||
c.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"5678");
|
||||
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
|
||||
io::ErrorKind::UnexpectedEOF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_exact_slice() {
|
||||
let mut buf = [0; 4];
|
||||
|
||||
let mut c = &b""[..];
|
||||
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
|
||||
io::ErrorKind::UnexpectedEOF);
|
||||
|
||||
let mut c = &b"123"[..];
|
||||
assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(),
|
||||
io::ErrorKind::UnexpectedEOF);
|
||||
// make sure the optimized (early returning) method is being used
|
||||
assert_eq!(&buf, &[0; 4]);
|
||||
|
||||
let mut c = &b"1234"[..];
|
||||
c.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"1234");
|
||||
|
||||
let mut c = &b"56789"[..];
|
||||
c.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"5678");
|
||||
assert_eq!(c, b"9");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn take_eof() {
|
||||
struct R;
|
||||
|
@ -271,6 +271,9 @@ impl Read for Stdin {
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
self.lock().read_to_string(buf)
|
||||
}
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
self.lock().read_exact(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
Loading…
Reference in New Issue
Block a user