Skip to content

Commit 2b675cb

Browse files
committed
Implement AsyncWrite for the generic Cursor<T: AsMut<[u8]>>
This introduces an unfortunate point of difference between `futures::io::AsyncWrite` and `std::io::Write`, but I think the increased ergonomics around writing to statically sized in memory buffers (presumably just for test purposes) is useful. `impl<T: AsRef<[u8]>> Read for Cursor<T>` was added in rust-lang/rust#27197, I'm not sure why `impl<T: AsMut<[u8]>> Write for Cursor<T>` wasn't added at the same time; I would propose doing this change in `std` and just piggybacking off it here, but the breakage is almost certainly not worth it by this point.
1 parent 6dea985 commit 2b675cb

File tree

4 files changed

+61
-33
lines changed

4 files changed

+61
-33
lines changed

futures-io/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ default = ["std"]
2424
futures-core-preview = { path = "../futures-core", version = "0.3.0-alpha.1", default-features = false }
2525
iovec = { version = "0.1", optional = true }
2626

27-
# [dev-dependencies]
28-
# futures = { path = "../futures", version = "0.2.0" }
27+
[dev-dependencies]
28+
futures-preview = { path = "../futures", version = "0.3.0-alpha.1" }
29+
assert_matches = "1.3.0"

futures-io/src/lib.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ macro_rules! if_std {
2323
if_std! {
2424
use futures_core::task::{self, Poll};
2525
use std::boxed::Box;
26+
use std::cmp;
2627
use std::io as StdIo;
2728
use std::ptr;
28-
use std::vec::Vec;
2929

3030
// Re-export IoVec for convenience
3131
pub use iovec::IoVec;
@@ -354,16 +354,31 @@ if_std! {
354354
}
355355
}
356356

357-
impl<'a> AsyncWrite for StdIo::Cursor<&'a mut [u8]> {
358-
delegate_async_write_to_stdio!();
359-
}
357+
impl<T: AsMut<[u8]>> AsyncWrite for StdIo::Cursor<T> {
358+
fn poll_write(
359+
&mut self,
360+
_: &mut task::Context,
361+
buf: &[u8],
362+
) -> Poll<Result<usize>> {
363+
let position = self.position();
364+
let result = {
365+
let mut out = self.get_mut().as_mut();
366+
let pos = cmp::min(out.len() as u64, position) as usize;
367+
StdIo::Write::write(&mut &mut out[pos..], buf)
368+
};
369+
if let Ok(offset) = result {
370+
self.set_position(position + offset as u64);
371+
}
372+
Poll::Ready(result)
373+
}
360374

361-
impl AsyncWrite for StdIo::Cursor<Vec<u8>> {
362-
delegate_async_write_to_stdio!();
363-
}
375+
fn poll_flush(&mut self, _: &mut task::Context) -> Poll<Result<()>> {
376+
Poll::Ready(StdIo::Write::flush(&mut self.get_mut().as_mut()))
377+
}
364378

365-
impl AsyncWrite for StdIo::Cursor<Box<[u8]>> {
366-
delegate_async_write_to_stdio!();
379+
fn poll_close(&mut self, cx: &mut task::Context) -> Poll<Result<()>> {
380+
self.poll_flush(cx)
381+
}
367382
}
368383

369384
impl AsyncWrite for StdIo::Sink {

futures-io/tests/cursor.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(use_extern_macros, futures_api)]
2+
3+
use assert_matches::assert_matches;
4+
use futures::Poll;
5+
use futures::future::lazy;
6+
use futures::io::AsyncWrite;
7+
use std::io::Cursor;
8+
9+
#[test]
10+
fn cursor_asyncwrite_asmut() {
11+
let mut cursor = Cursor::new([0; 5]);
12+
futures::executor::block_on(lazy(|ctx| {
13+
assert_matches!(cursor.poll_write(ctx, &[1, 2]), Poll::Ready(Ok(2)));
14+
assert_matches!(cursor.poll_write(ctx, &[3, 4]), Poll::Ready(Ok(2)));
15+
assert_matches!(cursor.poll_write(ctx, &[5, 6]), Poll::Ready(Ok(1)));
16+
assert_matches!(cursor.poll_write(ctx, &[6, 7]), Poll::Ready(Ok(0)));
17+
}));
18+
assert_eq!(cursor.into_inner(), [1, 2, 3, 4, 5]);
19+
}

futures-util/src/io/mod.rs

+15-22
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,12 @@ pub trait AsyncReadExt: AsyncRead {
6565
/// use std::io::Cursor;
6666
///
6767
/// let mut reader = Cursor::new([1, 2, 3, 4]);
68-
/// let mut output = [0u8; 5];
68+
/// let mut writer = Cursor::new([0u8; 5]);
6969
///
70-
/// let bytes = {
71-
/// let mut writer = Cursor::new(&mut output[..]);
72-
/// await!(reader.copy_into(&mut writer))?
73-
/// };
70+
/// let bytes = await!(reader.copy_into(&mut writer))?;
7471
///
7572
/// assert_eq!(bytes, 4);
76-
/// assert_eq!(output, [1, 2, 3, 4, 0]);
73+
/// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]);
7774
/// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
7875
/// ```
7976
fn copy_into<'a, W>(
@@ -201,23 +198,22 @@ pub trait AsyncReadExt: AsyncRead {
201198
/// use futures::io::AsyncReadExt;
202199
/// use std::io::Cursor;
203200
///
201+
/// // Note that for `Cursor` the read and write halves share a single
202+
/// // seek position. This may or may not be true for other types that
203+
/// // implement both `AsyncRead` and `AsyncWrite`.
204+
///
204205
/// let mut reader = Cursor::new([1, 2, 3, 4]);
205-
/// let mut buffer = [0, 0, 0, 0, 5, 6, 7, 8];
206-
/// let mut output = [0u8; 5];
206+
/// let mut buffer = Cursor::new([0, 0, 0, 0, 5, 6, 7, 8]);
207+
/// let mut writer = Cursor::new([0u8; 5]);
207208
///
208209
/// {
209-
/// let mut writer = Cursor::new(&mut output[..]);
210-
/// // Note that for `Cursor` the read and write halves share a single
211-
/// // seek position. This may or may not be true for other types that
212-
/// // implement both `AsyncRead` and `AsyncWrite`.
213-
/// let buffer_cursor = Cursor::new(&mut buffer[..]);
214-
/// let (mut buffer_reader, mut buffer_writer) = buffer_cursor.split();
210+
/// let (mut buffer_reader, mut buffer_writer) = (&mut buffer).split();
215211
/// await!(reader.copy_into(&mut buffer_writer))?;
216212
/// await!(buffer_reader.copy_into(&mut writer))?;
217213
/// }
218214
///
219-
/// assert_eq!(buffer, [1, 2, 3, 4, 5, 6, 7, 8]);
220-
/// assert_eq!(output, [5, 6, 7, 8, 0]);
215+
/// assert_eq!(buffer.into_inner(), [1, 2, 3, 4, 5, 6, 7, 8]);
216+
/// assert_eq!(writer.into_inner(), [5, 6, 7, 8, 0]);
221217
/// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
222218
/// ```
223219
fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
@@ -278,14 +274,11 @@ pub trait AsyncWriteExt: AsyncWrite {
278274
/// use futures::io::AsyncWriteExt;
279275
/// use std::io::Cursor;
280276
///
281-
/// let mut output = [0u8; 5];
277+
/// let mut writer = Cursor::new([0u8; 5]);
282278
///
283-
/// {
284-
/// let mut writer = Cursor::new(&mut output[..]);
285-
/// await!(writer.write_all(&[1, 2, 3, 4]))?;
286-
/// }
279+
/// await!(writer.write_all(&[1, 2, 3, 4]))?;
287280
///
288-
/// assert_eq!(output, [1, 2, 3, 4, 0]);
281+
/// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]);
289282
/// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
290283
/// ```
291284
fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> {

0 commit comments

Comments
 (0)