chiark / gitweb /
utils: Provide CookedStdout, buffered and with die on flush fail
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 1 Jun 2021 12:58:38 +0000 (13:58 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 1 Jun 2021 14:47:10 +0000 (15:47 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/utils.rs

index 4c239b3443ea1207e0e56bc5e7daf127846882d1..d4533ef39d0f82c4316ff6be660f9b2df3afcaf0 100644 (file)
@@ -731,6 +731,30 @@ impl<W:Write> Write for SigPipeWriter<W> {
 pub type RawStdout = SigPipeWriter<io::Stdout>;
 impl RawStdout { pub fn new() -> Self { SigPipeWriter(io::stdout()) } }
 
+pub struct CookedStdout(pub BufWriter<SigPipeWriter<io::Stdout>>);
+impl CookedStdout {
+  pub fn new() -> Self { Self(BufWriter::new(RawStdout::new())) }
+  fn handle_err(e: io::Error) -> ! {
+    AE::from(e).context("write stdout").end_process(12);
+  }
+  fn must_flush(&mut self) {
+    self.0.flush().unwrap_or_else(|e| Self::handle_err(e))
+  }
+}
+impl Write for CookedStdout {
+  #[throws(io::Error)]
+  fn write(&mut self, buf: &[u8]) -> usize {
+    let r = self.0.write(buf).unwrap_or_else(|e| Self::handle_err(e));
+    if buf.contains(&b'\n') { self.flush()? }
+    r
+  }
+  #[throws(io::Error)]
+  fn flush(&mut self) { self.must_flush() }
+}
+impl Drop for CookedStdout {
+  fn drop(&mut self) { self.must_flush() }
+}
+
 #[throws(fmt::Error)]
 pub fn fmt_hex(f: &mut Formatter, buf: &[u8]) {
   for v in buf { write!(f, "{:02x}", v)?; }