Skip to content

Commit 6b74506

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

File tree

1 file changed

+81
-32
lines changed

1 file changed

+81
-32
lines changed

library/std/src/io/mod.rs

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

254254
use crate::cmp;
255255
use crate::fmt;
256+
use crate::fmt::Debug;
256257
use crate::mem::take;
257258
use crate::ops::{Deref, DerefMut};
258259
use crate::slice;
@@ -1688,38 +1689,14 @@ pub trait Write {
16881689
/// }
16891690
/// ```
16901691
#[stable(feature = "rust1", since = "1.0.0")]
1691-
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
1692-
// Create a shim which translates a Write to a fmt::Write and saves
1693-
// off I/O errors. instead of discarding them
1694-
struct Adapter<'a, T: ?Sized + 'a> {
1695-
inner: &'a mut T,
1696-
error: Result<()>,
1697-
}
1698-
1699-
impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
1700-
fn write_str(&mut self, s: &str) -> fmt::Result {
1701-
match self.inner.write_all(s.as_bytes()) {
1702-
Ok(()) => Ok(()),
1703-
Err(e) => {
1704-
self.error = Err(e);
1705-
Err(fmt::Error)
1706-
}
1707-
}
1708-
}
1709-
}
1710-
1711-
let mut output = Adapter { inner: self, error: Ok(()) };
1712-
match fmt::write(&mut output, fmt) {
1713-
Ok(()) => Ok(()),
1714-
Err(..) => {
1715-
// check if the error came from the underlying `Write` or not
1716-
if output.error.is_err() {
1717-
output.error
1718-
} else {
1719-
Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error"))
1720-
}
1721-
}
1722-
}
1692+
fn write_fmt(mut self: &mut Self, fmt: fmt::Arguments<'_>) -> Result<()> {
1693+
let mut output = (&mut self).fmt_adapter();
1694+
fmt::write(&mut output, fmt).map_err(|_| {
1695+
output
1696+
.mut_err()
1697+
.take()
1698+
.unwrap_or(const_io_error!(ErrorKind::Uncategorized, "formatter error"))
1699+
})
17231700
}
17241701

17251702
/// Creates a "by reference" adapter for this instance of `Write`.
@@ -1750,6 +1727,78 @@ pub trait Write {
17501727
{
17511728
self
17521729
}
1730+
1731+
/// Convert an [`io::Write`](Write) to a [`FmtWriteAdapter`].
1732+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1733+
fn fmt_adapter(&mut self) -> FmtWriteAdapter<'_, Self>
1734+
where
1735+
Self: Sized,
1736+
{
1737+
FmtWriteAdapter { inner: self, error: None }
1738+
}
1739+
}
1740+
1741+
/// Adapter that enables writing through a [`fmt::Write`] to an underlying [`io::Write`](Write).
1742+
///
1743+
/// # Examples
1744+
///
1745+
/// ```rust
1746+
/// #![feature(impl_fmt_write_for_io_write)]
1747+
/// # use std::{fmt, io};
1748+
/// # use std::io::Write;
1749+
///
1750+
/// let mut output1 = String::new();
1751+
/// let mut output2 = io::stdout();
1752+
///
1753+
/// my_common_writer(&mut output1).unwrap();
1754+
/// my_common_writer(&mut output2.fmt_adapter()).unwrap();
1755+
///
1756+
/// fn my_common_writer(output: &mut impl fmt::Write) -> fmt::Result {
1757+
/// writeln!(output, "Hello World!")
1758+
/// }
1759+
/// ```
1760+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1761+
pub struct FmtWriteAdapter<'a, W: Write + ?Sized> {
1762+
inner: &'a mut W,
1763+
error: Option<Error>,
1764+
}
1765+
1766+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1767+
impl<W: Write + ?Sized> FmtWriteAdapter<'_, W> {
1768+
/// Returns a reference to the last error that occurred in this adapter.
1769+
pub fn err(&self) -> &Option<Error> {
1770+
&self.error
1771+
}
1772+
1773+
/// Returns a mutable reference to the last error that occurred in this adapter.
1774+
pub fn mut_err(&mut self) -> &mut Option<Error> {
1775+
&mut self.error
1776+
}
1777+
}
1778+
1779+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1780+
impl<W: Write + ?Sized> fmt::Write for FmtWriteAdapter<'_, W> {
1781+
fn write_str(&mut self, s: &str) -> fmt::Result {
1782+
match self.inner.write_all(s.as_bytes()) {
1783+
Ok(()) => {
1784+
self.error = None;
1785+
Ok(())
1786+
}
1787+
Err(e) => {
1788+
self.error = Some(e);
1789+
Err(fmt::Error)
1790+
}
1791+
}
1792+
}
1793+
}
1794+
1795+
#[unstable(feature = "impl_fmt_write_for_io_write", issue = "77733")]
1796+
impl<W: Write + ?Sized> Debug for FmtWriteAdapter<'_, W> {
1797+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1798+
let mut builder = f.debug_struct("FmtWriteAdapter");
1799+
builder.field("error", &self.error);
1800+
builder.finish()
1801+
}
17531802
}
17541803

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

0 commit comments

Comments
 (0)