//! Rustdoc's FileSystem abstraction module. //! //! On Windows this indirects IO into threads to work around performance issues //! with Defender (and other similar virus scanners that do blocking operations). //! On other platforms this is a thin shim to fs. //! //! Only calls needed to permit this workaround have been abstracted: thus //! fs::read is still done directly via the fs module; if in future rustdoc //! needs to read-after-write from a file, then it would be added to this //! abstraction. use std::fs; use std::io; use std::path::Path; use std::string::ToString; use std::sync::mpsc::Sender; macro_rules! try_err { ($e:expr, $file:expr) => { match $e { Ok(e) => e, Err(e) => return Err(E::new(e, $file)), } }; } pub trait PathError { fn new>(e: S, path: P) -> Self where S: ToString + Sized; } pub struct DocFS { sync_only: bool, errors: Option>, } impl DocFS { pub fn new(errors: Sender) -> DocFS { DocFS { sync_only: false, errors: Some(errors) } } pub fn set_sync_only(&mut self, sync_only: bool) { self.sync_only = sync_only; } pub fn close(&mut self) { self.errors = None; } pub fn create_dir_all>(&self, path: P) -> io::Result<()> { // For now, dir creation isn't a huge time consideration, do it // synchronously, which avoids needing ordering between write() actions // and directory creation. fs::create_dir_all(path) } pub fn write(&self, path: P, contents: C) -> Result<(), E> where P: AsRef, C: AsRef<[u8]>, E: PathError, { if !self.sync_only && cfg!(windows) { // A possible future enhancement after more detailed profiling would // be to create the file sync so errors are reported eagerly. let path = path.as_ref().to_path_buf(); let contents = contents.as_ref().to_vec(); let sender = self.errors.clone().expect("can't write after closing"); rayon::spawn(move || { fs::write(&path, contents).unwrap_or_else(|e| { sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| { panic!("failed to send error on \"{}\"", path.display()) }) }); }); } else { try_err!(fs::write(&path, contents), path); } Ok(()) } }