diff options
Diffstat (limited to 'compiler/rustc_serialize/src/opaque.rs')
-rw-r--r-- | compiler/rustc_serialize/src/opaque.rs | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 552554390..cc8d1c250 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -5,12 +5,13 @@ use std::io::{self, Write}; use std::marker::PhantomData; use std::ops::Range; use std::path::Path; +use std::path::PathBuf; // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- -pub type FileEncodeResult = Result<usize, io::Error>; +pub type FileEncodeResult = Result<usize, (PathBuf, io::Error)>; /// The size of the buffer in `FileEncoder`. const BUF_SIZE: usize = 8192; @@ -34,6 +35,9 @@ pub struct FileEncoder { // This is used to implement delayed error handling, as described in the // comment on `trait Encoder`. res: Result<(), io::Error>, + path: PathBuf, + #[cfg(debug_assertions)] + finished: bool, } impl FileEncoder { @@ -41,14 +45,18 @@ impl FileEncoder { // File::create opens the file for writing only. When -Zmeta-stats is enabled, the metadata // encoder rewinds the file to inspect what was written. So we need to always open the file // for reading and writing. - let file = File::options().read(true).write(true).create(true).truncate(true).open(path)?; + let file = + File::options().read(true).write(true).create(true).truncate(true).open(&path)?; Ok(FileEncoder { buf: vec![0u8; BUF_SIZE].into_boxed_slice().try_into().unwrap(), + path: path.as_ref().into(), buffered: 0, flushed: 0, file, res: Ok(()), + #[cfg(debug_assertions)] + finished: false, }) } @@ -63,6 +71,10 @@ impl FileEncoder { #[cold] #[inline(never)] pub fn flush(&mut self) { + #[cfg(debug_assertions)] + { + self.finished = false; + } if self.res.is_ok() { self.res = self.file.write_all(&self.buf[..self.buffered]); } @@ -74,6 +86,10 @@ impl FileEncoder { &self.file } + pub fn path(&self) -> &Path { + &self.path + } + #[inline] fn buffer_empty(&mut self) -> &mut [u8] { // SAFETY: self.buffered is inbounds as an invariant of the type @@ -97,6 +113,10 @@ impl FileEncoder { #[inline] fn write_all(&mut self, buf: &[u8]) { + #[cfg(debug_assertions)] + { + self.finished = false; + } if let Some(dest) = self.buffer_empty().get_mut(..buf.len()) { dest.copy_from_slice(buf); self.buffered += buf.len(); @@ -121,6 +141,10 @@ impl FileEncoder { /// with one instruction, so while this does in some sense do wasted work, we come out ahead. #[inline] pub fn write_with<const N: usize>(&mut self, visitor: impl FnOnce(&mut [u8; N]) -> usize) { + #[cfg(debug_assertions)] + { + self.finished = false; + } let flush_threshold = const { BUF_SIZE.checked_sub(N).unwrap() }; if std::intrinsics::unlikely(self.buffered > flush_threshold) { self.flush(); @@ -152,20 +176,25 @@ impl FileEncoder { }) } - pub fn finish(mut self) -> Result<usize, io::Error> { + pub fn finish(&mut self) -> FileEncodeResult { self.flush(); + #[cfg(debug_assertions)] + { + self.finished = true; + } match std::mem::replace(&mut self.res, Ok(())) { Ok(()) => Ok(self.position()), - Err(e) => Err(e), + Err(e) => Err((self.path.clone(), e)), } } } +#[cfg(debug_assertions)] impl Drop for FileEncoder { fn drop(&mut self) { - // Likely to be a no-op, because `finish` should have been called and - // it also flushes. But do it just in case. - self.flush(); + if !std::thread::panicking() { + assert!(self.finished); + } } } |