use std::{
fmt,
io::{self, Write},
};
pub type W = std::io::Stderr;
pub fn writer() -> W {
std::io::stderr()
}
pub struct WriteCleanup<W, F, E>
where
W: Write,
F: Fn(&mut W) -> Result<(), E>,
E: fmt::Display,
{
writer: W,
cleanup: F,
}
impl<W, F, E> WriteCleanup<W, F, E>
where
W: Write,
F: Fn(&mut W) -> Result<(), E>,
E: fmt::Display,
{
#[inline]
pub fn new(writer: W, cleanup: F) -> Self {
WriteCleanup { writer, cleanup }
}
#[inline]
pub fn build<E2, F2: Fn(&mut W) -> Result<(), E2>>(
mut writer: W,
build: F2,
cleanup: F,
) -> Result<Self, E2> {
build(&mut writer)?;
Ok(Self::new(writer, cleanup))
}
}
impl<W, F, E> Drop for WriteCleanup<W, F, E>
where
W: Write,
F: Fn(&mut W) -> Result<(), E>,
E: fmt::Display,
{
fn drop(&mut self) {
if let Err(err) = (self.cleanup)(&mut self.writer) {
warn!("Error cleaning up terminal: {}", err);
}
}
}
impl<W, F, E> fmt::Debug for WriteCleanup<W, F, E>
where
W: Write + fmt::Debug,
F: Fn(&mut W) -> Result<(), E>,
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WriteCleanup")
.field("writer", &self.writer)
.field("cleanup", &"<closure>")
.finish()
}
}
impl<W, F, E> Write for WriteCleanup<W, F, E>
where
W: Write,
F: Fn(&mut W) -> Result<(), E>,
E: fmt::Display,
{
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.writer.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.writer.flush()
}
#[inline]
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.writer.write_vectored(bufs)
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.writer.write_all(buf)
}
#[inline]
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
self.writer.write_fmt(fmt)
}
}
#[test]
fn test_write_cleanup() -> io::Result<()> {
use std::str;
let mut buffer: Vec<u8> = Vec::new();
{
let writer = WriteCleanup::build(
&mut buffer,
|writer| write!(writer, "abc "),
|writer| write!(writer, " xyz"),
)?;
let mut writer = WriteCleanup::build(
writer,
|writer| write!(writer, "123 "),
|writer| write!(writer, " 789"),
)?;
write!(&mut writer, "Hello, World!")?;
}
let result = str::from_utf8(&buffer).unwrap();
assert_eq!(result, "abc 123 Hello, World! 789 xyz");
Ok(())
}