Skip to content

Commit 33da049

Browse files
authored
Merge pull request #311 from async-rs/missing-write-methods
Add Write::write_fmt
2 parents 28b0ebe + b62e4a1 commit 33da049

File tree

3 files changed

+101
-2
lines changed

3 files changed

+101
-2
lines changed

src/io/write/mod.rs

+48-2
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
mod flush;
22
mod write;
33
mod write_all;
4+
mod write_fmt;
45
mod write_vectored;
56

67
use flush::FlushFuture;
78
use write::WriteFuture;
89
use write_all::WriteAllFuture;
10+
use write_fmt::WriteFmtFuture;
911
use write_vectored::WriteVectoredFuture;
1012

1113
use cfg_if::cfg_if;
1214

1315
use crate::io::IoSlice;
1416
use crate::utils::extension_trait;
1517

18+
use crate::io;
19+
1620
cfg_if! {
1721
if #[cfg(feature = "docs")] {
1822
use std::pin::Pin;
1923
use std::ops::{Deref, DerefMut};
20-
21-
use crate::io;
2224
use crate::task::{Context, Poll};
2325
}
2426
}
@@ -197,6 +199,50 @@ extension_trait! {
197199
{
198200
WriteAllFuture { writer: self, buf }
199201
}
202+
203+
#[doc = r#"
204+
Writes a formatted string into this writer, returning any error encountered.
205+
206+
This method will continuously call [`write`] until there is no more data to be
207+
written or an error is returned. This future will not resolve until the entire
208+
buffer has been successfully written or such an error occurs.
209+
210+
[`write`]: #tymethod.write
211+
212+
# Examples
213+
214+
```no_run
215+
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
216+
#
217+
use async_std::io::prelude::*;
218+
use async_std::fs::File;
219+
220+
let mut buffer = File::create("foo.txt").await?;
221+
222+
// this call
223+
write!(buffer, "{:.*}", 2, 1.234567).await?;
224+
// turns into this:
225+
buffer.write_fmt(format_args!("{:.*}", 2, 1.234567)).await?;
226+
#
227+
# Ok(()) }) }
228+
```
229+
"#]
230+
fn write_fmt<'a>(
231+
&'a mut self,
232+
fmt: std::fmt::Arguments<'_>,
233+
) -> impl Future<Output = io::Result<()>> + 'a [WriteFmtFuture<'a, Self>]
234+
where
235+
Self: Unpin,
236+
{
237+
// In order to not have to implement an async version of `fmt` including private types
238+
// and all, we convert `Arguments` to a `Result<Vec<u8>>` and pass that to the Future.
239+
// Doing an owned conversion saves us from juggling references.
240+
let mut string = String::new();
241+
let res = std::fmt::write(&mut string, fmt)
242+
.map(|_| string.into_bytes())
243+
.map_err(|_| io::Error::new(io::ErrorKind::Other, "formatter error"));
244+
WriteFmtFuture { writer: self, res: Some(res), buffer: None, amt: 0 }
245+
}
200246
}
201247

202248
impl<T: Write + Unpin + ?Sized> Write for Box<T> {

src/io/write/write_fmt.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::pin::Pin;
2+
3+
use crate::future::Future;
4+
use crate::io::{self, Write};
5+
use crate::task::{Context, Poll};
6+
7+
#[doc(hidden)]
8+
#[allow(missing_debug_implementations)]
9+
pub struct WriteFmtFuture<'a, T: Unpin + ?Sized> {
10+
pub(crate) writer: &'a mut T,
11+
pub(crate) res: Option<io::Result<Vec<u8>>>,
12+
pub(crate) buffer: Option<Vec<u8>>,
13+
pub(crate) amt: u64,
14+
}
15+
16+
impl<T: Write + Unpin + ?Sized> Future for WriteFmtFuture<'_, T> {
17+
type Output = io::Result<()>;
18+
19+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
20+
// Process the interal Result the first time we run.
21+
if self.buffer.is_none() {
22+
match self.res.take().unwrap() {
23+
Err(err) => return Poll::Ready(Err(err)),
24+
Ok(buffer) => self.buffer = Some(buffer),
25+
};
26+
}
27+
28+
// Get the types from the future.
29+
let Self {
30+
writer,
31+
amt,
32+
buffer,
33+
..
34+
} = &mut *self;
35+
let mut buffer = buffer.as_mut().unwrap();
36+
37+
// Copy the data from the buffer into the writer until it's done.
38+
loop {
39+
if buffer.is_empty() {
40+
futures_core::ready!(Pin::new(&mut **writer).poll_flush(cx))?;
41+
return Poll::Ready(Ok(()));
42+
}
43+
let i = futures_core::ready!(Pin::new(&mut **writer).poll_write(cx, &mut buffer))?;
44+
if i == 0 {
45+
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
46+
}
47+
*amt += i as u64;
48+
}
49+
}
50+
}

src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,6 @@ cfg_if! {
7777
}
7878

7979
pub(crate) mod utils;
80+
81+
#[doc(inline)]
82+
pub use std::{write, writeln};

0 commit comments

Comments
 (0)