diff --git a/std/src/fs.rs b/std/src/fs.rs index 6d1005272c603..b8e3f316bebd9 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -407,7 +407,10 @@ impl File { /// ``` #[unstable(feature = "file_buffered", issue = "none")] pub fn open_buffered>(path: P) -> io::Result> { - File::open(path).map(io::BufReader::new) + // Allocate the buffer *first* so we don't affect the filesystem otherwise. + let buffer = io::BufReader::::try_new_buffer()?; + let file = File::open(path)?; + Ok(io::BufReader::with_buffer(file, buffer)) } /// Opens a file in write-only mode. @@ -472,7 +475,10 @@ impl File { /// ``` #[unstable(feature = "file_buffered", issue = "none")] pub fn create_buffered>(path: P) -> io::Result> { - File::create(path).map(io::BufWriter::new) + // Allocate the buffer *first* so we don't affect the filesystem otherwise. + let buffer = io::BufWriter::::try_new_buffer()?; + let file = File::create(path)?; + Ok(io::BufWriter::with_buffer(file, buffer)) } /// Creates a new file in read-write mode; error if the file exists. diff --git a/std/src/io/buffered/bufreader.rs b/std/src/io/buffered/bufreader.rs index e51dde994de45..fcb3e36027bab 100644 --- a/std/src/io/buffered/bufreader.rs +++ b/std/src/io/buffered/bufreader.rs @@ -74,6 +74,14 @@ impl BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } + pub(crate) fn try_new_buffer() -> io::Result { + Buffer::try_with_capacity(DEFAULT_BUF_SIZE) + } + + pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self { + Self { inner, buf } + } + /// Creates a new `BufReader` with the specified buffer capacity. /// /// # Examples diff --git a/std/src/io/buffered/bufreader/buffer.rs b/std/src/io/buffered/bufreader/buffer.rs index 1bf84d8bef312..3df7e3971dac4 100644 --- a/std/src/io/buffered/bufreader/buffer.rs +++ b/std/src/io/buffered/bufreader/buffer.rs @@ -10,7 +10,7 @@ //! without encountering any runtime bounds checks. use crate::cmp; -use crate::io::{self, BorrowedBuf, Read}; +use crate::io::{self, BorrowedBuf, ErrorKind, Read}; use crate::mem::MaybeUninit; pub struct Buffer { @@ -36,6 +36,16 @@ impl Buffer { Self { buf, pos: 0, filled: 0, initialized: 0 } } + #[inline] + pub fn try_with_capacity(capacity: usize) -> io::Result { + match Box::try_new_uninit_slice(capacity) { + Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), + Err(_) => { + Err(io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) + } + } + } + #[inline] pub fn buffer(&self) -> &[u8] { // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and diff --git a/std/src/io/buffered/bufwriter.rs b/std/src/io/buffered/bufwriter.rs index 13516d3b961f1..c41bae2aa4e81 100644 --- a/std/src/io/buffered/bufwriter.rs +++ b/std/src/io/buffered/bufwriter.rs @@ -94,6 +94,16 @@ impl BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } + pub(crate) fn try_new_buffer() -> io::Result> { + Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| { + io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") + }) + } + + pub(crate) fn with_buffer(inner: W, buf: Vec) -> Self { + Self { inner, buf, panicked: false } + } + /// Creates a new `BufWriter` with at least the specified buffer capacity. /// /// # Examples diff --git a/std/src/lib.rs b/std/src/lib.rs index 4d93af6ea652e..b81e7c18abbb0 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -374,6 +374,7 @@ #![feature(slice_concat_trait)] #![feature(thin_box)] #![feature(try_reserve_kind)] +#![feature(try_with_capacity)] #![feature(vec_into_raw_parts)] // tidy-alphabetical-end //