Skip to content

Commit 2c224d5

Browse files
committed
Add fmt::Write to io::Write adapter
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
1 parent c9808f8 commit 2c224d5

File tree

1 file changed

+81
-32
lines changed

1 file changed

+81
-32
lines changed

Diff for: library/std/src/io/mod.rs

+81-32
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ mod tests;
299299

300300
use crate::cmp;
301301
use crate::fmt;
302+
use crate::fmt::Debug;
302303
use crate::mem::take;
303304
use crate::ops::{Deref, DerefMut};
304305
use crate::slice;
@@ -1786,38 +1787,14 @@ pub trait Write {
17861787
/// }
17871788
/// ```
17881789
#[stable(feature = "rust1", since = "1.0.0")]
1789-
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
1790-
// Create a shim which translates a Write to a fmt::Write and saves
1791-
// off I/O errors. instead of discarding them
1792-
struct Adapter<'a, T: ?Sized + 'a> {
1793-
inner: &'a mut T,
1794-
error: Result<()>,
1795-
}
1796-
1797-
impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
1798-
fn write_str(&mut self, s: &str) -> fmt::Result {
1799-
match self.inner.write_all(s.as_bytes()) {
1800-
Ok(()) => Ok(()),
1801-
Err(e) => {
1802-
self.error = Err(e);
1803-
Err(fmt::Error)
1804-
}
1805-
}
1806-
}
1807-
}
1808-
1809-
let mut output = Adapter { inner: self, error: Ok(()) };
1810-
match fmt::write(&mut output, fmt) {
1811-
Ok(()) => Ok(()),
1812-
Err(..) => {
1813-
// check if the error came from the underlying `Write` or not
1814-
if output.error.is_err() {
1815-
output.error
1816-
} else {
1817-
Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error"))
1818-
}
1819-
}
1820-
}
1790+
fn write_fmt(mut self: &mut Self, fmt: fmt::Arguments<'_>) -> Result<()> {
1791+
let mut output = (&mut self).fmt_adapter();
1792+
fmt::write(&mut output, fmt).map_err(|_| {
1793+
output
1794+
.mut_err()
1795+
.take()
1796+
.unwrap_or(const_io_error!(ErrorKind::Uncategorized, "formatter error"))
1797+
})
18211798
}
18221799

18231800
/// Creates a "by reference" adapter for this instance of `Write`.
@@ -1848,6 +1825,78 @@ pub trait Write {
18481825
{
18491826
self
18501827
}
1828+
1829+
/// Convert an [`io::Write`](Write) to a [`FmtWriteAdapter`].
1830+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1831+
fn fmt_adapter(&mut self) -> FmtWriteAdapter<'_, Self>
1832+
where
1833+
Self: Sized,
1834+
{
1835+
FmtWriteAdapter { inner: self, error: None }
1836+
}
1837+
}
1838+
1839+
/// Adapter that enables writing through a [`fmt::Write`] to an underlying [`io::Write`](Write).
1840+
///
1841+
/// # Examples
1842+
///
1843+
/// ```rust
1844+
/// #![feature(impl_fmt_write_for_io_write)]
1845+
/// # use std::{fmt, io};
1846+
/// # use std::io::Write;
1847+
///
1848+
/// let mut output1 = String::new();
1849+
/// let mut output2 = io::stdout();
1850+
///
1851+
/// my_common_writer(&mut output1).unwrap();
1852+
/// my_common_writer(&mut output2.fmt_adapter()).unwrap();
1853+
///
1854+
/// fn my_common_writer(output: &mut impl fmt::Write) -> fmt::Result {
1855+
/// writeln!(output, "Hello World!")
1856+
/// }
1857+
/// ```
1858+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1859+
pub struct FmtWriteAdapter<'a, W: Write + ?Sized> {
1860+
inner: &'a mut W,
1861+
error: Option<Error>,
1862+
}
1863+
1864+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1865+
impl<W: Write + ?Sized> FmtWriteAdapter<'_, W> {
1866+
/// Returns a reference to the last error that occurred in this adapter.
1867+
pub fn err(&self) -> &Option<Error> {
1868+
&self.error
1869+
}
1870+
1871+
/// Returns a mutable reference to the last error that occurred in this adapter.
1872+
pub fn mut_err(&mut self) -> &mut Option<Error> {
1873+
&mut self.error
1874+
}
1875+
}
1876+
1877+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1878+
impl<W: Write + ?Sized> fmt::Write for FmtWriteAdapter<'_, W> {
1879+
fn write_str(&mut self, s: &str) -> fmt::Result {
1880+
match self.inner.write_all(s.as_bytes()) {
1881+
Ok(()) => {
1882+
self.error = None;
1883+
Ok(())
1884+
}
1885+
Err(e) => {
1886+
self.error = Some(e);
1887+
Err(fmt::Error)
1888+
}
1889+
}
1890+
}
1891+
}
1892+
1893+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1894+
impl<W: Write + ?Sized> Debug for FmtWriteAdapter<'_, W> {
1895+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1896+
let mut builder = f.debug_struct("FmtWriteAdapter");
1897+
builder.field("error", &self.error);
1898+
builder.finish()
1899+
}
18511900
}
18521901

18531902
/// The `Seek` trait provides a cursor which can be moved within a stream of

0 commit comments

Comments
 (0)