Skip to content

Commit 43c5f14

Browse files
committed
Make AsyncRead::initializer unstable API
1 parent 90c83b8 commit 43c5f14

18 files changed

+111
-66
lines changed

.travis.yml

+12-2
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,23 @@ matrix:
136136
--no-default-features
137137
--features async-await
138138

139-
- name: cargo check (futures-util)
139+
- name: cargo check (sub crates)
140140
rust: nightly
141141
script:
142142
- cargo run --manifest-path ci/remove-dev-dependencies/Cargo.toml */Cargo.toml
143143

144+
# futures-io
145+
# Check default-features, all-features
146+
- cargo check --manifest-path futures-io/Cargo.toml
147+
- cargo check --manifest-path futures-io/Cargo.toml --all-features
148+
# Check each features
149+
- cargo check --manifest-path futures-io/Cargo.toml --features read_initializer,unstable
150+
151+
# futures-util
152+
# Check default-features, all-features
144153
- cargo check --manifest-path futures-util/Cargo.toml
145154
- cargo check --manifest-path futures-util/Cargo.toml --all-features
146-
155+
# Check each features
147156
- cargo check --manifest-path futures-util/Cargo.toml --features sink
148157
- cargo check --manifest-path futures-util/Cargo.toml --features io
149158
- cargo check --manifest-path futures-util/Cargo.toml --features channel
@@ -158,6 +167,7 @@ matrix:
158167
- cargo check --manifest-path futures-util/Cargo.toml --features sink,bilock,unstable
159168
- cargo check --manifest-path futures-util/Cargo.toml --features io,bilock,unstable
160169
- cargo check --manifest-path futures-util/Cargo.toml --features sink,io
170+
- cargo check --manifest-path futures-util/Cargo.toml --features read_initializer,unstable
161171

162172
- cargo check --manifest-path futures-util/Cargo.toml --no-default-features
163173
- cargo check --manifest-path futures-util/Cargo.toml --no-default-features --features sink

futures-io/Cargo.toml

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

21+
# Unstable features
22+
# These features are outside of the normal semver guarantees and require the
23+
# `unstable` feature as an explicit opt-in to unstable API.
24+
unstable = []
25+
read_initializer = []
26+
2127
[dependencies]
2228

2329
[dev-dependencies]

futures-io/src/lib.rs

+16-46
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
//! All items of this library are only available when the `std` feature of this
99
//! library is activated, and it is activated by default.
1010
11+
#![cfg_attr(feature = "read_initializer", feature(read_initializer))]
12+
1113
#![cfg_attr(not(feature = "std"), no_std)]
1214

1315
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
@@ -19,13 +21,15 @@
1921

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

24+
#[cfg(all(feature = "read_initializer", not(feature = "unstable")))]
25+
compile_error!("The `read_initializer` feature requires the `unstable` feature as an explicit opt-in to unstable features");
26+
2227
#[cfg(feature = "std")]
2328
mod if_std {
2429
use std::cmp;
2530
use std::io;
2631
use std::ops::DerefMut;
2732
use std::pin::Pin;
28-
use std::ptr;
2933
use std::task::{Context, Poll};
3034

3135
// Re-export some types from `std::io` so that users don't have to deal
@@ -40,45 +44,9 @@ mod if_std {
4044
SeekFrom as SeekFrom,
4145
};
4246

43-
/// A type used to conditionally initialize buffers passed to `AsyncRead`
44-
/// methods, modeled after `std`.
45-
#[derive(Debug)]
46-
pub struct Initializer(bool);
47-
48-
impl Initializer {
49-
/// Returns a new `Initializer` which will zero out buffers.
50-
#[inline]
51-
pub fn zeroing() -> Initializer {
52-
Initializer(true)
53-
}
54-
55-
/// Returns a new `Initializer` which will not zero out buffers.
56-
///
57-
/// # Safety
58-
///
59-
/// This method may only be called by `AsyncRead`ers which guarantee
60-
/// that they will not read from the buffers passed to `AsyncRead`
61-
/// methods, and that the return value of the method accurately reflects
62-
/// the number of bytes that have been written to the head of the buffer.
63-
#[inline]
64-
pub unsafe fn nop() -> Initializer {
65-
Initializer(false)
66-
}
67-
68-
/// Indicates if a buffer should be initialized.
69-
#[inline]
70-
pub fn should_initialize(&self) -> bool {
71-
self.0
72-
}
73-
74-
/// Initializes a buffer if necessary.
75-
#[inline]
76-
pub fn initialize(&self, buf: &mut [u8]) {
77-
if self.should_initialize() {
78-
unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
79-
}
80-
}
81-
}
47+
#[cfg(feature = "read_initializer")]
48+
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
49+
pub use io::Initializer as Initializer;
8250

8351
/// Read bytes asynchronously.
8452
///
@@ -99,6 +67,7 @@ mod if_std {
9967
/// This method is `unsafe` because and `AsyncRead`er could otherwise
10068
/// return a non-zeroing `Initializer` from another `AsyncRead` type
10169
/// without an `unsafe` block.
70+
#[cfg(feature = "read_initializer")]
10271
#[inline]
10372
unsafe fn initializer(&self) -> Initializer {
10473
Initializer::zeroing()
@@ -342,6 +311,7 @@ mod if_std {
342311

343312
macro_rules! deref_async_read {
344313
() => {
314+
#[cfg(feature = "read_initializer")]
345315
unsafe fn initializer(&self) -> Initializer {
346316
(**self).initializer()
347317
}
@@ -373,6 +343,7 @@ mod if_std {
373343
P: DerefMut + Unpin,
374344
P::Target: AsyncRead,
375345
{
346+
#[cfg(feature = "read_initializer")]
376347
unsafe fn initializer(&self) -> Initializer {
377348
(**self).initializer()
378349
}
@@ -390,12 +361,11 @@ mod if_std {
390361
}
391362
}
392363

393-
/// `unsafe` because the `io::Read` type must not access the buffer
394-
/// before reading data into it.
395-
macro_rules! unsafe_delegate_async_read_to_stdio {
364+
macro_rules! delegate_async_read_to_stdio {
396365
() => {
366+
#[cfg(feature = "read_initializer")]
397367
unsafe fn initializer(&self) -> Initializer {
398-
Initializer::nop()
368+
io::Read::initializer(self)
399369
}
400370

401371
fn poll_read(mut self: Pin<&mut Self>, _: &mut Context<'_>, buf: &mut [u8])
@@ -413,11 +383,11 @@ mod if_std {
413383
}
414384

415385
impl AsyncRead for &[u8] {
416-
unsafe_delegate_async_read_to_stdio!();
386+
delegate_async_read_to_stdio!();
417387
}
418388

419389
impl<T: AsRef<[u8]> + Unpin> AsyncRead for io::Cursor<T> {
420-
unsafe_delegate_async_read_to_stdio!();
390+
delegate_async_read_to_stdio!();
421391
}
422392

423393
macro_rules! deref_async_write {

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
bilock = []
36+
read_initializer = ["io", "futures-io-preview/read_initializer", "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/compat/compat01as03.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -368,9 +368,9 @@ unsafe impl UnsafeNotify01 for NotifyWaker {
368368
#[cfg(feature = "io-compat")]
369369
mod io {
370370
use super::*;
371-
use futures_io::{
372-
AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03, Initializer,
373-
};
371+
#[cfg(feature = "read_initializer")]
372+
use futures_io::Initializer;
373+
use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03};
374374
use std::io::Error;
375375
use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};
376376

@@ -433,6 +433,7 @@ mod io {
433433
impl<W: AsyncWrite01> AsyncWrite01CompatExt for W {}
434434

435435
impl<R: AsyncRead01> AsyncRead03 for Compat01As03<R> {
436+
#[cfg(feature = "read_initializer")]
436437
unsafe fn initializer(&self) -> Initializer {
437438
// check if `prepare_uninitialized_buffer` needs zeroing
438439
if self.inner.get_ref().prepare_uninitialized_buffer(&mut [1]) {

futures-util/src/compat/compat03as01.rs

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ mod io {
262262
}
263263

264264
impl<R: AsyncRead03 + Unpin> AsyncRead01 for Compat<R> {
265+
#[cfg(feature = "read_initializer")]
265266
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
266267
let initializer = self.inner.initializer();
267268
let does_init = initializer.should_initialize();

futures-util/src/future/either.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,18 @@ mod if_std {
160160
use super::Either;
161161
use core::pin::Pin;
162162
use core::task::{Context, Poll};
163+
#[cfg(feature = "read_initializer")]
164+
use futures_io::Initializer;
163165
use futures_io::{
164-
AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, Initializer, IoSlice, IoSliceMut, Result,
165-
SeekFrom,
166+
AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, IoSlice, IoSliceMut, Result, SeekFrom,
166167
};
167168

168169
impl<A, B> AsyncRead for Either<A, B>
169170
where
170171
A: AsyncRead,
171172
B: AsyncRead,
172173
{
174+
#[cfg(feature = "read_initializer")]
173175
unsafe fn initializer(&self) -> Initializer {
174176
match self {
175177
Either::Left(x) => x.initializer(),

futures-util/src/io/allow_std.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use futures_core::task::{Context, Poll};
2+
#[cfg(feature = "read_initializer")]
3+
use futures_io::Initializer;
24
use futures_io::{AsyncRead, AsyncWrite, AsyncSeek, AsyncBufRead, IoSlice, IoSliceMut, SeekFrom};
35
use std::{fmt, io};
46
use std::pin::Pin;
@@ -106,8 +108,10 @@ impl<T> io::Read for AllowStdIo<T> where T: io::Read {
106108
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
107109
self.0.read_vectored(bufs)
108110
}
109-
// TODO: implement the `initializer` fn when it stabilizes.
110-
// See rust-lang/rust #42788
111+
#[cfg(feature = "read_initializer")]
112+
unsafe fn initializer(&self) -> Initializer {
113+
self.0.initializer()
114+
}
111115
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
112116
self.0.read_to_end(buf)
113117
}
@@ -131,6 +135,11 @@ impl<T> AsyncRead for AllowStdIo<T> where T: io::Read {
131135
{
132136
Poll::Ready(Ok(try_with_interrupt!(self.0.read_vectored(bufs))))
133137
}
138+
139+
#[cfg(feature = "read_initializer")]
140+
unsafe fn initializer(&self) -> Initializer {
141+
self.0.initializer()
142+
}
134143
}
135144

136145
impl<T> io::Seek for AllowStdIo<T> where T: io::Seek {

futures-util/src/io/buf_reader.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use futures_core::task::{Context, Poll};
2-
use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, Initializer, IoSliceMut, SeekFrom};
2+
#[cfg(feature = "read_initializer")]
3+
use futures_io::Initializer;
4+
use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, IoSliceMut, SeekFrom};
35
use pin_utils::{unsafe_pinned, unsafe_unpinned};
46
use std::io::{self, Read};
57
use std::pin::Pin;
@@ -48,7 +50,7 @@ impl<R: AsyncRead> BufReader<R> {
4850
unsafe {
4951
let mut buffer = Vec::with_capacity(capacity);
5052
buffer.set_len(capacity);
51-
inner.initializer().initialize(&mut buffer);
53+
super::initialize(&inner, &mut buffer);
5254
Self {
5355
inner,
5456
buf: buffer.into_boxed_slice(),
@@ -166,6 +168,7 @@ impl<R: AsyncRead> AsyncRead for BufReader<R> {
166168
}
167169

168170
// we can't skip unconditionally because of the large buffer case in read.
171+
#[cfg(feature = "read_initializer")]
169172
unsafe fn initializer(&self) -> Initializer {
170173
self.inner.initializer()
171174
}

futures-util/src/io/chain.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use futures_core::task::{Context, Poll};
2-
use futures_io::{AsyncBufRead, AsyncRead, Initializer, IoSliceMut};
2+
#[cfg(feature = "read_initializer")]
3+
use futures_io::Initializer;
4+
use futures_io::{AsyncBufRead, AsyncRead, IoSliceMut};
35
use pin_utils::{unsafe_pinned, unsafe_unpinned};
46
use std::fmt;
57
use std::io;
@@ -117,6 +119,7 @@ where
117119
self.second().poll_read_vectored(cx, bufs)
118120
}
119121

122+
#[cfg(feature = "read_initializer")]
120123
unsafe fn initializer(&self) -> Initializer {
121124
let initializer = self.first.initializer();
122125
if initializer.should_initialize() {

futures-util/src/io/empty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use futures_core::task::{Context, Poll};
2-
use futures_io::{AsyncBufRead, AsyncRead, Initializer};
2+
#[cfg(feature = "read_initializer")]
3+
use futures_io::Initializer;
4+
use futures_io::{AsyncBufRead, AsyncRead};
35
use std::fmt;
46
use std::io;
57
use std::pin::Pin;
@@ -42,6 +44,7 @@ impl AsyncRead for Empty {
4244
Poll::Ready(Ok(0))
4345
}
4446

47+
#[cfg(feature = "read_initializer")]
4548
#[inline]
4649
unsafe fn initializer(&self) -> Initializer {
4750
Initializer::nop()

futures-util/src/io/mod.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,35 @@
99
//! This module is only available when the `io` and `std` features of this
1010
//! library is activated, and it is activated by default.
1111
12+
#[cfg(feature = "io-compat")]
13+
use crate::compat::Compat;
14+
use std::ptr;
15+
1216
pub use futures_io::{
1317
AsyncRead, AsyncWrite, AsyncSeek, AsyncBufRead, Error, ErrorKind,
1418
IoSlice, IoSliceMut, Result, SeekFrom,
1519
};
16-
17-
#[cfg(feature = "io-compat")] use crate::compat::Compat;
20+
#[cfg(feature = "read_initializer")]
21+
pub use futures_io::Initializer;
1822

1923
// used by `BufReader` and `BufWriter`
2024
// https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1
2125
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
2226

27+
/// Initializes a buffer if necessary.
28+
///
29+
/// A buffer is always initialized if `read_initializer` feature is disabled.
30+
#[inline]
31+
unsafe fn initialize<R: AsyncRead>(reader: &R, buf: &mut [u8]) {
32+
#[cfg(feature = "read_initializer")]
33+
{
34+
if !reader.initializer().should_initialize() {
35+
return;
36+
}
37+
}
38+
ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len())
39+
}
40+
2341
mod allow_std;
2442
pub use self::allow_std::AllowStdIo;
2543

futures-util/src/io/read_to_end.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub(super) fn read_to_end_internal<R: AsyncRead + ?Sized>(
5858
g.buf.reserve(32);
5959
let capacity = g.buf.capacity();
6060
g.buf.set_len(capacity);
61-
rd.initializer().initialize(&mut g.buf[g.len..]);
61+
super::initialize(&rd, &mut g.buf[g.len..]);
6262
}
6363
}
6464

futures-util/src/io/repeat.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use futures_core::task::{Context, Poll};
2-
use futures_io::{AsyncRead, Initializer, IoSliceMut};
2+
#[cfg(feature = "read_initializer")]
3+
use futures_io::Initializer;
4+
use futures_io::{AsyncRead, IoSliceMut};
35
use std::fmt;
46
use std::io;
57
use std::pin::Pin;
@@ -57,6 +59,7 @@ impl AsyncRead for Repeat {
5759
Poll::Ready(Ok(nwritten))
5860
}
5961

62+
#[cfg(feature = "read_initializer")]
6063
#[inline]
6164
unsafe fn initializer(&self) -> Initializer {
6265
Initializer::nop()

0 commit comments

Comments
 (0)