diff --git a/src/io/fmt/mod.rs b/src/io/fmt/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/io/fmt/write.rs b/src/io/fmt/write.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/io/write/mod.rs b/src/io/write/mod.rs index 5e1ecc8..169c9e1 100644 --- a/src/io/write/mod.rs +++ b/src/io/write/mod.rs @@ -1,11 +1,13 @@ mod flush; mod write; mod write_all; +mod write_fmt; mod write_vectored; use flush::FlushFuture; use write::WriteFuture; use write_all::WriteAllFuture; +use write_fmt::WriteFmtFuture; use write_vectored::WriteVectoredFuture; use cfg_if::cfg_if; @@ -13,12 +15,12 @@ use cfg_if::cfg_if; use crate::io::IoSlice; use crate::utils::extension_trait; +use crate::io; + cfg_if! { if #[cfg(feature = "docs")] { use std::pin::Pin; use std::ops::{Deref, DerefMut}; - - use crate::io; use crate::task::{Context, Poll}; } } @@ -197,6 +199,47 @@ extension_trait! { { WriteAllFuture { writer: self, buf } } + + #[doc = r#" + Writes a formatted string into this writer, returning any error encountered. + + This method will continuously call [`write`] until there is no more data to be + written or an error is returned. This method will not return until the entire + buffer has been successfully written or such an error occurs. + + [`write`]: #tymethod.write + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::io::prelude::*; + use async_std::fs::File; + + let mut buffer = File::create("foo.txt").await?; + + // this call + write!(buffer, "{:.*}", 2, 1.234567).await?; + // turns into this: + buffer.write_fmt(format_args!("{:.*}", 2, 1.234567)).await?; + # + # Ok(()) }) } + ``` + "#] + fn write_fmt<'a>( + &'a mut self, + fmt: std::fmt::Arguments<'_>, + ) -> impl Future> + 'a [WriteFmtFuture<'a, Self>] + where + Self: Unpin, + { + let mut string = String::new(); + let res = std::fmt::write(&mut string, fmt) + .map(|_| string.into_bytes()) + .map_err(|_| io::Error::new(io::ErrorKind::Other, "formatter error")); + WriteFmtFuture { writer: self, res: Some(res), buffer: None, amt: 0 } + } } impl Write for Box { diff --git a/src/io/write/write_fmt.rs b/src/io/write/write_fmt.rs new file mode 100644 index 0000000..9c8187a --- /dev/null +++ b/src/io/write/write_fmt.rs @@ -0,0 +1,45 @@ +use std::pin::Pin; + +use crate::future::Future; +use crate::io::{self, Write}; +use crate::task::{Context, Poll}; + +#[doc(hidden)] +#[allow(missing_debug_implementations)] +pub struct WriteFmtFuture<'a, T: Unpin + ?Sized> { + pub(crate) writer: &'a mut T, + pub(crate) res: Option>>, + pub(crate) buffer: Option>, + pub(crate) amt: u64, +} + +impl Future for WriteFmtFuture<'_, T> { + type Output = io::Result<()>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + + // Process the interal Result the first time we run. + if self.buffer.is_none() { + match self.res.take().unwrap() { + Err(err) => return Poll::Ready(Err(err)), + Ok(buffer) => self.buffer = Some(buffer), + }; + } + + let Self { writer, amt, buffer, .. } = &mut *self; + let mut buffer = buffer.as_mut().unwrap(); + + loop { + if buffer.is_empty() { + futures_core::ready!(Pin::new(&mut **writer).poll_flush(cx))?; + return Poll::Ready(Ok(())); + } + + let i = futures_core::ready!(Pin::new(&mut **writer).poll_write(cx, &mut buffer))?; + if i == 0 { + return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); + } + *amt += i as u64; + } + } +} diff --git a/src/lib.rs b/src/lib.rs index fa4e946..f1ed43e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,3 +77,6 @@ cfg_if! { } pub(crate) mod utils; + +#[doc(inline)] +pub use std::{write, writeln};