io_adapters/adapters/
fmt_write.rs

1use std::{fmt, io};
2
3use crate::WriteExtension;
4
5/// Adapter that enables writing through a [`fmt::Write`] to an underlying
6/// [`io::Write`].
7///
8/// # Examples
9///
10/// ```rust
11/// # use std::{fmt, str};
12/// use io_adapters::WriteExtension;
13///
14/// let mut output1 = String::new();
15/// let mut output2 = [0u8; 13]; // Or io::stdout() for example
16///
17/// my_common_writer(&mut output1).unwrap();
18/// my_common_writer(&mut output2.as_mut_slice().write_adapter()).unwrap();
19///
20/// fn my_common_writer(mut output: impl fmt::Write) -> fmt::Result {
21///     write!(output, "Hello, World!")
22/// }
23///
24/// assert_eq!(&output1, "Hello, World!");
25/// assert_eq!(str::from_utf8(&output2).unwrap(), "Hello, World!");
26/// ```
27///
28/// ## Error handling
29///
30/// Error handling is unpleasant with this adapter due to the [`fmt::Write`]
31/// interface returning a stateless [`fmt::Error`] rather than an [`io::Error`].
32/// Here is the suggested usage when unwrap doesn't cut it:
33///
34/// ```
35/// # use std::{fmt, io, str};
36/// # use io_adapters::WriteExtension;
37///
38/// let mut adapter = io::stdout().write_adapter();
39/// match (conv(&mut adapter), adapter.error) {
40///   (Ok(()), None) => {}
41///   (Ok(()), Some(_)) => unreachable!(),
42///   (Err(fmt::Error), None) => { /* Handle format error. */ }
43///   (Err(fmt::Error), Some(e)) => { /* Handle I/O error. */ }
44/// }
45///
46/// fn conv(output: impl fmt::Write) -> fmt::Result
47/// # { Ok(()) }
48/// ```
49#[derive(Debug)]
50pub struct FmtToIo<W> {
51    inner: W,
52    pub error: Option<io::Error>,
53}
54
55impl<W: io::Write> fmt::Write for FmtToIo<W> {
56    fn write_str(&mut self, s: &str) -> fmt::Result {
57        match self.inner.write_all(s.as_bytes()) {
58            Ok(()) => {
59                self.error = None;
60                Ok(())
61            }
62            Err(e) => {
63                self.error = Some(e);
64                Err(fmt::Error)
65            }
66        }
67    }
68}
69
70impl<W: io::Write> WriteExtension<FmtToIo<W>> for W {
71    type Adapter = FmtToIo<W>;
72
73    fn write_adapter(self) -> FmtToIo<W> {
74        FmtToIo {
75            inner: self,
76            error: None,
77        }
78    }
79}