From 58c3a06a14c70d34ff884c94142eac278032c238 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 01:24:50 +0200 Subject: [PATCH 1/5] init write_fmt Signed-off-by: Yoshua Wuyts --- src/io/fmt/mod.rs | 0 src/io/fmt/write.rs | 0 src/io/write/mod.rs | 47 +++++++++++++++++++++++++++++++++++++-- src/io/write/write_fmt.rs | 45 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ 5 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/io/fmt/mod.rs create mode 100644 src/io/fmt/write.rs create mode 100644 src/io/write/write_fmt.rs diff --git a/src/io/fmt/mod.rs b/src/io/fmt/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/src/io/fmt/write.rs b/src/io/fmt/write.rs new file mode 100644 index 000000000..e69de29bb diff --git a/src/io/write/mod.rs b/src/io/write/mod.rs index 5e1ecc8be..169c9e1ee 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 000000000..9c8187ab7 --- /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 fa4e946f9..f1ed43e13 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}; From 570dedd71269642b3e3b4a11ab7c5126292b2a49 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 01:31:51 +0200 Subject: [PATCH 2/5] cleanup Signed-off-by: Yoshua Wuyts --- src/io/fmt/mod.rs | 0 src/io/fmt/write.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/io/fmt/mod.rs delete mode 100644 src/io/fmt/write.rs diff --git a/src/io/fmt/mod.rs b/src/io/fmt/mod.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/io/fmt/write.rs b/src/io/fmt/write.rs deleted file mode 100644 index e69de29bb..000000000 From f3eba1fb48641cc7c671c7cdd0e4683888714a13 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 01:34:13 +0200 Subject: [PATCH 3/5] comments Signed-off-by: Yoshua Wuyts --- src/io/write/mod.rs | 3 +++ src/io/write/write_fmt.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/io/write/mod.rs b/src/io/write/mod.rs index 169c9e1ee..bb03d9010 100644 --- a/src/io/write/mod.rs +++ b/src/io/write/mod.rs @@ -234,6 +234,9 @@ extension_trait! { where Self: Unpin, { + // In order to not have to implement an async version of `fmt` including private types + // and all, we convert `Arguments` to a `Result>` and pass that to the Future. + // Doing an owned conversion saves us from juggling references. let mut string = String::new(); let res = std::fmt::write(&mut string, fmt) .map(|_| string.into_bytes()) diff --git a/src/io/write/write_fmt.rs b/src/io/write/write_fmt.rs index 9c8187ab7..bd2dd6737 100644 --- a/src/io/write/write_fmt.rs +++ b/src/io/write/write_fmt.rs @@ -17,7 +17,6 @@ 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() { @@ -26,15 +25,16 @@ impl Future for WriteFmtFuture<'_, T> { }; } + // Get the types from the future. let Self { writer, amt, buffer, .. } = &mut *self; let mut buffer = buffer.as_mut().unwrap(); + // Copy the data from the buffer into the writer until it's done. 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())); From a1cd76e24436117d43c85a91e6b9469ca0c58924 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 01:36:44 +0200 Subject: [PATCH 4/5] cargo fmt Signed-off-by: Yoshua Wuyts --- src/io/write/write_fmt.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/io/write/write_fmt.rs b/src/io/write/write_fmt.rs index bd2dd6737..f59422897 100644 --- a/src/io/write/write_fmt.rs +++ b/src/io/write/write_fmt.rs @@ -26,7 +26,12 @@ impl Future for WriteFmtFuture<'_, T> { } // Get the types from the future. - let Self { writer, amt, buffer, .. } = &mut *self; + let Self { + writer, + amt, + buffer, + .. + } = &mut *self; let mut buffer = buffer.as_mut().unwrap(); // Copy the data from the buffer into the writer until it's done. From b62e4a1e48cd9c58a09f7455e895fb234b0de2c6 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 02:39:14 +0200 Subject: [PATCH 5/5] update desc Signed-off-by: Yoshua Wuyts --- src/io/write/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/write/mod.rs b/src/io/write/mod.rs index bb03d9010..7914ccc82 100644 --- a/src/io/write/mod.rs +++ b/src/io/write/mod.rs @@ -204,7 +204,7 @@ extension_trait! { 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 + written or an error is returned. This future will not resolve until the entire buffer has been successfully written or such an error occurs. [`write`]: #tymethod.write