Skip to content

Commit df29530

Browse files
committed
Add AsyncRead::poll_read_buf and AsyncWrite::poll_write_buf
1 parent 775e267 commit df29530

File tree

11 files changed

+299
-4
lines changed

11 files changed

+299
-4
lines changed

.travis.yml

+13-3
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,23 @@ matrix:
128128
--no-default-features
129129
--features alloc
130130

131-
- name: cargo check (futures-util)
131+
- name: cargo check (sub crates)
132132
rust: nightly
133133
script:
134134
- cargo run --manifest-path ci/remove-dev-dependencies/Cargo.toml */Cargo.toml
135135

136+
# futures-io
137+
# Check default-features, all-features
138+
- cargo check --manifest-path futures-io/Cargo.toml
139+
- cargo check --manifest-path futures-io/Cargo.toml --all-features
140+
# Check each features
141+
- cargo check --manifest-path futures-io/Cargo.toml --features bytes,unstable
142+
143+
# futures-util
144+
# Check default-features, all-features
136145
- cargo check --manifest-path futures-util/Cargo.toml
137146
- cargo check --manifest-path futures-util/Cargo.toml --all-features
138-
147+
# Check each features
139148
- cargo check --manifest-path futures-util/Cargo.toml --features sink
140149
- cargo check --manifest-path futures-util/Cargo.toml --features io
141150
- cargo check --manifest-path futures-util/Cargo.toml --features channel
@@ -146,7 +155,8 @@ matrix:
146155
- cargo check --manifest-path futures-util/Cargo.toml --features io-compat
147156
- cargo check --manifest-path futures-util/Cargo.toml --features sink,compat
148157
- cargo check --manifest-path futures-util/Cargo.toml --features sink,channel
149-
158+
- cargo check --manifest-path futures-util/Cargo.toml --features bytes,unstable
159+
# Check no-default-features
150160
- cargo check --manifest-path futures-util/Cargo.toml --no-default-features
151161
- cargo check --manifest-path futures-util/Cargo.toml --no-default-features --features sink
152162
- cargo check --manifest-path futures-util/Cargo.toml --no-default-features --features alloc,sink

futures-io/Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ name = "futures_io"
1818
default = ["std"]
1919
std = []
2020

21+
# Unstable features
22+
# `bytes` feature is outside of the normal semver guarantees and require the
23+
# `unstable` feature as an explicit opt-in to unstable API.
24+
unstable = []
25+
2126
[dependencies]
27+
bytes = { version = "0.4.7", optional = true }
2228

2329
[dev-dependencies]
2430
futures-preview = { path = "../futures", version = "=0.3.0-alpha.18" }

futures-io/src/lib.rs

+68
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
#![doc(html_root_url = "https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures_io")]
2121

22+
#[cfg(all(feature = "bytes", not(feature = "unstable")))]
23+
compile_error!("The `bytes` feature requires the `unstable` feature as an explicit opt-in to unstable features");
24+
2225
#[cfg(feature = "std")]
2326
mod if_std {
2427
use std::cmp;
@@ -40,6 +43,10 @@ mod if_std {
4043
SeekFrom as SeekFrom,
4144
};
4245

46+
#[cfg(feature = "bytes")]
47+
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
48+
pub use bytes::{Buf, BufMut};
49+
4350
/// A type used to conditionally initialize buffers passed to `AsyncRead`
4451
/// methods, modeled after `std`.
4552
#[derive(Debug)]
@@ -154,6 +161,42 @@ mod if_std {
154161
Poll::Ready(Ok(0))
155162
}
156163
}
164+
165+
/// Pull some bytes from this source into the specified `BufMut`, returning
166+
/// how many bytes were read.
167+
///
168+
/// The `buf` provided will have bytes read into it and the internal cursor
169+
/// will be advanced if any bytes were read. Note that this method typically
170+
/// will not reallocate the buffer provided.
171+
#[cfg(feature = "bytes")]
172+
fn poll_read_buf<B: BufMut>(
173+
self: Pin<&mut Self>,
174+
cx: &mut Context<'_>,
175+
buf: &mut B,
176+
) -> Poll<Result<usize>>
177+
where
178+
Self: Sized,
179+
{
180+
if !buf.has_remaining_mut() {
181+
return Poll::Ready(Ok(0));
182+
}
183+
184+
unsafe {
185+
let n = {
186+
let mut b = buf.bytes_mut();
187+
188+
self.initializer().initialize(&mut b);
189+
190+
match self.poll_read(cx, b)? {
191+
Poll::Ready(n) => n,
192+
Poll::Pending => return Poll::Pending,
193+
}
194+
};
195+
196+
buf.advance_mut(n);
197+
Poll::Ready(Ok(n))
198+
}
199+
}
157200
}
158201

159202
/// Write bytes asynchronously.
@@ -250,6 +293,31 @@ mod if_std {
250293
/// `Poll::Pending` and either internally retry or convert
251294
/// `Interrupted` into another error kind.
252295
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>>;
296+
297+
/// Write a `Buf` into this value, returning how many bytes were written.
298+
///
299+
/// Note that this method will advance the `buf` provided automatically by
300+
/// the number of bytes written.
301+
#[cfg(feature = "bytes")]
302+
fn poll_write_buf<B: Buf>(
303+
self: Pin<&mut Self>,
304+
cx: &mut Context<'_>,
305+
buf: &mut B,
306+
) -> Poll<Result<usize>>
307+
where
308+
Self: Sized,
309+
{
310+
if !buf.has_remaining() {
311+
return Poll::Ready(Ok(0));
312+
}
313+
314+
let n = match self.poll_write(cx, buf.bytes())? {
315+
Poll::Ready(n) => n,
316+
Poll::Pending => return Poll::Pending,
317+
};
318+
buf.advance(n);
319+
Poll::Ready(Ok(n))
320+
}
253321
}
254322

255323
/// Seek bytes asynchronously.

futures-util/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ select-macro = ["async-await", "futures-select-macro-preview", "proc-macro-hack"
3333
unstable = ["futures-core-preview/unstable"]
3434
cfg-target-has-atomic = ["futures-core-preview/cfg-target-has-atomic"]
3535
bench = []
36+
bytes = ["io", "futures-io-preview/bytes", "futures-io-preview/unstable"]
3637

3738
[dependencies]
3839
futures-core-preview = { path = "../futures-core", version = "=0.3.0-alpha.18", default-features = false }

futures-util/src/io/mod.rs

+34
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub use futures_io::{
1313
AsyncRead, AsyncWrite, AsyncSeek, AsyncBufRead, Error, ErrorKind,
1414
IoSlice, IoSliceMut, Result, SeekFrom,
1515
};
16+
#[cfg(feature = "bytes")]
17+
pub use futures_io::{Buf, BufMut};
1618

1719
#[cfg(feature = "io-compat")] use crate::compat::Compat;
1820

@@ -58,6 +60,11 @@ pub use self::read::Read;
5860
mod read_vectored;
5961
pub use self::read_vectored::ReadVectored;
6062

63+
#[cfg(feature = "bytes")]
64+
mod read_buf;
65+
#[cfg(feature = "bytes")]
66+
pub use self::read_buf::ReadBuf;
67+
6168
mod read_exact;
6269
pub use self::read_exact::ReadExact;
6370

@@ -91,6 +98,11 @@ pub use self::write::Write;
9198
mod write_vectored;
9299
pub use self::write_vectored::WriteVectored;
93100

101+
#[cfg(feature = "bytes")]
102+
mod write_buf;
103+
#[cfg(feature = "bytes")]
104+
pub use self::write_buf::WriteBuf;
105+
94106
mod write_all;
95107
pub use self::write_all::WriteAll;
96108

@@ -204,6 +216,17 @@ pub trait AsyncReadExt: AsyncRead {
204216
ReadVectored::new(self, bufs)
205217
}
206218

219+
/// Creates a future which will read from the `AsyncRead` into `buf`.
220+
///
221+
/// The returned future will resolve to the number of bytes read once the read
222+
/// operation is completed.
223+
#[cfg(feature = "bytes")]
224+
fn read_buf<'a, B: BufMut>(&'a mut self, buf: &'a mut B) -> ReadBuf<'a, Self, B>
225+
where Self: Unpin,
226+
{
227+
ReadBuf::new(self, buf)
228+
}
229+
207230
/// Creates a future which will read exactly enough bytes to fill `buf`,
208231
/// returning an error if end of file (EOF) is hit sooner.
209232
///
@@ -446,6 +469,17 @@ pub trait AsyncWriteExt: AsyncWrite {
446469
WriteVectored::new(self, bufs)
447470
}
448471

472+
/// Creates a future which will write bytes from `buf` into the object.
473+
///
474+
/// The returned future will resolve to the number of bytes written once the write
475+
/// operation is completed.
476+
#[cfg(feature = "bytes")]
477+
fn write_buf<'a, B: Buf>(&'a mut self, buf: &'a mut B) -> WriteBuf<'a, Self, B>
478+
where Self: Unpin,
479+
{
480+
WriteBuf::new(self, buf)
481+
}
482+
449483
/// Write data into this object.
450484
///
451485
/// Creates a future that will write the entire contents of the buffer `buf` into

futures-util/src/io/read_buf.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use futures_core::future::Future;
2+
use futures_core::task::{Context, Poll};
3+
use futures_io::{AsyncRead, BufMut};
4+
use std::io;
5+
use std::pin::Pin;
6+
7+
/// Future for the [`read_buf`](super::AsyncReadExt::read_buf) method.
8+
#[derive(Debug)]
9+
#[must_use = "futures do nothing unless you `.await` or poll them"]
10+
pub struct ReadBuf<'a, R: ?Sized + Unpin, B> {
11+
reader: &'a mut R,
12+
buf: &'a mut B,
13+
}
14+
15+
impl<R: ?Sized + Unpin, B> Unpin for ReadBuf<'_, R, B> {}
16+
17+
impl<'a, R: AsyncRead + ?Sized + Unpin, B: BufMut> ReadBuf<'a, R, B> {
18+
pub(super) fn new(reader: &'a mut R, buf: &'a mut B) -> Self {
19+
Self { reader, buf }
20+
}
21+
}
22+
23+
impl<R: AsyncRead + ?Sized + Unpin, B: BufMut> Future for ReadBuf<'_, R, B> {
24+
type Output = io::Result<usize>;
25+
26+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
27+
let this = &mut *self;
28+
Pin::new(&mut this.reader).poll_read_buf(cx, this.buf)
29+
}
30+
}

futures-util/src/io/write_buf.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use futures_core::future::Future;
2+
use futures_core::task::{Context, Poll};
3+
use futures_io::{AsyncWrite, Buf};
4+
use std::io;
5+
use std::pin::Pin;
6+
7+
/// Future for the [`write_buf`](super::AsyncWriteExt::write_buf) method.
8+
#[derive(Debug)]
9+
#[must_use = "futures do nothing unless you `.await` or poll them"]
10+
pub struct WriteBuf<'a, W: ?Sized + Unpin, B> {
11+
writer: &'a mut W,
12+
buf: &'a mut B,
13+
}
14+
15+
impl<W: ?Sized + Unpin, B> Unpin for WriteBuf<'_, W, B> {}
16+
17+
impl<'a, W: AsyncWrite + ?Sized + Unpin, B: Buf> WriteBuf<'a, W, B> {
18+
pub(super) fn new(writer: &'a mut W, buf: &'a mut B) -> Self {
19+
Self { writer, buf }
20+
}
21+
}
22+
23+
impl<W: AsyncWrite + ?Sized + Unpin, B: Buf> Future for WriteBuf<'_, W, B> {
24+
type Output = io::Result<usize>;
25+
26+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
27+
let this = &mut *self;
28+
Pin::new(&mut this.writer).poll_write_buf(cx, this.buf)
29+
}
30+
}

futures-util/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ compile_error!("The `cfg-target-has-atomic` feature requires the `unstable` feat
1919
#[cfg(all(feature = "bench", not(feature = "unstable")))]
2020
compile_error!("The `bench` feature requires the `unstable` feature as an explicit opt-in to unstable features");
2121

22+
#[cfg(all(feature = "bytes", not(feature = "unstable")))]
23+
compile_error!("The `bytes` feature requires the `unstable` feature as an explicit opt-in to unstable features");
24+
2225
#[cfg(feature = "alloc")]
2326
extern crate alloc;
2427

futures/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pin-utils = "0.1.0-alpha.4"
3434
futures-test-preview = { path = "../futures-test", version = "=0.3.0-alpha.18" }
3535
tokio = "0.1.11"
3636
assert_matches = "1.3.0"
37+
bytes_crate = { version = "0.4.7", package = "bytes" }
3738

3839
[features]
3940
default = ["std"]
@@ -46,8 +47,9 @@ io-compat = ["compat", "futures-util-preview/io-compat"]
4647
# Unstable features
4748
# These features are outside of the normal semver guarantees and require the
4849
# `unstable` feature as an explicit opt-in to unstable API.
49-
unstable = ["futures-core-preview/unstable", "futures-channel-preview/unstable", "futures-util-preview/unstable"]
50+
unstable = ["futures-core-preview/unstable", "futures-channel-preview/unstable", "futures-io-preview/unstable", "futures-util-preview/unstable"]
5051
cfg-target-has-atomic = ["futures-core-preview/cfg-target-has-atomic", "futures-channel-preview/cfg-target-has-atomic", "futures-util-preview/cfg-target-has-atomic"]
52+
bytes = ["futures-io-preview/bytes", "futures-util-preview/bytes"]
5153

5254
[package.metadata.docs.rs]
5355
all-features = true

futures/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
#[cfg(all(feature = "cfg-target-has-atomic", not(feature = "unstable")))]
3838
compile_error!("The `cfg-target-has-atomic` feature requires the `unstable` feature as an explicit opt-in to unstable features");
3939

40+
#[cfg(all(feature = "bytes", not(feature = "unstable")))]
41+
compile_error!("The `bytes` feature requires the `unstable` feature as an explicit opt-in to unstable features");
42+
4043
#[doc(hidden)] pub use futures_core::core_reexport;
4144

4245
#[doc(hidden)] pub use futures_core::future::Future;
@@ -305,6 +308,12 @@ pub mod io {
305308
ReadToString, ReadUntil, ReadVectored, Seek, Take, Window, Write,
306309
WriteAll, WriteHalf, WriteVectored,
307310
};
311+
312+
#[cfg(feature = "bytes")]
313+
pub use futures_io::{Buf, BufMut};
314+
315+
#[cfg(feature = "bytes")]
316+
pub use futures_util::io::{ReadBuf, WriteBuf};
308317
}
309318

310319
#[cfg(feature = "std")]

0 commit comments

Comments
 (0)